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 = "NRC_BUFLEN llegal buffer length"; break;
240 case 0x03: s = "NRC_ILLCMD illegal command"; break;
241 case 0x05: s = "NRC_CMDTMO command timed out"; break;
242 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
243 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
244 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
245 case 0x09: s = "NRC_NORES no resource available"; break;
246 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
247 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
248 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
249 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
250 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
251 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
252 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
253 case 0x13: s = "NRC_ILLNN illegal name number"; break;
254 case 0x14: s = "NRC_NOCALL no callname"; break;
255 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
256 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
257 case 0x17: s = "NRC_NAMERR name deleted"; break;
258 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
259 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
260 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
261 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
263 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
264 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
265 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
266 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
267 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
268 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
269 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
270 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
271 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
272 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
273 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
274 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
275 case 0x40: s = "NRC_SYSTEM 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 #ifdef DEBUG_SMB_REFCOUNT
823 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
825 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
830 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
831 lock_ObtainWrite(&smb_rctLock);
832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
833 if (vcp->magic != SMB_VC_MAGIC)
834 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
837 if (lsn == vcp->lsn && lana == vcp->lana &&
838 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
839 smb_HoldVCNoLock(vcp);
843 if (!vcp && (flags & SMB_FLAG_CREATE)) {
844 vcp = malloc(sizeof(*vcp));
845 memset(vcp, 0, sizeof(*vcp));
846 vcp->vcID = ++numVCs;
847 vcp->magic = SMB_VC_MAGIC;
848 vcp->refCount = 2; /* smb_allVCsp and caller */
851 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
852 vcp->nextp = smb_allVCsp;
854 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
859 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
860 /* We must obtain a challenge for extended auth
861 * in case the client negotiates smb v3
863 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
864 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
865 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
866 ULONG lsaRespSize = 0;
868 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
870 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
877 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
878 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
879 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
880 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
881 nts, ntsEx, lsaRespSize);
883 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
885 if (ntsEx == STATUS_SUCCESS) {
886 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
889 * This will cause the subsequent authentication to fail but
890 * that is better than us dereferencing a NULL pointer and
893 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 LsaFreeReturnBuffer(lsaResp);
899 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
901 if (numVCs >= CM_SESSION_RESERVED) {
903 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
906 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
913 lock_ReleaseWrite(&smb_globalLock);
917 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 static int smb_IsStarMask(clientchar_t *maskp)
937 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
943 #ifdef DEBUG_SMB_REFCOUNT
944 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
945 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
947 void smb_ReleaseVCInternal(smb_vc_t *vcp)
953 lock_AssertWrite(&smb_rctLock);
956 if (vcp->refCount == 0) {
957 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
958 #ifdef DEBUG_SMB_REFCOUNT
959 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
960 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
962 /* remove VCP from smb_deadVCsp */
963 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
969 lock_FinalizeMutex(&vcp->mx);
970 memset(vcp,0,sizeof(smb_vc_t));
973 #ifdef DEBUG_SMB_REFCOUNT
974 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
976 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
980 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
981 avcp?"":"not ",vcp, vcp->refCount);
983 /* This is a wrong. However, I suspect that there is an undercount
984 * and I don't want to release 1.4.1 in a state that will allow
985 * smb_vc_t objects to be deallocated while still in the
986 * smb_allVCsp list. The list is supposed to keep a reference
987 * to the smb_vc_t. Put it back.
991 #ifdef DEBUG_SMB_REFCOUNT
992 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
993 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
997 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
998 /* The reference count is non-zero but the VC is dead.
999 * This implies that some FIDs, TIDs, etc on the VC have yet to
1000 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1001 * add a reference that will be dropped by
1002 * smb_CleanupDeadVC() and try to cleanup the VC again.
1003 * Eventually the refCount will drop to zero when all of the
1004 * active threads working with the VC end their task.
1006 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1007 vcp->refCount++; /* put the refCount back */
1008 lock_ReleaseWrite(&smb_rctLock);
1009 smb_CleanupDeadVC(vcp);
1010 #ifdef DEBUG_SMB_REFCOUNT
1011 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1012 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1014 lock_ObtainWrite(&smb_rctLock);
1017 #ifdef DEBUG_SMB_REFCOUNT
1018 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1019 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1024 #ifdef DEBUG_SMB_REFCOUNT
1025 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1027 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1030 lock_AssertWrite(&smb_rctLock);
1031 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1032 smb_ReleaseVCInternal(vcp);
1035 #ifdef DEBUG_SMB_REFCOUNT
1036 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1038 void smb_ReleaseVC(smb_vc_t *vcp)
1041 lock_ObtainWrite(&smb_rctLock);
1042 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1043 smb_ReleaseVCInternal(vcp);
1044 lock_ReleaseWrite(&smb_rctLock);
1047 #ifdef DEBUG_SMB_REFCOUNT
1048 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1050 void smb_HoldVCNoLock(smb_vc_t *vcp)
1053 lock_AssertWrite(&smb_rctLock);
1055 #ifdef DEBUG_SMB_REFCOUNT
1056 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1057 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1059 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1063 #ifdef DEBUG_SMB_REFCOUNT
1064 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1066 void smb_HoldVC(smb_vc_t *vcp)
1069 lock_ObtainWrite(&smb_rctLock);
1071 #ifdef DEBUG_SMB_REFCOUNT
1072 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1073 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1075 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1077 lock_ReleaseWrite(&smb_rctLock);
1080 void smb_CleanupDeadVC(smb_vc_t *vcp)
1082 smb_fid_t *fidpIter;
1083 smb_fid_t *fidpNext;
1085 smb_tid_t *tidpIter;
1086 smb_tid_t *tidpNext;
1088 smb_user_t *uidpIter;
1089 smb_user_t *uidpNext;
1091 afs_uint32 refCount = 0;
1093 lock_ObtainMutex(&vcp->mx);
1094 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1095 lock_ReleaseMutex(&vcp->mx);
1096 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1099 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1100 lock_ReleaseMutex(&vcp->mx);
1101 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1103 lock_ObtainWrite(&smb_rctLock);
1104 /* remove VCP from smb_allVCsp */
1105 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1106 if ((*vcpp)->magic != SMB_VC_MAGIC)
1107 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1108 __FILE__, __LINE__);
1111 vcp->nextp = smb_deadVCsp;
1113 /* Hold onto the reference until we are done with this function */
1118 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1119 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1121 if (fidpIter->deleteOk)
1124 fid = fidpIter->fid;
1125 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1127 smb_HoldFIDNoLock(fidpIter);
1128 lock_ReleaseWrite(&smb_rctLock);
1130 smb_CloseFID(vcp, fidpIter, NULL, 0);
1131 smb_ReleaseFID(fidpIter);
1133 lock_ObtainWrite(&smb_rctLock);
1134 fidpNext = vcp->fidsp;
1137 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1138 tidpNext = tidpIter->nextp;
1139 if (tidpIter->deleteOk)
1141 tidpIter->deleteOk = 1;
1143 tid = tidpIter->tid;
1144 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1146 smb_HoldTIDNoLock(tidpIter);
1147 smb_ReleaseTID(tidpIter, TRUE);
1148 tidpNext = vcp->tidsp;
1151 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1152 uidpNext = uidpIter->nextp;
1153 if (uidpIter->deleteOk)
1155 uidpIter->deleteOk = 1;
1157 /* do not add an additional reference count for the smb_user_t
1158 * as the smb_vc_t already is holding a reference */
1159 lock_ReleaseWrite(&smb_rctLock);
1161 smb_ReleaseUID(uidpIter);
1163 lock_ObtainWrite(&smb_rctLock);
1164 uidpNext = vcp->usersp;
1167 /* The vcp is now on the deadVCsp list. We intentionally drop the
1168 * reference so that the refcount can reach 0 and we can delete it
1170 * If the refCount == 1 going into the ReleaseVCNoLock call
1171 * the object will be freed and it won't be safe to clear
1174 refCount = vcp->refCount;
1175 smb_ReleaseVCNoLock(vcp);
1177 lock_ObtainMutex(&vcp->mx);
1178 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1179 lock_ReleaseMutex(&vcp->mx);
1182 lock_ReleaseWrite(&smb_rctLock);
1183 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1186 #ifdef DEBUG_SMB_REFCOUNT
1187 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1189 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1194 lock_ObtainWrite(&smb_rctLock);
1196 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1197 if (tidp->refCount == 0 && tidp->deleteOk) {
1199 smb_ReleaseTID(tidp, TRUE);
1203 if (tid == tidp->tid) {
1208 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1209 tidp = malloc(sizeof(*tidp));
1210 memset(tidp, 0, sizeof(*tidp));
1211 tidp->nextp = vcp->tidsp;
1214 smb_HoldVCNoLock(vcp);
1216 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1219 #ifdef DEBUG_SMB_REFCOUNT
1221 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1222 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1225 lock_ReleaseWrite(&smb_rctLock);
1229 #ifdef DEBUG_SMB_REFCOUNT
1230 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1232 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1235 lock_AssertWrite(&smb_rctLock);
1237 #ifdef DEBUG_SMB_REFCOUNT
1238 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1239 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1246 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1251 cm_user_t *userp = NULL;
1252 smb_vc_t *vcp = NULL;
1255 lock_ObtainWrite(&smb_rctLock);
1257 lock_AssertWrite(&smb_rctLock);
1259 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1260 #ifdef DEBUG_SMB_REFCOUNT
1261 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1262 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1264 if (tidp->refCount == 0) {
1265 if (tidp->deleteOk) {
1266 ltpp = &tidp->vcp->tidsp;
1267 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1271 osi_assertx(tp != NULL, "null smb_tid_t");
1273 lock_FinalizeMutex(&tidp->mx);
1274 userp = tidp->userp; /* remember to drop ref later */
1282 lock_ReleaseWrite(&smb_rctLock);
1284 cm_ReleaseUser(userp);
1286 smb_ReleaseVCNoLock(vcp);
1289 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1291 smb_user_t *uidp = NULL;
1293 lock_ObtainWrite(&smb_rctLock);
1294 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1295 if (uid == uidp->userID) {
1297 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1299 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1303 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1304 uidp = malloc(sizeof(*uidp));
1305 memset(uidp, 0, sizeof(*uidp));
1306 uidp->nextp = vcp->usersp;
1307 uidp->refCount = 2; /* one for the vcp and one for the caller */
1309 smb_HoldVCNoLock(vcp);
1311 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1313 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1315 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1317 lock_ReleaseWrite(&smb_rctLock);
1321 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1324 smb_username_t *unp= NULL;
1326 lock_ObtainWrite(&smb_rctLock);
1327 for(unp = usernamesp; unp; unp = unp->nextp) {
1328 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1329 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1334 if (!unp && (flags & SMB_FLAG_CREATE)) {
1335 unp = malloc(sizeof(*unp));
1336 memset(unp, 0, sizeof(*unp));
1338 unp->nextp = usernamesp;
1339 unp->name = cm_ClientStrDup(usern);
1340 unp->machine = cm_ClientStrDup(machine);
1342 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1343 if (flags & SMB_FLAG_AFSLOGON)
1344 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1347 lock_ReleaseWrite(&smb_rctLock);
1351 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1353 smb_user_t *uidp= NULL;
1355 lock_ObtainWrite(&smb_rctLock);
1356 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1359 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1361 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1362 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1367 lock_ReleaseWrite(&smb_rctLock);
1371 void smb_ReleaseUsername(smb_username_t *unp)
1374 smb_username_t **lupp;
1375 cm_user_t *userp = NULL;
1376 time_t now = osi_Time();
1378 lock_ObtainWrite(&smb_rctLock);
1379 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1380 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1381 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1383 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1387 osi_assertx(up != NULL, "null smb_username_t");
1389 up->nextp = NULL; /* do not remove this */
1390 lock_FinalizeMutex(&unp->mx);
1396 lock_ReleaseWrite(&smb_rctLock);
1398 cm_ReleaseUser(userp);
1401 void smb_HoldUIDNoLock(smb_user_t *uidp)
1403 lock_AssertWrite(&smb_rctLock);
1407 void smb_ReleaseUID(smb_user_t *uidp)
1411 smb_username_t *unp = NULL;
1413 lock_ObtainWrite(&smb_rctLock);
1414 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1415 if (uidp->refCount == 0) {
1416 lupp = &uidp->vcp->usersp;
1417 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1421 osi_assertx(up != NULL, "null smb_user_t");
1423 lock_FinalizeMutex(&uidp->mx);
1425 smb_ReleaseVCNoLock(uidp->vcp);
1429 lock_ReleaseWrite(&smb_rctLock);
1433 cm_ReleaseUserVCRef(unp->userp);
1434 smb_ReleaseUsername(unp);
1438 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1440 cm_user_t *up = NULL;
1445 lock_ObtainMutex(&uidp->mx);
1447 up = uidp->unp->userp;
1450 lock_ReleaseMutex(&uidp->mx);
1456 /* retrieve a held reference to a user structure corresponding to an incoming
1458 * corresponding release function is cm_ReleaseUser.
1460 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1463 cm_user_t *up = NULL;
1466 smbp = (smb_t *) inp;
1467 uidp = smb_FindUID(vcp, smbp->uid, 0);
1471 up = smb_GetUserFromUID(uidp);
1473 smb_ReleaseUID(uidp);
1478 * Return a pointer to a pathname extracted from a TID structure. The
1479 * TID structure is not held; assume it won't go away.
1481 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1486 tidp = smb_FindTID(vcp, tid, 0);
1490 if (tidp->flags & SMB_TIDFLAG_IPC) {
1491 code = CM_ERROR_TIDIPC;
1492 /* tidp->pathname would be NULL, but that's fine */
1494 *treepath = tidp->pathname;
1495 smb_ReleaseTID(tidp, FALSE);
1500 /* check to see if we have a chained fid, that is, a fid that comes from an
1501 * OpenAndX message that ran earlier in this packet. In this case, the fid
1502 * field in a read, for example, request, isn't set, since the value is
1503 * supposed to be inherited from the openAndX call.
1505 int smb_ChainFID(int fid, smb_packet_t *inp)
1507 if (inp->fid == 0 || inp->inCount == 0)
1513 /* are we a priv'd user? What does this mean on NT? */
1514 int smb_SUser(cm_user_t *userp)
1519 /* find a file ID. If we pass in 0 we select an unused File ID.
1520 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1521 * smb_fid_t data structure if desired File ID cannot be found.
1523 #ifdef DEBUG_SMB_REFCOUNT
1524 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1526 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1532 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1535 lock_ObtainWrite(&smb_rctLock);
1536 /* figure out if we need to allocate a new file ID */
1539 fid = vcp->fidCounter;
1543 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1544 if (fidp->refCount == 0 && fidp->deleteOk) {
1546 lock_ReleaseWrite(&smb_rctLock);
1547 smb_ReleaseFID(fidp);
1548 lock_ObtainWrite(&smb_rctLock);
1551 if (fid == fidp->fid) {
1554 if (fid == 0xFFFF) {
1556 "New FID number wraps on vcp 0x%x", vcp);
1566 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1567 char eventName[MAX_PATH];
1569 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1570 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1571 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1572 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1573 thrd_CloseHandle(event);
1575 if (fid == 0xFFFF) {
1576 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1582 fidp = malloc(sizeof(*fidp));
1583 memset(fidp, 0, sizeof(*fidp));
1584 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1587 smb_HoldVCNoLock(vcp);
1588 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1590 fidp->curr_chunk = fidp->prev_chunk = -2;
1591 fidp->raw_write_event = event;
1593 vcp->fidCounter = fid+1;
1594 if (vcp->fidCounter == 0xFFFF) {
1595 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1597 vcp->fidCounter = 1;
1602 #ifdef DEBUG_SMB_REFCOUNT
1604 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1605 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1608 lock_ReleaseWrite(&smb_rctLock);
1612 #ifdef DEBUG_SMB_REFCOUNT
1613 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1615 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1618 smb_fid_t *fidp = NULL;
1624 lock_ObtainWrite(&smb_rctLock);
1625 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1626 if (scp == fidp->scp) {
1631 #ifdef DEBUG_SMB_REFCOUNT
1633 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1634 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1637 lock_ReleaseWrite(&smb_rctLock);
1641 #ifdef DEBUG_SMB_REFCOUNT
1642 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1644 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1647 lock_AssertWrite(&smb_rctLock);
1649 #ifdef DEBUG_SMB_REFCOUNT
1650 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1651 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1656 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1657 /* the sm_fid_t->mx and smb_rctLock must not be held */
1658 #ifdef DEBUG_SMB_REFCOUNT
1659 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1661 void smb_ReleaseFID(smb_fid_t *fidp)
1664 cm_scache_t *scp = NULL;
1665 cm_user_t *userp = NULL;
1666 smb_vc_t *vcp = NULL;
1667 smb_ioctl_t *ioctlp;
1669 lock_ObtainMutex(&fidp->mx);
1670 lock_ObtainWrite(&smb_rctLock);
1671 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1672 #ifdef DEBUG_SMB_REFCOUNT
1673 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1674 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1676 if (fidp->refCount == 0) {
1677 if (fidp->deleteOk) {
1680 scp = fidp->scp; /* release after lock is released */
1682 lock_ObtainWrite(&scp->rw);
1683 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1684 lock_ReleaseWrite(&scp->rw);
1685 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1688 userp = fidp->userp;
1692 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1693 thrd_CloseHandle(fidp->raw_write_event);
1695 /* and see if there is ioctl stuff to free */
1696 ioctlp = fidp->ioctlp;
1699 cm_FreeSpace(ioctlp->prefix);
1700 if (ioctlp->ioctl.inAllocp)
1701 free(ioctlp->ioctl.inAllocp);
1702 if (ioctlp->ioctl.outAllocp)
1703 free(ioctlp->ioctl.outAllocp);
1706 lock_ReleaseMutex(&fidp->mx);
1707 lock_FinalizeMutex(&fidp->mx);
1712 smb_ReleaseVCNoLock(vcp);
1716 lock_ReleaseMutex(&fidp->mx);
1718 lock_ReleaseWrite(&smb_rctLock);
1720 /* now release the scache structure */
1722 cm_ReleaseSCache(scp);
1725 cm_ReleaseUser(userp);
1729 * Case-insensitive search for one string in another;
1730 * used to find variable names in submount pathnames.
1732 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1734 clientchar_t *cursor;
1736 for (cursor = str1; *cursor; cursor++)
1737 if (cm_ClientStrCmpI(cursor, str2) == 0)
1744 * Substitute a variable value for its name in a submount pathname. Variable
1745 * name has been identified by smb_stristr() and is in substr. Variable name
1746 * length (plus one) is in substr_size. Variable value is in newstr.
1748 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1749 unsigned int substr_size, clientchar_t *newstr)
1751 clientchar_t temp[1024];
1753 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1754 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1755 cm_ClientStrCat(str1, cchstr1, temp);
1758 clientchar_t VNUserName[] = _C("%USERNAME%");
1759 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1760 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1761 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1763 typedef struct smb_findShare_rock {
1764 clientchar_t * shareName;
1765 clientchar_t * match;
1767 } smb_findShare_rock_t;
1769 #define SMB_FINDSHARE_EXACT_MATCH 1
1770 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1772 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1776 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1777 normchar_t normName[MAX_PATH];
1779 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1780 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1781 osi_LogSaveString(smb_logp, dep->name));
1785 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1786 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1787 matchType = SMB_FINDSHARE_EXACT_MATCH;
1789 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1792 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1793 vrock->matchType = matchType;
1795 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1796 return CM_ERROR_STOPNOW;
1802 /* find a shareName in the table of submounts */
1803 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1804 clientchar_t *shareName,
1805 clientchar_t **pathNamep)
1809 clientchar_t pathName[1024];
1812 clientchar_t *p, *q;
1813 fschar_t *cellname = NULL;
1816 DWORD allSubmount = 1;
1818 /* if allSubmounts == 0, only return the //mountRoot/all share
1819 * if in fact it has been been created in the subMounts table.
1820 * This is to allow sites that want to restrict access to the
1823 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1824 0, KEY_QUERY_VALUE, &parmKey);
1825 if (code == ERROR_SUCCESS) {
1826 cblen = sizeof(allSubmount);
1827 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1828 (BYTE *) &allSubmount, &cblen);
1829 if (code != ERROR_SUCCESS) {
1832 RegCloseKey (parmKey);
1835 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1840 /* In case, the all share is disabled we need to still be able
1841 * to handle ioctl requests
1843 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1844 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1848 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1849 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1850 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1851 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1852 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1858 /* Check for volume references
1860 * They look like <cell>{%,#}<volume>
1862 if (cm_ClientStrChr(shareName, '%') != NULL ||
1863 cm_ClientStrChr(shareName, '#') != NULL) {
1864 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1865 /* make room for '/@vol:' + mountchar + NULL terminator*/
1867 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1868 osi_LogSaveClientString(smb_logp, shareName));
1870 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1871 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1872 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1874 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1876 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1877 cm_ClientStrLwr(*pathNamep);
1878 osi_Log1(smb_logp, " returning pathname [%S]",
1879 osi_LogSaveClientString(smb_logp, *pathNamep));
1887 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1888 0, KEY_QUERY_VALUE, &parmKey);
1889 if (code == ERROR_SUCCESS) {
1890 cblen = sizeof(pathName);
1891 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1892 (BYTE *) pathName, &cblen);
1893 if (code != ERROR_SUCCESS)
1895 RegCloseKey (parmKey);
1899 cchlen = cblen / sizeof(clientchar_t);
1900 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1901 /* We can accept either unix or PC style AFS pathnames. Convert
1902 * Unix-style to PC style here for internal use.
1905 cchlen = lengthof(pathName);
1907 /* within this code block, we maintain, cchlen = writeable
1908 buffer length of p */
1910 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1911 p += cm_mountRootCLen; /* skip mount path */
1912 cchlen -= (DWORD)(p - pathName);
1917 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1923 clientchar_t temp[1024];
1925 if (var = smb_stristr(p, VNUserName)) {
1926 if (uidp && uidp->unp)
1927 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1929 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1931 else if (var = smb_stristr(p, VNLCUserName))
1933 if (uidp && uidp->unp)
1934 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1936 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1937 cm_ClientStrLwr(temp);
1938 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1940 else if (var = smb_stristr(p, VNComputerName))
1942 sizeTemp = lengthof(temp);
1943 GetComputerNameW(temp, &sizeTemp);
1944 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1946 else if (var = smb_stristr(p, VNLCComputerName))
1948 sizeTemp = lengthof(temp);
1949 GetComputerName((LPTSTR)temp, &sizeTemp);
1950 cm_ClientStrLwr(temp);
1951 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1956 *pathNamep = cm_ClientStrDup(p);
1961 /* First lookup shareName in root.afs */
1963 smb_findShare_rock_t vrock;
1965 fschar_t ftemp[1024];
1966 clientchar_t * p = shareName;
1969 /* attempt to locate a partial match in root.afs. This is because
1970 when using the ANSI RAP calls, the share name is limited to 13 chars
1971 and hence is truncated. Of course we prefer exact matches. */
1973 thyper.HighPart = 0;
1976 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1977 if (vrock.shareName == NULL)
1980 vrock.matchType = 0;
1982 cm_HoldSCache(cm_data.rootSCachep);
1983 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1984 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1985 cm_ReleaseSCache(cm_data.rootSCachep);
1987 free(vrock.shareName);
1988 vrock.shareName = NULL;
1990 if (vrock.matchType) {
1991 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1992 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1997 /* if we get here, there was no match for the share in root.afs */
1998 /* so try to create \\<netbiosName>\<cellname> */
2003 /* Get the full name for this cell */
2004 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2005 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2006 #ifdef AFS_AFSDB_ENV
2007 if (code && cm_dnsEnabled) {
2009 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2015 /* construct the path */
2017 clientchar_t temp[1024];
2019 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2020 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2021 rw ? _C("/.%S/") : _C("/%S/"), temp);
2022 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2032 /* Client-side offline caching policy types */
2033 #define CSC_POLICY_MANUAL 0
2034 #define CSC_POLICY_DOCUMENTS 1
2035 #define CSC_POLICY_PROGRAMS 2
2036 #define CSC_POLICY_DISABLE 3
2038 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2041 clientchar_t policy[1024];
2044 int retval = CSC_POLICY_MANUAL;
2046 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2047 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2050 REG_OPTION_NON_VOLATILE,
2056 len = sizeof(policy);
2057 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2059 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2061 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2063 retval = CSC_POLICY_DOCUMENTS;
2065 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2067 retval = CSC_POLICY_PROGRAMS;
2069 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2071 retval = CSC_POLICY_DISABLE;
2074 RegCloseKey(hkCSCPolicy);
2078 /* find a dir search structure by cookie value, and return it held.
2079 * Must be called with smb_globalLock held.
2081 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2083 smb_dirSearch_t *dsp;
2085 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2086 if (dsp->cookie == cookie) {
2087 if (dsp != smb_firstDirSearchp) {
2088 /* move to head of LRU queue, too, if we're not already there */
2089 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2090 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2091 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2092 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2093 if (!smb_lastDirSearchp)
2094 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2102 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2103 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2104 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2110 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2112 lock_ObtainMutex(&dsp->mx);
2113 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2114 dsp->cookie, dsp, dsp->scp);
2115 dsp->flags |= SMB_DIRSEARCH_DELETE;
2116 if (dsp->scp != NULL) {
2117 lock_ObtainWrite(&dsp->scp->rw);
2118 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2119 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2120 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2121 dsp->scp->bulkStatProgress = hzero;
2123 lock_ReleaseWrite(&dsp->scp->rw);
2125 lock_ReleaseMutex(&dsp->mx);
2128 /* Must be called with the smb_globalLock held */
2129 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2131 cm_scache_t *scp = NULL;
2133 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2134 if (dsp->refCount == 0) {
2135 lock_ObtainMutex(&dsp->mx);
2136 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2137 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2138 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2139 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2140 lock_ReleaseMutex(&dsp->mx);
2141 lock_FinalizeMutex(&dsp->mx);
2143 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2144 dsp->cookie, dsp, scp);
2147 lock_ReleaseMutex(&dsp->mx);
2150 /* do this now to avoid spurious locking hierarchy creation */
2152 cm_ReleaseSCache(scp);
2155 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2157 lock_ObtainWrite(&smb_globalLock);
2158 smb_ReleaseDirSearchNoLock(dsp);
2159 lock_ReleaseWrite(&smb_globalLock);
2162 /* find a dir search structure by cookie value, and return it held */
2163 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2165 smb_dirSearch_t *dsp;
2167 lock_ObtainWrite(&smb_globalLock);
2168 dsp = smb_FindDirSearchNoLock(cookie);
2169 lock_ReleaseWrite(&smb_globalLock);
2173 /* GC some dir search entries, in the address space expected by the specific protocol.
2174 * Must be called with smb_globalLock held; release the lock temporarily.
2176 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2177 void smb_GCDirSearches(int isV3)
2179 smb_dirSearch_t *prevp;
2180 smb_dirSearch_t *dsp;
2181 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2185 victimCount = 0; /* how many have we got so far */
2186 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2187 /* we'll move tp from queue, so
2190 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2191 /* if no one is using this guy, and we're either in the new protocol,
2192 * or we're in the old one and this is a small enough ID to be useful
2193 * to the old protocol, GC this guy.
2195 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2196 /* hold and delete */
2197 lock_ObtainMutex(&dsp->mx);
2198 dsp->flags |= SMB_DIRSEARCH_DELETE;
2199 lock_ReleaseMutex(&dsp->mx);
2200 victimsp[victimCount++] = dsp;
2204 /* don't do more than this */
2205 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2209 /* now release them */
2210 for (i = 0; i < victimCount; i++) {
2211 smb_ReleaseDirSearchNoLock(victimsp[i]);
2215 /* function for allocating a dir search entry. We need these to remember enough context
2216 * since we don't get passed the path from call to call during a directory search.
2218 * Returns a held dir search structure, and bumps the reference count on the vnode,
2219 * since it saves a pointer to the vnode.
2221 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2223 smb_dirSearch_t *dsp;
2229 lock_ObtainWrite(&smb_globalLock);
2232 /* what's the biggest ID allowed in this version of the protocol */
2233 /* TODO: do we really want a non v3 dir search request to wrap
2234 smb_dirSearchCounter? */
2235 maxAllowed = isV3 ? 65535 : 255;
2236 if (smb_dirSearchCounter > maxAllowed)
2237 smb_dirSearchCounter = 1;
2239 start = smb_dirSearchCounter;
2242 /* twice so we have enough tries to find guys we GC after one pass;
2243 * 10 extra is just in case I mis-counted.
2245 if (++counter > 2*maxAllowed+10)
2246 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2248 if (smb_dirSearchCounter > maxAllowed) {
2249 smb_dirSearchCounter = 1;
2251 if (smb_dirSearchCounter == start) {
2253 smb_GCDirSearches(isV3);
2256 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2258 /* don't need to watch for refcount zero and deleted, since
2259 * we haven't dropped the global lock.
2262 ++smb_dirSearchCounter;
2266 dsp = malloc(sizeof(*dsp));
2267 memset(dsp, 0, sizeof(*dsp));
2268 dsp->cookie = smb_dirSearchCounter;
2269 ++smb_dirSearchCounter;
2271 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2272 dsp->lastTime = osi_Time();
2273 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2274 if (!smb_lastDirSearchp)
2275 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2277 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2281 lock_ReleaseWrite(&smb_globalLock);
2285 static smb_packet_t *smb_GetPacket(void)
2289 lock_ObtainWrite(&smb_globalLock);
2290 tbp = smb_packetFreeListp;
2292 smb_packetFreeListp = tbp->nextp;
2293 lock_ReleaseWrite(&smb_globalLock);
2295 tbp = calloc(sizeof(*tbp),1);
2296 tbp->magic = SMB_PACKETMAGIC;
2299 tbp->resumeCode = 0;
2305 tbp->ncb_length = 0;
2308 tbp->stringsp = NULL;
2310 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2315 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2318 tbp = smb_GetPacket();
2319 memcpy(tbp, pkt, sizeof(smb_packet_t));
2320 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2321 tbp->stringsp = NULL;
2323 smb_HoldVC(tbp->vcp);
2327 static NCB *smb_GetNCB(void)
2332 lock_ObtainWrite(&smb_globalLock);
2333 tbp = smb_ncbFreeListp;
2335 smb_ncbFreeListp = tbp->nextp;
2336 lock_ReleaseWrite(&smb_globalLock);
2338 tbp = calloc(sizeof(*tbp),1);
2339 tbp->magic = SMB_NCBMAGIC;
2342 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2344 memset(&tbp->ncb, 0, sizeof(NCB));
2349 static void FreeSMBStrings(smb_packet_t * pkt)
2354 for (s = pkt->stringsp; s; s = ns) {
2358 pkt->stringsp = NULL;
2361 void smb_FreePacket(smb_packet_t *tbp)
2363 smb_vc_t * vcp = NULL;
2364 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2366 lock_ObtainWrite(&smb_globalLock);
2367 tbp->nextp = smb_packetFreeListp;
2368 smb_packetFreeListp = tbp;
2369 tbp->magic = SMB_PACKETMAGIC;
2373 tbp->resumeCode = 0;
2379 tbp->ncb_length = 0;
2381 FreeSMBStrings(tbp);
2382 lock_ReleaseWrite(&smb_globalLock);
2388 static void smb_FreeNCB(NCB *bufferp)
2392 tbp = (smb_ncb_t *) bufferp;
2393 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2395 lock_ObtainWrite(&smb_globalLock);
2396 tbp->nextp = smb_ncbFreeListp;
2397 smb_ncbFreeListp = tbp;
2398 lock_ReleaseWrite(&smb_globalLock);
2401 /* get a ptr to the data part of a packet, and its count */
2402 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2406 unsigned char *afterParmsp;
2408 parmBytes = *smbp->wctp << 1;
2409 afterParmsp = smbp->wctp + parmBytes + 1;
2411 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2412 if (nbytesp) *nbytesp = dataBytes;
2414 /* don't forget to skip the data byte count, since it follows
2415 * the parameters; that's where the "2" comes from below.
2417 return (unsigned char *) (afterParmsp + 2);
2420 /* must set all the returned parameters before playing around with the
2421 * data region, since the data region is located past the end of the
2422 * variable number of parameters.
2424 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2426 unsigned char *afterParmsp;
2428 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2430 *afterParmsp++ = dsize & 0xff;
2431 *afterParmsp = (dsize>>8) & 0xff;
2434 /* return the parm'th parameter in the smbp packet */
2435 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2438 unsigned char *parmDatap;
2440 parmCount = *smbp->wctp;
2442 if (parm >= parmCount) {
2445 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2446 parm, parmCount, smbp->ncb_length);
2447 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2448 parm, parmCount, smbp->ncb_length);
2449 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2450 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2451 osi_panic(s, __FILE__, __LINE__);
2453 parmDatap = smbp->wctp + (2*parm) + 1;
2455 return parmDatap[0] + (parmDatap[1] << 8);
2458 /* return the parm'th parameter in the smbp packet */
2459 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2462 unsigned char *parmDatap;
2464 parmCount = *smbp->wctp;
2466 if (parm >= parmCount) {
2469 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2470 parm, parmCount, smbp->ncb_length);
2471 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2472 parm, parmCount, smbp->ncb_length);
2473 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2474 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2475 osi_panic(s, __FILE__, __LINE__);
2477 parmDatap = smbp->wctp + (2*parm) + 1;
2479 return parmDatap[0];
2482 /* return the parm'th parameter in the smbp packet */
2483 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2486 unsigned char *parmDatap;
2488 parmCount = *smbp->wctp;
2490 if (parm + 1 >= parmCount) {
2493 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2494 parm, parmCount, smbp->ncb_length);
2495 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2496 parm, parmCount, smbp->ncb_length);
2497 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2498 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2499 osi_panic(s, __FILE__, __LINE__);
2501 parmDatap = smbp->wctp + (2*parm) + 1;
2503 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2506 /* return the parm'th parameter in the smbp packet */
2507 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2510 unsigned char *parmDatap;
2512 parmCount = *smbp->wctp;
2514 if (parm * 2 + offset >= parmCount * 2) {
2517 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2518 parm, offset, parmCount, smbp->ncb_length);
2519 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2520 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2521 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2522 parm, offset, parmCount, smbp->ncb_length);
2523 osi_panic(s, __FILE__, __LINE__);
2525 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2527 return parmDatap[0] + (parmDatap[1] << 8);
2530 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2532 unsigned char *parmDatap;
2534 /* make sure we have enough slots */
2535 if (*smbp->wctp <= slot)
2536 *smbp->wctp = slot+1;
2538 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2539 *parmDatap++ = parmValue & 0xff;
2540 *parmDatap = (parmValue>>8) & 0xff;
2543 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2545 unsigned char *parmDatap;
2547 /* make sure we have enough slots */
2548 if (*smbp->wctp <= slot)
2549 *smbp->wctp = slot+2;
2551 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2552 *parmDatap++ = parmValue & 0xff;
2553 *parmDatap++ = (parmValue>>8) & 0xff;
2554 *parmDatap++ = (parmValue>>16) & 0xff;
2555 *parmDatap = (parmValue>>24) & 0xff;
2558 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2560 unsigned char *parmDatap;
2563 /* make sure we have enough slots */
2564 if (*smbp->wctp <= slot)
2565 *smbp->wctp = slot+4;
2567 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2569 *parmDatap++ = *parmValuep++;
2572 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2574 unsigned char *parmDatap;
2576 /* make sure we have enough slots */
2577 if (*smbp->wctp <= slot) {
2578 if (smbp->oddByte) {
2580 *smbp->wctp = slot+1;
2585 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2586 *parmDatap++ = parmValue & 0xff;
2591 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2592 clientchar_t *inPathp)
2594 clientchar_t *lastSlashp;
2596 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2598 *lastComponentp = lastSlashp;
2601 if (inPathp == lastSlashp)
2603 *outPathp++ = *inPathp++;
2612 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2613 char **chainpp, int flags)
2621 if (!WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2625 cb = sizeof(pktp->data) - (inp - pktp->data);
2626 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2627 #ifdef DEBUG_UNICODE
2630 cb = sizeof(pktp->data);
2632 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2635 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2636 char ** chainpp, int flags)
2641 if (!WANTS_UNICODE(pktp))
2642 flags |= SMB_STRF_FORCEASCII;
2645 cb = sizeof(pktp->data) - (inp - pktp->data);
2646 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2647 #ifdef DEBUG_UNICODE
2650 cb = sizeof(pktp->data);
2652 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2653 flags | SMB_STRF_SRCNULTERM);
2656 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2657 size_t cb, char ** chainpp, int flags)
2660 if (!WANTS_UNICODE(pktp))
2661 flags |= SMB_STRF_FORCEASCII;
2664 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2667 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2668 size_t cch, char ** chainpp, int flags)
2673 if (!WANTS_UNICODE(pktp))
2674 flags |= SMB_STRF_FORCEASCII;
2676 cb = cch * sizeof(wchar_t);
2679 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2683 smb_ParseStringBuf(const unsigned char * bufbase,
2684 cm_space_t ** stringspp,
2685 unsigned char *inp, size_t *pcb_max,
2686 char **chainpp, int flags)
2689 if (!(flags & SMB_STRF_FORCEASCII)) {
2691 cm_space_t * spacep;
2694 if (bufbase && ((inp - bufbase) % 2) != 0) {
2695 inp++; /* unicode strings are always word aligned */
2699 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2701 cch_src = *pcb_max / sizeof(wchar_t);
2705 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2712 spacep = cm_GetSpace();
2713 spacep->nextp = *stringspp;
2714 *stringspp = spacep;
2718 *chainpp = inp + sizeof(wchar_t);
2721 *(spacep->wdata) = 0;
2722 return spacep->wdata;
2725 StringCchCopyNW(spacep->wdata,
2726 lengthof(spacep->wdata),
2727 (const clientchar_t *) inp, cch_src);
2730 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2732 return spacep->wdata;
2736 cm_space_t * spacep;
2739 /* Not using Unicode */
2741 *chainpp = inp + strlen(inp) + 1;
2744 spacep = cm_GetSpace();
2745 spacep->nextp = *stringspp;
2746 *stringspp = spacep;
2748 cchdest = lengthof(spacep->wdata);
2749 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2750 spacep->wdata, cchdest);
2752 return spacep->wdata;
2758 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2760 size_t * plen, int flags)
2766 /* we are only calculating the required size */
2773 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2775 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2776 if (!(flags & SMB_STRF_IGNORENUL))
2777 *plen += sizeof(wchar_t);
2779 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2789 cch_str = cm_ClientStrLen(str);
2790 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2793 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2801 /* if outp != NULL ... */
2803 /* Number of bytes left in the buffer.
2805 If outp lies inside the packet data buffer, we assume that the
2806 buffer is the packet data buffer. Otherwise we assume that the
2807 buffer is sizeof(packet->data).
2810 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2811 align = (int)((outp - pktp->data) % 2);
2812 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2814 align = (int)(((size_t) outp) % 2);
2815 buffersize = (int)sizeof(pktp->data);
2820 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2826 if (*str == _C('\0')) {
2828 if (buffersize < sizeof(wchar_t))
2831 *((wchar_t *) outp) = L'\0';
2832 if (plen && !(flags & SMB_STRF_IGNORENUL))
2833 *plen += sizeof(wchar_t);
2834 return outp + sizeof(wchar_t);
2837 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2839 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2840 osi_LogSaveClientString(smb_logp, str),
2846 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2848 return outp + sizeof(wchar_t) * nchars;
2856 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2859 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2861 return outp + cch_dest;
2865 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2871 tlen = inp[0] + (inp[1]<<8);
2872 inp += 2; /* skip length field */
2875 *chainpp = inp + tlen;
2884 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2888 if (*inp++ != 0x1) return NULL;
2889 tlen = inp[0] + (inp[1]<<8);
2890 inp += 2; /* skip length field */
2893 *chainpp = inp + tlen;
2896 if (lengthp) *lengthp = tlen;
2901 /* format a packet as a response */
2902 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2907 outp = (smb_t *) op;
2909 /* zero the basic structure through the smb_wct field, and zero the data
2910 * size field, assuming that wct stays zero; otherwise, you have to
2911 * explicitly set the data size field, too.
2913 inSmbp = (smb_t *) inp;
2914 memset(outp, 0, sizeof(smb_t)+2);
2920 outp->com = inSmbp->com;
2921 outp->tid = inSmbp->tid;
2922 outp->pid = inSmbp->pid;
2923 outp->uid = inSmbp->uid;
2924 outp->mid = inSmbp->mid;
2925 outp->res[0] = inSmbp->res[0];
2926 outp->res[1] = inSmbp->res[1];
2927 op->inCom = inSmbp->com;
2929 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2930 #ifdef SEND_CANONICAL_PATHNAMES
2931 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2933 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2935 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2936 outp->flg2 |= SMB_FLAGS2_UNICODE;
2939 /* copy fields in generic packet area */
2940 op->wctp = &outp->wct;
2943 /* send a (probably response) packet; vcp tells us to whom to send it.
2944 * we compute the length by looking at wct and bcc fields.
2946 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2956 ncbp = smb_GetNCB();
2960 memset((char *)ncbp, 0, sizeof(NCB));
2962 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2963 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2964 extra += tp[0] + (tp[1]<<8);
2965 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2966 extra += 3; /* wct and length fields */
2968 ncbp->ncb_length = extra; /* bytes to send */
2969 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2970 ncbp->ncb_lana_num = vcp->lana;
2971 ncbp->ncb_command = NCBSEND; /* op means send data */
2972 ncbp->ncb_buffer = (char *) inp;/* packet */
2973 code = Netbios(ncbp);
2976 const char * s = ncb_error_string(code);
2977 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2978 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2980 lock_ObtainMutex(&vcp->mx);
2981 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2982 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2984 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2985 lock_ReleaseMutex(&vcp->mx);
2986 lock_ObtainWrite(&smb_globalLock);
2987 dead_sessions[vcp->session] = TRUE;
2988 lock_ReleaseWrite(&smb_globalLock);
2989 smb_CleanupDeadVC(vcp);
2991 lock_ReleaseMutex(&vcp->mx);
2999 void smb_MapNTError(long code, unsigned long *NTStatusp)
3001 unsigned long NTStatus;
3003 /* map CM_ERROR_* errors to NT 32-bit status codes */
3004 /* NT Status codes are listed in ntstatus.h not winerror.h */
3008 else if (code == CM_ERROR_NOSUCHCELL) {
3009 NTStatus = 0xC000000FL; /* No such file */
3011 else if (code == CM_ERROR_NOSUCHVOLUME) {
3012 NTStatus = 0xC000000FL; /* No such file */
3014 else if (code == CM_ERROR_TIMEDOUT) {
3016 NTStatus = 0xC00000CFL; /* Sharing Paused */
3018 NTStatus = 0x00000102L; /* Timeout */
3021 else if (code == CM_ERROR_RETRY) {
3022 NTStatus = 0xC000022DL; /* Retry */
3024 else if (code == CM_ERROR_NOACCESS) {
3025 NTStatus = 0xC0000022L; /* Access denied */
3027 else if (code == CM_ERROR_READONLY) {
3028 NTStatus = 0xC00000A2L; /* Write protected */
3030 else if (code == CM_ERROR_NOSUCHFILE ||
3031 code == CM_ERROR_BPLUS_NOMATCH) {
3032 NTStatus = 0xC000000FL; /* No such file */
3034 else if (code == CM_ERROR_NOSUCHPATH) {
3035 NTStatus = 0xC000003AL; /* Object path not found */
3037 else if (code == CM_ERROR_TOOBIG) {
3038 NTStatus = 0xC000007BL; /* Invalid image format */
3040 else if (code == CM_ERROR_INVAL) {
3041 NTStatus = 0xC000000DL; /* Invalid parameter */
3043 else if (code == CM_ERROR_BADFD) {
3044 NTStatus = 0xC0000008L; /* Invalid handle */
3046 else if (code == CM_ERROR_BADFDOP) {
3047 NTStatus = 0xC0000022L; /* Access denied */
3049 else if (code == CM_ERROR_EXISTS) {
3050 NTStatus = 0xC0000035L; /* Object name collision */
3052 else if (code == CM_ERROR_NOTEMPTY) {
3053 NTStatus = 0xC0000101L; /* Directory not empty */
3055 else if (code == CM_ERROR_CROSSDEVLINK) {
3056 NTStatus = 0xC00000D4L; /* Not same device */
3058 else if (code == CM_ERROR_NOTDIR) {
3059 NTStatus = 0xC0000103L; /* Not a directory */
3061 else if (code == CM_ERROR_ISDIR) {
3062 NTStatus = 0xC00000BAL; /* File is a directory */
3064 else if (code == CM_ERROR_BADOP) {
3066 /* I have no idea where this comes from */
3067 NTStatus = 0xC09820FFL; /* SMB no support */
3069 NTStatus = 0xC00000BBL; /* Not supported */
3070 #endif /* COMMENT */
3072 else if (code == CM_ERROR_BADSHARENAME) {
3073 NTStatus = 0xC00000CCL; /* Bad network name */
3075 else if (code == CM_ERROR_NOIPC) {
3077 NTStatus = 0xC0000022L; /* Access Denied */
3079 NTStatus = 0xC000013DL; /* Remote Resources */
3082 else if (code == CM_ERROR_CLOCKSKEW) {
3083 NTStatus = 0xC0000133L; /* Time difference at DC */
3085 else if (code == CM_ERROR_BADTID) {
3086 NTStatus = 0xC0982005L; /* SMB bad TID */
3088 else if (code == CM_ERROR_USESTD) {
3089 NTStatus = 0xC09820FBL; /* SMB use standard */
3091 else if (code == CM_ERROR_QUOTA) {
3092 NTStatus = 0xC0000044L; /* Quota exceeded */
3094 else if (code == CM_ERROR_SPACE) {
3095 NTStatus = 0xC000007FL; /* Disk full */
3097 else if (code == CM_ERROR_ATSYS) {
3098 NTStatus = 0xC0000033L; /* Object name invalid */
3100 else if (code == CM_ERROR_BADNTFILENAME) {
3101 NTStatus = 0xC0000033L; /* Object name invalid */
3103 else if (code == CM_ERROR_WOULDBLOCK) {
3104 NTStatus = 0xC00000D8L; /* Can't wait */
3106 else if (code == CM_ERROR_SHARING_VIOLATION) {
3107 NTStatus = 0xC0000043L; /* Sharing violation */
3109 else if (code == CM_ERROR_LOCK_CONFLICT) {
3110 NTStatus = 0xC0000054L; /* Lock conflict */
3112 else if (code == CM_ERROR_PARTIALWRITE) {
3113 NTStatus = 0xC000007FL; /* Disk full */
3115 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3116 NTStatus = 0xC0000023L; /* Buffer too small */
3118 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3119 NTStatus = 0xC0000035L; /* Object name collision */
3121 else if (code == CM_ERROR_BADPASSWORD) {
3122 NTStatus = 0xC000006DL; /* unknown username or bad password */
3124 else if (code == CM_ERROR_BADLOGONTYPE) {
3125 NTStatus = 0xC000015BL; /* logon type not granted */
3127 else if (code == CM_ERROR_GSSCONTINUE) {
3128 NTStatus = 0xC0000016L; /* more processing required */
3130 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3132 NTStatus = 0xC0000280L; /* reparse point not resolved */
3134 NTStatus = 0xC0000022L; /* Access Denied */
3137 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3138 NTStatus = 0xC0000257L; /* Path Not Covered */
3140 else if (code == CM_ERROR_ALLBUSY) {
3141 NTStatus = 0xC000022DL; /* Retry */
3143 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3144 NTStatus = 0xC00000BEL; /* Bad Network Path */
3146 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3147 NTStatus = 0xC0000322L; /* No Kerberos key */
3149 else if (code == CM_ERROR_BAD_LEVEL) {
3150 NTStatus = 0xC0000148L; /* Invalid Level */
3152 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3153 NTStatus = 0xC000007EL; /* Range Not Locked */
3155 else if (code == CM_ERROR_NOSUCHDEVICE) {
3156 NTStatus = 0xC000000EL; /* No Such Device */
3158 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3159 NTStatus = 0xC0000055L; /* Lock Not Granted */
3160 } else if (code == ENOMEM) {
3161 NTStatus = 0xC0000017L; /* Out of Memory */
3163 NTStatus = 0xC0982001L; /* SMB non-specific error */
3166 *NTStatusp = NTStatus;
3167 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3170 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3171 unsigned char *classp)
3173 unsigned char class;
3174 unsigned short error;
3176 /* map CM_ERROR_* errors to SMB errors */
3177 if (code == CM_ERROR_NOSUCHCELL) {
3179 error = 3; /* bad path */
3181 else if (code == CM_ERROR_NOSUCHVOLUME) {
3183 error = 3; /* bad path */
3185 else if (code == CM_ERROR_TIMEDOUT) {
3187 error = 81; /* server is paused */
3189 else if (code == CM_ERROR_RETRY) {
3190 class = 2; /* shouldn't happen */
3193 else if (code == CM_ERROR_NOACCESS) {
3195 error = 4; /* bad access */
3197 else if (code == CM_ERROR_READONLY) {
3199 error = 19; /* read only */
3201 else if (code == CM_ERROR_NOSUCHFILE ||
3202 code == CM_ERROR_BPLUS_NOMATCH) {
3204 error = 2; /* ENOENT! */
3206 else if (code == CM_ERROR_NOSUCHPATH) {
3208 error = 3; /* Bad path */
3210 else if (code == CM_ERROR_TOOBIG) {
3212 error = 11; /* bad format */
3214 else if (code == CM_ERROR_INVAL) {
3215 class = 2; /* server non-specific error code */
3218 else if (code == CM_ERROR_BADFD) {
3220 error = 6; /* invalid file handle */
3222 else if (code == CM_ERROR_BADFDOP) {
3223 class = 1; /* invalid op on FD */
3226 else if (code == CM_ERROR_EXISTS) {
3228 error = 80; /* file already exists */
3230 else if (code == CM_ERROR_NOTEMPTY) {
3232 error = 5; /* delete directory not empty */
3234 else if (code == CM_ERROR_CROSSDEVLINK) {
3236 error = 17; /* EXDEV */
3238 else if (code == CM_ERROR_NOTDIR) {
3239 class = 1; /* bad path */
3242 else if (code == CM_ERROR_ISDIR) {
3243 class = 1; /* access denied; DOS doesn't have a good match */
3246 else if (code == CM_ERROR_BADOP) {
3250 else if (code == CM_ERROR_BADSHARENAME) {
3254 else if (code == CM_ERROR_NOIPC) {
3256 error = 4; /* bad access */
3258 else if (code == CM_ERROR_CLOCKSKEW) {
3259 class = 1; /* invalid function */
3262 else if (code == CM_ERROR_BADTID) {
3266 else if (code == CM_ERROR_USESTD) {
3270 else if (code == CM_ERROR_REMOTECONN) {
3274 else if (code == CM_ERROR_QUOTA) {
3275 if (vcp->flags & SMB_VCFLAG_USEV3) {
3277 error = 39; /* disk full */
3281 error = 5; /* access denied */
3284 else if (code == CM_ERROR_SPACE) {
3285 if (vcp->flags & SMB_VCFLAG_USEV3) {
3287 error = 39; /* disk full */
3291 error = 5; /* access denied */
3294 else if (code == CM_ERROR_PARTIALWRITE) {
3296 error = 39; /* disk full */
3298 else if (code == CM_ERROR_ATSYS) {
3300 error = 2; /* ENOENT */
3302 else if (code == CM_ERROR_WOULDBLOCK) {
3304 error = 33; /* lock conflict */
3306 else if (code == CM_ERROR_LOCK_CONFLICT) {
3308 error = 33; /* lock conflict */
3310 else if (code == CM_ERROR_SHARING_VIOLATION) {
3312 error = 33; /* lock conflict */
3314 else if (code == CM_ERROR_NOFILES) {
3316 error = 18; /* no files in search */
3318 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3320 error = 183; /* Samba uses this */
3322 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3323 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3325 error = 2; /* bad password */
3327 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3329 error = 3; /* bad path */
3338 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3341 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3343 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3344 return CM_ERROR_BADOP;
3348 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3350 unsigned short EchoCount, i;
3351 char *data, *outdata;
3354 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3356 for (i=1; i<=EchoCount; i++) {
3357 data = smb_GetSMBData(inp, &dataSize);
3358 smb_SetSMBParm(outp, 0, i);
3359 smb_SetSMBDataLength(outp, dataSize);
3360 outdata = smb_GetSMBData(outp, NULL);
3361 memcpy(outdata, data, dataSize);
3362 smb_SendPacket(vcp, outp);
3368 /* SMB_COM_READ_RAW */
3369 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3372 long count, minCount, finalCount;
3376 smb_t *smbp = (smb_t*) inp;
3378 cm_user_t *userp = NULL;
3381 char *rawBuf = NULL;
3386 fd = smb_GetSMBParm(inp, 0);
3387 count = smb_GetSMBParm(inp, 3);
3388 minCount = smb_GetSMBParm(inp, 4);
3389 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3391 if (*inp->wctp == 10) {
3392 /* we were sent a request with 64-bit file offsets */
3393 #ifdef AFS_LARGEFILES
3394 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3396 if (LargeIntegerLessThanZero(offset)) {
3397 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3401 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3402 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3405 offset.HighPart = 0;
3409 /* we were sent a request with 32-bit file offsets */
3410 offset.HighPart = 0;
3413 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3414 fd, offset.HighPart, offset.LowPart, count);
3416 fidp = smb_FindFID(vcp, fd, 0);
3420 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3421 smb_CloseFID(vcp, fidp, NULL, 0);
3422 code = CM_ERROR_NOSUCHFILE;
3429 LARGE_INTEGER LOffset, LLength;
3432 key = cm_GenerateKey(vcp->vcID, pid, fd);
3434 LOffset.HighPart = offset.HighPart;
3435 LOffset.LowPart = offset.LowPart;
3436 LLength.HighPart = 0;
3437 LLength.LowPart = count;
3439 lock_ObtainWrite(&fidp->scp->rw);
3440 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3441 lock_ReleaseWrite(&fidp->scp->rw);
3447 lock_ObtainMutex(&smb_RawBufLock);
3449 /* Get a raw buf, from head of list */
3450 rawBuf = smb_RawBufs;
3451 smb_RawBufs = *(char **)smb_RawBufs;
3453 lock_ReleaseMutex(&smb_RawBufLock);
3457 lock_ObtainMutex(&fidp->mx);
3458 if (fidp->flags & SMB_FID_IOCTL)
3460 lock_ReleaseMutex(&fidp->mx);
3461 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3463 /* Give back raw buffer */
3464 lock_ObtainMutex(&smb_RawBufLock);
3465 *((char **) rawBuf) = smb_RawBufs;
3467 smb_RawBufs = rawBuf;
3468 lock_ReleaseMutex(&smb_RawBufLock);
3471 lock_ReleaseMutex(&fidp->mx);
3472 smb_ReleaseFID(fidp);
3475 lock_ReleaseMutex(&fidp->mx);
3477 userp = smb_GetUserFromVCP(vcp, inp);
3479 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3485 cm_ReleaseUser(userp);
3488 smb_ReleaseFID(fidp);
3492 memset((char *)ncbp, 0, sizeof(NCB));
3494 ncbp->ncb_length = (unsigned short) finalCount;
3495 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3496 ncbp->ncb_lana_num = vcp->lana;
3497 ncbp->ncb_command = NCBSEND;
3498 ncbp->ncb_buffer = rawBuf;
3500 code = Netbios(ncbp);
3502 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3505 /* Give back raw buffer */
3506 lock_ObtainMutex(&smb_RawBufLock);
3507 *((char **) rawBuf) = smb_RawBufs;
3509 smb_RawBufs = rawBuf;
3510 lock_ReleaseMutex(&smb_RawBufLock);
3516 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3518 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3523 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3525 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3530 /* SMB_COM_NEGOTIATE */
3531 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3538 int VistaProtoIndex;
3539 int protoIndex; /* index we're using */
3544 char protocol_array[10][1024]; /* protocol signature of the client */
3545 int caps; /* capabilities */
3548 TIME_ZONE_INFORMATION tzi;
3550 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3553 namep = smb_GetSMBData(inp, &dbytes);
3556 coreProtoIndex = -1; /* not found */
3559 VistaProtoIndex = -1;
3560 while(namex < dbytes) {
3561 osi_Log1(smb_logp, "Protocol %s",
3562 osi_LogSaveString(smb_logp, namep+1));
3563 strcpy(protocol_array[tcounter], namep+1);
3565 /* namep points at the first protocol, or really, a 0x02
3566 * byte preceding the null-terminated ASCII name.
3568 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3569 coreProtoIndex = tcounter;
3571 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3572 v3ProtoIndex = tcounter;
3574 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3575 NTProtoIndex = tcounter;
3577 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3578 VistaProtoIndex = tcounter;
3581 /* compute size of protocol entry */
3582 entryLength = (int)strlen(namep+1);
3583 entryLength += 2; /* 0x02 bytes and null termination */
3585 /* advance over this protocol entry */
3586 namex += entryLength;
3587 namep += entryLength;
3588 tcounter++; /* which proto entry we're looking at */
3591 lock_ObtainMutex(&vcp->mx);
3593 if (VistaProtoIndex != -1) {
3594 protoIndex = VistaProtoIndex;
3595 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3598 if (NTProtoIndex != -1) {
3599 protoIndex = NTProtoIndex;
3600 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3602 else if (v3ProtoIndex != -1) {
3603 protoIndex = v3ProtoIndex;
3604 vcp->flags |= SMB_VCFLAG_USEV3;
3606 else if (coreProtoIndex != -1) {
3607 protoIndex = coreProtoIndex;
3608 vcp->flags |= SMB_VCFLAG_USECORE;
3610 else protoIndex = -1;
3611 lock_ReleaseMutex(&vcp->mx);
3613 if (protoIndex == -1)
3614 return CM_ERROR_INVAL;
3615 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3616 smb_SetSMBParm(outp, 0, protoIndex);
3617 if (smb_authType != SMB_AUTH_NONE) {
3618 smb_SetSMBParmByte(outp, 1,
3619 NEGOTIATE_SECURITY_USER_LEVEL |
3620 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3622 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3624 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3625 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3626 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3627 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3628 /* The session key is not a well documented field however most clients
3629 * will echo back the session key to the server. Currently we are using
3630 * the same value for all sessions. We should generate a random value
3631 * and store it into the vcp
3633 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3634 smb_SetSMBParm(outp, 8, 1);
3636 * Tried changing the capabilities to support for W2K - defect 117695
3637 * Maybe something else needs to be changed here?
3641 smb_SetSMBParmLong(outp, 9, 0x43fd);
3643 smb_SetSMBParmLong(outp, 9, 0x251);
3646 * 32-bit error codes *
3652 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3654 NTNEGOTIATE_CAPABILITY_DFS |
3656 #ifdef AFS_LARGEFILES
3657 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3659 NTNEGOTIATE_CAPABILITY_NTFIND |
3660 NTNEGOTIATE_CAPABILITY_RAWMODE |
3661 NTNEGOTIATE_CAPABILITY_NTSMB;
3663 if ( smb_authType == SMB_AUTH_EXTENDED )
3664 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3667 if ( smb_UseUnicode ) {
3668 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3672 smb_SetSMBParmLong(outp, 9, caps);
3674 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3675 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3676 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3678 GetTimeZoneInformation(&tzi);
3679 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3681 if (smb_authType == SMB_AUTH_NTLM) {
3682 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3683 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3684 /* paste in encryption key */
3685 datap = smb_GetSMBData(outp, NULL);
3686 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3687 /* and the faux domain name */
3688 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3689 datap + MSV1_0_CHALLENGE_LENGTH,
3690 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3691 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3695 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3697 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3699 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3701 datap = smb_GetSMBData(outp, NULL);
3702 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3705 datap += sizeof(smb_ServerGUID);
3706 memcpy(datap, secBlob, secBlobLength);
3710 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3711 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3714 else if (v3ProtoIndex != -1) {
3715 smb_SetSMBParm(outp, 0, protoIndex);
3717 /* NOTE: Extended authentication cannot be negotiated with v3
3718 * therefore we fail over to NTLM
3720 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3721 smb_SetSMBParm(outp, 1,
3722 NEGOTIATE_SECURITY_USER_LEVEL |
3723 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3725 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3727 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3728 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3729 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3730 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3731 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3732 smb_SetSMBParm(outp, 7, 1);
3734 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3735 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3736 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3738 GetTimeZoneInformation(&tzi);
3739 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3741 /* NOTE: Extended authentication cannot be negotiated with v3
3742 * therefore we fail over to NTLM
3744 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3745 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3746 smb_SetSMBParm(outp, 12, 0); /* resvd */
3747 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3748 datap = smb_GetSMBData(outp, NULL);
3749 /* paste in a new encryption key */
3750 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3751 /* and the faux domain name */
3752 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3753 datap + MSV1_0_CHALLENGE_LENGTH,
3754 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3756 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3757 smb_SetSMBParm(outp, 12, 0); /* resvd */
3758 smb_SetSMBDataLength(outp, 0);
3761 else if (coreProtoIndex != -1) { /* not really supported anymore */
3762 smb_SetSMBParm(outp, 0, protoIndex);
3763 smb_SetSMBDataLength(outp, 0);
3768 void smb_CheckVCs(void)
3770 smb_vc_t * vcp, *nextp;
3771 smb_packet_t * outp = smb_GetPacket();
3774 lock_ObtainWrite(&smb_rctLock);
3775 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3777 if (vcp->magic != SMB_VC_MAGIC)
3778 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3779 __FILE__, __LINE__);
3781 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3783 smb_HoldVCNoLock(vcp);
3786 * obtain a reference to 'nextp' now because we drop the
3787 * smb_rctLock later and the list contents could change
3788 * or 'vcp' could be destroyed when released.
3792 smb_HoldVCNoLock(nextp);
3794 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3795 smb_ReleaseVCNoLock(vcp);
3799 smb_FormatResponsePacket(vcp, NULL, outp);
3800 smbp = (smb_t *)outp;
3801 outp->inCom = smbp->com = 0x2b /* Echo */;
3809 smb_SetSMBParm(outp, 0, 0);
3810 smb_SetSMBDataLength(outp, 0);
3811 lock_ReleaseWrite(&smb_rctLock);
3813 smb_SendPacket(vcp, outp);
3815 lock_ObtainWrite(&smb_rctLock);
3816 smb_ReleaseVCNoLock(vcp);
3818 lock_ReleaseWrite(&smb_rctLock);
3819 smb_FreePacket(outp);
3822 void smb_Daemon(void *parmp)
3824 afs_uint32 count = 0;
3825 smb_username_t **unpp;
3828 while(smbShutdownFlag == 0) {
3832 if (smbShutdownFlag == 1)
3835 if ((count % 72) == 0) { /* every five minutes */
3837 time_t old_localZero = smb_localZero;
3839 /* Initialize smb_localZero */
3840 myTime.tm_isdst = -1; /* compute whether on DST or not */
3841 myTime.tm_year = 70;
3847 smb_localZero = mktime(&myTime);
3849 #ifndef USE_NUMERIC_TIME_CONV
3850 smb_CalculateNowTZ();
3851 #endif /* USE_NUMERIC_TIME_CONV */
3852 #ifdef AFS_FREELANCE
3853 if ( smb_localZero != old_localZero )
3854 cm_noteLocalMountPointChange();
3860 /* GC smb_username_t objects that will no longer be used */
3862 lock_ObtainWrite(&smb_rctLock);
3863 for ( unpp=&usernamesp; *unpp; ) {
3865 smb_username_t *unp;
3867 lock_ObtainMutex(&(*unpp)->mx);
3868 if ( (*unpp)->refCount > 0 ||
3869 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3870 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3872 else if (!smb_LogoffTokenTransfer ||
3873 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3875 lock_ReleaseMutex(&(*unpp)->mx);
3883 lock_FinalizeMutex(&unp->mx);
3889 cm_ReleaseUser(userp);
3891 unpp = &(*unpp)->nextp;
3894 lock_ReleaseWrite(&smb_rctLock);
3896 /* XXX GC dir search entries */
3900 void smb_WaitingLocksDaemon()
3902 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3903 smb_waitingLock_t *wl, *wlNext;
3906 smb_packet_t *inp, *outp;
3910 while (smbShutdownFlag == 0) {
3911 lock_ObtainWrite(&smb_globalLock);
3912 nwlRequest = smb_allWaitingLocks;
3913 if (nwlRequest == NULL) {
3914 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3919 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3926 lock_ObtainWrite(&smb_globalLock);
3928 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3930 wlRequest = nwlRequest;
3931 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3932 lock_ReleaseWrite(&smb_globalLock);
3936 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3937 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3940 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3941 code = CM_ERROR_LOCK_NOT_GRANTED;
3945 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3947 /* wl->state is either _DONE or _WAITING. _ERROR
3948 would no longer be on the queue. */
3949 code = cm_RetryLock( wl->lockp,
3950 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3953 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3954 } else if (code != CM_ERROR_WOULDBLOCK) {
3955 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3960 if (code == CM_ERROR_WOULDBLOCK) {
3963 if (wlRequest->msTimeout != 0xffffffff
3964 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3976 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3979 scp = wlRequest->scp;
3980 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3984 lock_ObtainWrite(&scp->rw);
3986 for (wl = wlRequest->locks; wl; wl = wlNext) {
3987 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3989 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3990 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3991 wl->LLength, wl->key, NULL, &req);
3993 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3998 lock_ReleaseWrite(&scp->rw);
4002 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4005 for (wl = wlRequest->locks; wl; wl = wlNext) {
4006 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4007 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4012 vcp = wlRequest->vcp;
4013 inp = wlRequest->inp;
4014 outp = wlRequest->outp;
4015 ncbp = smb_GetNCB();
4016 ncbp->ncb_length = inp->ncb_length;
4017 inp->spacep = cm_GetSpace();
4019 /* Remove waitingLock from list */
4020 lock_ObtainWrite(&smb_globalLock);
4021 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4023 lock_ReleaseWrite(&smb_globalLock);
4025 /* Resume packet processing */
4027 smb_SetSMBDataLength(outp, 0);
4028 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4029 outp->resumeCode = code;
4031 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4034 cm_FreeSpace(inp->spacep);
4035 smb_FreePacket(inp);
4036 smb_FreePacket(outp);
4038 cm_ReleaseSCache(wlRequest->scp);
4041 } while (nwlRequest && smbShutdownFlag == 0);
4046 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4048 osi_Log0(smb_logp, "SMB receive get disk attributes");
4050 smb_SetSMBParm(outp, 0, 32000);
4051 smb_SetSMBParm(outp, 1, 64);
4052 smb_SetSMBParm(outp, 2, 1024);
4053 smb_SetSMBParm(outp, 3, 30000);
4054 smb_SetSMBParm(outp, 4, 0);
4055 smb_SetSMBDataLength(outp, 0);
4059 /* SMB_COM_TREE_CONNECT */
4060 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4064 unsigned short newTid;
4065 clientchar_t shareName[AFSPATHMAX];
4066 clientchar_t *sharePath;
4069 clientchar_t *pathp;
4072 osi_Log0(smb_logp, "SMB receive tree connect");
4074 /* parse input parameters */
4077 tbp = smb_GetSMBData(inp, NULL);
4078 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4080 tp = cm_ClientStrRChr(pathp, '\\');
4082 return CM_ERROR_BADSMB;
4083 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4085 lock_ObtainMutex(&vcp->mx);
4086 newTid = vcp->tidCounter++;
4087 lock_ReleaseMutex(&vcp->mx);
4089 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4090 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4092 return CM_ERROR_BADSMB;
4093 userp = smb_GetUserFromUID(uidp);
4094 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4095 smb_ReleaseUID(uidp);
4097 smb_ReleaseTID(tidp, FALSE);
4098 return CM_ERROR_BADSHARENAME;
4100 lock_ObtainMutex(&tidp->mx);
4101 tidp->userp = userp;
4102 tidp->pathname = sharePath;
4103 lock_ReleaseMutex(&tidp->mx);
4104 smb_ReleaseTID(tidp, FALSE);
4106 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4107 smb_SetSMBParm(rsp, 1, newTid);
4108 smb_SetSMBDataLength(rsp, 0);
4110 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4114 /* set maskp to the mask part of the incoming path.
4115 * Mask is 11 bytes long (8.3 with the dot elided).
4116 * Returns true if succeeds with a valid name, otherwise it does
4117 * its best, but returns false.
4119 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4127 /* starts off valid */
4130 /* mask starts out all blanks */
4131 memset(maskp, ' ', 11);
4134 /* find last backslash, or use whole thing if there is none */
4135 tp = cm_ClientStrRChr(pathp, '\\');
4139 tp++; /* skip slash */
4143 /* names starting with a dot are illegal */
4151 if (tc == '.' || tc == '"')
4159 /* if we get here, tp point after the dot */
4160 up = maskp+8; /* ext goes here */
4167 if (tc == '.' || tc == '"')
4170 /* copy extension if not too long */
4180 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4182 clientchar_t umask[11];
4190 /* XXX redo this, calling cm_MatchMask with a converted mask */
4192 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4196 /* otherwise, we have a valid 8.3 name; see if we have a match,
4197 * treating '?' as a wildcard in maskp (but not in the file name).
4199 tp1 = umask; /* real name, in mask format */
4200 tp2 = maskp; /* mask, in mask format */
4201 for(i=0; i<11; i++) {
4202 tc1 = *tp1++; /* clientchar_t from real name */
4203 tc2 = *tp2++; /* clientchar_t from mask */
4204 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4205 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4208 if (tc2 == '?' && tc1 != ' ')
4215 /* we got a match */
4219 clientchar_t *smb_FindMask(clientchar_t *pathp)
4223 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4226 return tp+1; /* skip the slash */
4228 return pathp; /* no slash, return the entire path */
4231 /* SMB_COM_SEARCH for a volume label
4233 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4234 dispatch function.) */
4235 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4237 clientchar_t *pathp;
4239 clientchar_t mask[12];
4240 unsigned char *statBlockp;
4241 unsigned char initStatBlock[21];
4244 osi_Log0(smb_logp, "SMB receive search volume");
4246 /* pull pathname and stat block out of request */
4247 tp = smb_GetSMBData(inp, NULL);
4248 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4249 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4250 osi_assertx(pathp != NULL, "null path");
4251 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4252 osi_assertx(statBlockp != NULL, "null statBlock");
4254 statBlockp = initStatBlock;
4258 /* for returning to caller */
4259 smb_Get8Dot3MaskFromPath(mask, pathp);
4261 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4262 tp = smb_GetSMBData(outp, NULL);
4264 *tp++ = 43; /* bytes in a dir entry */
4265 *tp++ = 0; /* high byte in counter */
4267 /* now marshall the dir entry, starting with the search status */
4268 *tp++ = statBlockp[0]; /* Reserved */
4269 memcpy(tp, mask, 11); tp += 11; /* FileName */
4271 /* now pass back server use info, with 1st byte non-zero */
4273 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4275 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4277 *tp++ = 0x8; /* attribute: volume */
4287 /* 4 byte file size */
4293 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4296 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4297 memset(tp, ' ', 13);
4300 /* set the length of the data part of the packet to 43 + 3, for the dir
4301 * entry plus the 5 and the length fields.
4303 smb_SetSMBDataLength(outp, 46);
4308 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4309 clientchar_t * tidPathp, clientchar_t * relPathp,
4310 cm_user_t *userp, cm_req_t *reqp)
4318 smb_dirListPatch_t *patchp;
4319 smb_dirListPatch_t *npatchp;
4320 clientchar_t path[AFSPATHMAX];
4322 afs_int32 mustFake = 0;
4324 code = cm_FindACLCache(dscp, userp, &rights);
4326 lock_ObtainWrite(&dscp->rw);
4327 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4328 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4329 lock_ReleaseWrite(&dscp->rw);
4330 if (code == CM_ERROR_NOACCESS) {
4338 if (!mustFake) { /* Bulk Stat */
4340 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4342 memset(bsp, 0, sizeof(cm_bulkStat_t));
4344 for (patchp = *dirPatchespp, count=0;
4346 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4347 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4351 if (lock_TryWrite(&tscp->rw)) {
4352 /* we have an entry that we can look at */
4353 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4354 /* we have a callback on it. Don't bother
4355 * fetching this stat entry, since we're happy
4356 * with the info we have.
4358 lock_ReleaseWrite(&tscp->rw);
4359 cm_ReleaseSCache(tscp);
4362 lock_ReleaseWrite(&tscp->rw);
4364 cm_ReleaseSCache(tscp);
4368 bsp->fids[i].Volume = patchp->fid.volume;
4369 bsp->fids[i].Vnode = patchp->fid.vnode;
4370 bsp->fids[i].Unique = patchp->fid.unique;
4372 if (bsp->counter == AFSCBMAX) {
4373 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4374 memset(bsp, 0, sizeof(cm_bulkStat_t));
4378 if (bsp->counter > 0)
4379 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4384 for (patchp = *dirPatchespp; patchp; patchp =
4385 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4387 dptr = patchp->dptr;
4389 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4390 relPathp ? relPathp : _C(""), patchp->dep->name);
4391 reqp->relPathp = path;
4392 reqp->tidPathp = tidPathp;
4394 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4395 reqp->relPathp = reqp->tidPathp = NULL;
4398 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4399 *dptr++ = SMB_ATTR_HIDDEN;
4402 lock_ObtainWrite(&scp->rw);