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 void smb_MarkAllVCsDead(smb_vc_t * exclude)
825 smb_vc_t **vcp_to_cleanup = NULL;
826 int n_to_cleanup = 0;
829 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
831 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
832 lock_ObtainWrite(&smb_rctLock);
833 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
835 if (vcp->magic != SMB_VC_MAGIC)
836 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
842 lock_ObtainMutex(&vcp->mx);
843 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
844 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
845 lock_ReleaseMutex(&vcp->mx);
846 dead_sessions[vcp->session] = TRUE;
848 lock_ReleaseMutex(&vcp->mx);
853 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
855 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
859 vcp_to_cleanup[i++] = vcp;
860 smb_HoldVCNoLock(vcp);
863 osi_assert(i == n_to_cleanup);
865 lock_ReleaseWrite(&smb_rctLock);
866 lock_ReleaseWrite(&smb_globalLock);
868 for (i=0; i < n_to_cleanup; i++) {
869 smb_CleanupDeadVC(vcp_to_cleanup[i]);
870 smb_ReleaseVC(vcp_to_cleanup[i]);
871 vcp_to_cleanup[i] = 0;
874 free(vcp_to_cleanup);
877 #ifdef DEBUG_SMB_REFCOUNT
878 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
880 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
885 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
886 lock_ObtainWrite(&smb_rctLock);
887 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
888 if (vcp->magic != SMB_VC_MAGIC)
889 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
892 lock_ObtainMutex(&vcp->mx);
893 if (lsn == vcp->lsn && lana == vcp->lana &&
894 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
895 lock_ReleaseMutex(&vcp->mx);
896 smb_HoldVCNoLock(vcp);
899 lock_ReleaseMutex(&vcp->mx);
901 if (!vcp && (flags & SMB_FLAG_CREATE)) {
902 vcp = malloc(sizeof(*vcp));
903 memset(vcp, 0, sizeof(*vcp));
904 vcp->vcID = ++numVCs;
905 vcp->magic = SMB_VC_MAGIC;
906 vcp->refCount = 2; /* smb_allVCsp and caller */
909 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
910 vcp->nextp = smb_allVCsp;
912 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
917 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
918 /* We must obtain a challenge for extended auth
919 * in case the client negotiates smb v3
921 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
922 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
923 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
924 ULONG lsaRespSize = 0;
926 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
928 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
935 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
936 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
937 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
938 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
939 nts, ntsEx, lsaRespSize);
941 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
943 if (ntsEx == STATUS_SUCCESS) {
944 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
947 * This will cause the subsequent authentication to fail but
948 * that is better than us dereferencing a NULL pointer and
951 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
954 LsaFreeReturnBuffer(lsaResp);
957 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
959 if (numVCs >= CM_SESSION_RESERVED) {
961 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
964 #ifdef DEBUG_SMB_REFCOUNT
966 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
967 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
970 lock_ReleaseWrite(&smb_rctLock);
971 lock_ReleaseWrite(&smb_globalLock);
975 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
980 for(i=0; i<11; i++) {
982 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
988 static int smb_IsStarMask(clientchar_t *maskp)
994 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
1000 #ifdef DEBUG_SMB_REFCOUNT
1001 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
1002 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
1004 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1010 lock_AssertWrite(&smb_rctLock);
1013 if (vcp->refCount == 0) {
1014 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1015 #ifdef DEBUG_SMB_REFCOUNT
1016 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1017 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1019 /* remove VCP from smb_deadVCsp */
1020 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1026 lock_FinalizeMutex(&vcp->mx);
1027 memset(vcp,0,sizeof(smb_vc_t));
1030 #ifdef DEBUG_SMB_REFCOUNT
1031 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
1033 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1037 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1038 avcp?"":"not ",vcp, vcp->refCount);
1040 /* This is a wrong. However, I suspect that there is an undercount
1041 * and I don't want to release 1.4.1 in a state that will allow
1042 * smb_vc_t objects to be deallocated while still in the
1043 * smb_allVCsp list. The list is supposed to keep a reference
1044 * to the smb_vc_t. Put it back.
1048 #ifdef DEBUG_SMB_REFCOUNT
1049 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1050 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1054 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1055 /* The reference count is non-zero but the VC is dead.
1056 * This implies that some FIDs, TIDs, etc on the VC have yet to
1057 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1058 * add a reference that will be dropped by
1059 * smb_CleanupDeadVC() and try to cleanup the VC again.
1060 * Eventually the refCount will drop to zero when all of the
1061 * active threads working with the VC end their task.
1063 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1064 vcp->refCount++; /* put the refCount back */
1065 lock_ReleaseWrite(&smb_rctLock);
1066 smb_CleanupDeadVC(vcp);
1067 #ifdef DEBUG_SMB_REFCOUNT
1068 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1069 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1071 lock_ObtainWrite(&smb_rctLock);
1074 #ifdef DEBUG_SMB_REFCOUNT
1075 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1076 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1081 #ifdef DEBUG_SMB_REFCOUNT
1082 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1084 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1087 lock_AssertWrite(&smb_rctLock);
1088 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1089 smb_ReleaseVCInternal(vcp);
1092 #ifdef DEBUG_SMB_REFCOUNT
1093 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1095 void smb_ReleaseVC(smb_vc_t *vcp)
1098 lock_ObtainWrite(&smb_rctLock);
1099 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1100 smb_ReleaseVCInternal(vcp);
1101 lock_ReleaseWrite(&smb_rctLock);
1104 #ifdef DEBUG_SMB_REFCOUNT
1105 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1107 void smb_HoldVCNoLock(smb_vc_t *vcp)
1110 lock_AssertWrite(&smb_rctLock);
1112 #ifdef DEBUG_SMB_REFCOUNT
1113 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1114 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1116 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1120 #ifdef DEBUG_SMB_REFCOUNT
1121 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1123 void smb_HoldVC(smb_vc_t *vcp)
1126 lock_ObtainWrite(&smb_rctLock);
1128 #ifdef DEBUG_SMB_REFCOUNT
1129 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1130 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1132 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1134 lock_ReleaseWrite(&smb_rctLock);
1137 void smb_CleanupDeadVC(smb_vc_t *vcp)
1139 smb_fid_t *fidpIter;
1140 smb_fid_t *fidpNext;
1142 smb_tid_t *tidpIter;
1143 smb_tid_t *tidpNext;
1145 smb_user_t *uidpIter;
1146 smb_user_t *uidpNext;
1148 afs_uint32 refCount = 0;
1150 lock_ObtainMutex(&vcp->mx);
1151 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1152 lock_ReleaseMutex(&vcp->mx);
1153 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1156 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1157 lock_ReleaseMutex(&vcp->mx);
1158 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1160 lock_ObtainWrite(&smb_rctLock);
1161 /* remove VCP from smb_allVCsp */
1162 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1163 if ((*vcpp)->magic != SMB_VC_MAGIC)
1164 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1165 __FILE__, __LINE__);
1168 vcp->nextp = smb_deadVCsp;
1170 /* Hold onto the reference until we are done with this function */
1175 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1176 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1178 if (fidpIter->deleteOk)
1181 fid = fidpIter->fid;
1182 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1184 smb_HoldFIDNoLock(fidpIter);
1185 lock_ReleaseWrite(&smb_rctLock);
1187 smb_CloseFID(vcp, fidpIter, NULL, 0);
1188 smb_ReleaseFID(fidpIter);
1190 lock_ObtainWrite(&smb_rctLock);
1191 fidpNext = vcp->fidsp;
1194 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1195 tidpNext = tidpIter->nextp;
1196 if (tidpIter->deleteOk)
1198 tidpIter->deleteOk = 1;
1200 tid = tidpIter->tid;
1201 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1203 smb_HoldTIDNoLock(tidpIter);
1204 smb_ReleaseTID(tidpIter, TRUE);
1205 tidpNext = vcp->tidsp;
1208 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1209 uidpNext = uidpIter->nextp;
1210 if (uidpIter->deleteOk)
1212 uidpIter->deleteOk = 1;
1214 /* do not add an additional reference count for the smb_user_t
1215 * as the smb_vc_t already is holding a reference */
1216 lock_ReleaseWrite(&smb_rctLock);
1218 smb_ReleaseUID(uidpIter);
1220 lock_ObtainWrite(&smb_rctLock);
1221 uidpNext = vcp->usersp;
1224 /* The vcp is now on the deadVCsp list. We intentionally drop the
1225 * reference so that the refcount can reach 0 and we can delete it
1227 * If the refCount == 1 going into the ReleaseVCNoLock call
1228 * the object will be freed and it won't be safe to clear
1231 refCount = vcp->refCount;
1232 smb_ReleaseVCNoLock(vcp);
1234 lock_ObtainMutex(&vcp->mx);
1235 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1236 lock_ReleaseMutex(&vcp->mx);
1239 lock_ReleaseWrite(&smb_rctLock);
1240 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1246 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1251 lock_ObtainWrite(&smb_rctLock);
1253 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1254 if (tidp->refCount == 0 && tidp->deleteOk) {
1256 smb_ReleaseTID(tidp, TRUE);
1260 if (tid == tidp->tid) {
1265 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1266 tidp = malloc(sizeof(*tidp));
1267 memset(tidp, 0, sizeof(*tidp));
1268 tidp->nextp = vcp->tidsp;
1271 smb_HoldVCNoLock(vcp);
1273 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1276 #ifdef DEBUG_SMB_REFCOUNT
1278 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1279 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1282 lock_ReleaseWrite(&smb_rctLock);
1286 #ifdef DEBUG_SMB_REFCOUNT
1287 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1289 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1292 lock_AssertWrite(&smb_rctLock);
1294 #ifdef DEBUG_SMB_REFCOUNT
1295 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1296 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1300 #ifdef DEBUG_SMB_REFCOUNT
1301 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1303 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1308 cm_user_t *userp = NULL;
1309 smb_vc_t *vcp = NULL;
1312 lock_ObtainWrite(&smb_rctLock);
1314 lock_AssertWrite(&smb_rctLock);
1316 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1317 #ifdef DEBUG_SMB_REFCOUNT
1318 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1319 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1321 if (tidp->refCount == 0) {
1322 if (tidp->deleteOk) {
1323 ltpp = &tidp->vcp->tidsp;
1324 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1328 osi_assertx(tp != NULL, "null smb_tid_t");
1330 lock_FinalizeMutex(&tidp->mx);
1331 userp = tidp->userp; /* remember to drop ref later */
1339 smb_ReleaseVCNoLock(vcp);
1341 lock_ReleaseWrite(&smb_rctLock);
1343 cm_ReleaseUser(userp);
1346 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1348 smb_user_t *uidp = NULL;
1350 lock_ObtainWrite(&smb_rctLock);
1351 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1352 if (uid == uidp->userID) {
1354 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1356 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1360 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1361 uidp = malloc(sizeof(*uidp));
1362 memset(uidp, 0, sizeof(*uidp));
1363 uidp->nextp = vcp->usersp;
1364 uidp->refCount = 2; /* one for the vcp and one for the caller */
1366 smb_HoldVCNoLock(vcp);
1368 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1370 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1372 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1374 lock_ReleaseWrite(&smb_rctLock);
1378 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1381 smb_username_t *unp= NULL;
1383 lock_ObtainWrite(&smb_rctLock);
1384 for(unp = usernamesp; unp; unp = unp->nextp) {
1385 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1386 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1391 if (!unp && (flags & SMB_FLAG_CREATE)) {
1392 unp = malloc(sizeof(*unp));
1393 memset(unp, 0, sizeof(*unp));
1395 unp->nextp = usernamesp;
1396 unp->name = cm_ClientStrDup(usern);
1397 unp->machine = cm_ClientStrDup(machine);
1399 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1400 if (flags & SMB_FLAG_AFSLOGON)
1401 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1404 lock_ReleaseWrite(&smb_rctLock);
1408 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1410 smb_user_t *uidp= NULL;
1412 lock_ObtainWrite(&smb_rctLock);
1413 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1416 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1418 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1419 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1424 lock_ReleaseWrite(&smb_rctLock);
1428 void smb_ReleaseUsername(smb_username_t *unp)
1431 smb_username_t **lupp;
1432 cm_user_t *userp = NULL;
1433 time_t now = osi_Time();
1435 lock_ObtainWrite(&smb_rctLock);
1436 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1437 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1438 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1440 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1444 osi_assertx(up != NULL, "null smb_username_t");
1446 up->nextp = NULL; /* do not remove this */
1447 lock_FinalizeMutex(&unp->mx);
1453 lock_ReleaseWrite(&smb_rctLock);
1455 cm_ReleaseUser(userp);
1458 void smb_HoldUIDNoLock(smb_user_t *uidp)
1460 lock_AssertWrite(&smb_rctLock);
1464 void smb_ReleaseUID(smb_user_t *uidp)
1468 smb_username_t *unp = NULL;
1470 lock_ObtainWrite(&smb_rctLock);
1471 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1472 if (uidp->refCount == 0) {
1473 lupp = &uidp->vcp->usersp;
1474 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1478 osi_assertx(up != NULL, "null smb_user_t");
1480 lock_FinalizeMutex(&uidp->mx);
1482 smb_ReleaseVCNoLock(uidp->vcp);
1486 lock_ReleaseWrite(&smb_rctLock);
1490 cm_ReleaseUserVCRef(unp->userp);
1491 smb_ReleaseUsername(unp);
1495 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1497 cm_user_t *up = NULL;
1502 lock_ObtainMutex(&uidp->mx);
1504 up = uidp->unp->userp;
1507 lock_ReleaseMutex(&uidp->mx);
1513 /* retrieve a held reference to a user structure corresponding to an incoming
1515 * corresponding release function is cm_ReleaseUser.
1517 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1520 cm_user_t *up = NULL;
1523 smbp = (smb_t *) inp;
1524 uidp = smb_FindUID(vcp, smbp->uid, 0);
1528 up = smb_GetUserFromUID(uidp);
1530 smb_ReleaseUID(uidp);
1535 * Return a pointer to a pathname extracted from a TID structure. The
1536 * TID structure is not held; assume it won't go away.
1538 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1543 tidp = smb_FindTID(vcp, tid, 0);
1547 if (tidp->flags & SMB_TIDFLAG_IPC) {
1548 code = CM_ERROR_TIDIPC;
1549 /* tidp->pathname would be NULL, but that's fine */
1551 *treepath = tidp->pathname;
1552 smb_ReleaseTID(tidp, FALSE);
1557 /* check to see if we have a chained fid, that is, a fid that comes from an
1558 * OpenAndX message that ran earlier in this packet. In this case, the fid
1559 * field in a read, for example, request, isn't set, since the value is
1560 * supposed to be inherited from the openAndX call.
1562 int smb_ChainFID(int fid, smb_packet_t *inp)
1564 if (inp->fid == 0 || inp->inCount == 0)
1570 /* are we a priv'd user? What does this mean on NT? */
1571 int smb_SUser(cm_user_t *userp)
1576 /* find a file ID. If we pass in 0 we select an unused File ID.
1577 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1578 * smb_fid_t data structure if desired File ID cannot be found.
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1583 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1589 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1592 lock_ObtainWrite(&smb_rctLock);
1593 /* figure out if we need to allocate a new file ID */
1596 fid = vcp->fidCounter;
1600 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1601 if (fidp->refCount == 0 && fidp->deleteOk) {
1603 lock_ReleaseWrite(&smb_rctLock);
1604 smb_ReleaseFID(fidp);
1605 lock_ObtainWrite(&smb_rctLock);
1608 if (fid == fidp->fid) {
1611 if (fid == 0xFFFF) {
1613 "New FID number wraps on vcp 0x%x", vcp);
1623 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1624 char eventName[MAX_PATH];
1626 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1627 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1628 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1629 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1630 thrd_CloseHandle(event);
1632 if (fid == 0xFFFF) {
1633 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1639 fidp = malloc(sizeof(*fidp));
1640 memset(fidp, 0, sizeof(*fidp));
1641 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1644 smb_HoldVCNoLock(vcp);
1645 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1647 fidp->curr_chunk = fidp->prev_chunk = -2;
1648 fidp->raw_write_event = event;
1650 vcp->fidCounter = fid+1;
1651 if (vcp->fidCounter == 0xFFFF) {
1652 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1654 vcp->fidCounter = 1;
1659 #ifdef DEBUG_SMB_REFCOUNT
1661 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1662 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1665 lock_ReleaseWrite(&smb_rctLock);
1670 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1671 #ifdef DEBUG_SMB_REFCOUNT
1672 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1674 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1677 smb_fid_t *fidp = NULL, *nextp = NULL;
1683 * If the fidp->scp changes out from under us then
1684 * we must not grab a refCount. It means the *fidp
1685 * was processed by smb_CloseFID() and the *fidp is
1686 * no longer valid for use.
1688 lock_ObtainWrite(&smb_rctLock);
1689 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1690 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1694 if (scp == fidp->scp) {
1695 lock_ReleaseWrite(&smb_rctLock);
1696 lock_ObtainMutex(&fidp->mx);
1697 lock_ObtainWrite(&smb_rctLock);
1698 if (scp == fidp->scp) {
1699 lock_ReleaseMutex(&fidp->mx);
1702 lock_ReleaseMutex(&fidp->mx);
1705 if (fidp->refCount > 1) {
1708 lock_ReleaseWrite(&smb_rctLock);
1709 smb_ReleaseFID(fidp);
1710 lock_ObtainWrite(&smb_rctLock);
1715 if (nextp->refCount > 1) {
1718 lock_ReleaseWrite(&smb_rctLock);
1719 smb_ReleaseFID(nextp);
1720 lock_ObtainWrite(&smb_rctLock);
1724 #ifdef DEBUG_SMB_REFCOUNT
1726 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1727 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1730 lock_ReleaseWrite(&smb_rctLock);
1734 #ifdef DEBUG_SMB_REFCOUNT
1735 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1737 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1740 lock_AssertWrite(&smb_rctLock);
1742 #ifdef DEBUG_SMB_REFCOUNT
1743 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1744 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1749 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1750 /* the smb_fid_t->mx and smb_rctLock must not be held */
1751 #ifdef DEBUG_SMB_REFCOUNT
1752 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1754 void smb_ReleaseFID(smb_fid_t *fidp)
1757 cm_scache_t *scp = NULL;
1758 cm_user_t *userp = NULL;
1759 smb_vc_t *vcp = NULL;
1760 smb_ioctl_t *ioctlp;
1762 lock_ObtainMutex(&fidp->mx);
1763 lock_ObtainWrite(&smb_rctLock);
1764 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1765 #ifdef DEBUG_SMB_REFCOUNT
1766 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1767 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1769 if (fidp->refCount == 0) {
1770 if (fidp->deleteOk) {
1773 scp = fidp->scp; /* release after lock is released */
1775 lock_ObtainWrite(&scp->rw);
1776 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1777 lock_ReleaseWrite(&scp->rw);
1778 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1781 userp = fidp->userp;
1785 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1786 thrd_CloseHandle(fidp->raw_write_event);
1788 /* and see if there is ioctl stuff to free */
1789 ioctlp = fidp->ioctlp;
1792 cm_FreeSpace(ioctlp->prefix);
1793 if (ioctlp->ioctl.inAllocp)
1794 free(ioctlp->ioctl.inAllocp);
1795 if (ioctlp->ioctl.outAllocp)
1796 free(ioctlp->ioctl.outAllocp);
1799 lock_ReleaseMutex(&fidp->mx);
1800 lock_FinalizeMutex(&fidp->mx);
1805 smb_ReleaseVCNoLock(vcp);
1809 lock_ReleaseMutex(&fidp->mx);
1811 lock_ReleaseWrite(&smb_rctLock);
1813 /* now release the scache structure */
1815 cm_ReleaseSCache(scp);
1818 cm_ReleaseUser(userp);
1822 * Case-insensitive search for one string in another;
1823 * used to find variable names in submount pathnames.
1825 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1827 clientchar_t *cursor;
1829 for (cursor = str1; *cursor; cursor++)
1830 if (cm_ClientStrCmpI(cursor, str2) == 0)
1837 * Substitute a variable value for its name in a submount pathname. Variable
1838 * name has been identified by smb_stristr() and is in substr. Variable name
1839 * length (plus one) is in substr_size. Variable value is in newstr.
1841 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1842 unsigned int substr_size, clientchar_t *newstr)
1844 clientchar_t temp[1024];
1846 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1847 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1848 cm_ClientStrCat(str1, cchstr1, temp);
1851 clientchar_t VNUserName[] = _C("%USERNAME%");
1852 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1853 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1854 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1856 typedef struct smb_findShare_rock {
1857 clientchar_t * shareName;
1858 clientchar_t * match;
1860 } smb_findShare_rock_t;
1862 #define SMB_FINDSHARE_EXACT_MATCH 1
1863 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1865 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1869 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1870 normchar_t normName[MAX_PATH];
1872 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1873 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1874 osi_LogSaveString(smb_logp, dep->name));
1878 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1879 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1880 matchType = SMB_FINDSHARE_EXACT_MATCH;
1882 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1885 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1886 vrock->matchType = matchType;
1888 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1889 return CM_ERROR_STOPNOW;
1895 /* find a shareName in the table of submounts */
1896 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1897 clientchar_t *shareName,
1898 clientchar_t **pathNamep)
1902 clientchar_t pathName[1024];
1905 clientchar_t *p, *q;
1906 fschar_t *cellname = NULL;
1909 DWORD allSubmount = 1;
1911 /* if allSubmounts == 0, only return the //mountRoot/all share
1912 * if in fact it has been been created in the subMounts table.
1913 * This is to allow sites that want to restrict access to the
1916 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1917 0, KEY_QUERY_VALUE, &parmKey);
1918 if (code == ERROR_SUCCESS) {
1919 cblen = sizeof(allSubmount);
1920 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1921 (BYTE *) &allSubmount, &cblen);
1922 if (code != ERROR_SUCCESS) {
1925 RegCloseKey (parmKey);
1928 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1933 /* In case, the all share is disabled we need to still be able
1934 * to handle ioctl requests
1936 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1937 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1941 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1942 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1943 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1944 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1945 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1951 /* Check for volume references
1953 * They look like <cell>{%,#}<volume>
1955 if (cm_ClientStrChr(shareName, '%') != NULL ||
1956 cm_ClientStrChr(shareName, '#') != NULL) {
1957 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1958 /* make room for '/@vol:' + mountchar + NULL terminator*/
1960 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1961 osi_LogSaveClientString(smb_logp, shareName));
1963 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1964 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1965 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1967 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1969 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1970 cm_ClientStrLwr(*pathNamep);
1971 osi_Log1(smb_logp, " returning pathname [%S]",
1972 osi_LogSaveClientString(smb_logp, *pathNamep));
1980 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1981 0, KEY_QUERY_VALUE, &parmKey);
1982 if (code == ERROR_SUCCESS) {
1983 cblen = sizeof(pathName);
1984 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1985 (BYTE *) pathName, &cblen);
1986 if (code != ERROR_SUCCESS)
1988 RegCloseKey (parmKey);
1992 cchlen = cblen / sizeof(clientchar_t);
1993 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1994 /* We can accept either unix or PC style AFS pathnames. Convert
1995 * Unix-style to PC style here for internal use.
1998 cchlen = lengthof(pathName);
2000 /* within this code block, we maintain, cchlen = writeable
2001 buffer length of p */
2003 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
2004 p += cm_mountRootCLen; /* skip mount path */
2005 cchlen -= (DWORD)(p - pathName);
2010 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
2016 clientchar_t temp[1024];
2018 if (var = smb_stristr(p, VNUserName)) {
2019 if (uidp && uidp->unp)
2020 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
2022 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
2024 else if (var = smb_stristr(p, VNLCUserName))
2026 if (uidp && uidp->unp)
2027 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
2029 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
2030 cm_ClientStrLwr(temp);
2031 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2033 else if (var = smb_stristr(p, VNComputerName))
2035 sizeTemp = lengthof(temp);
2036 GetComputerNameW(temp, &sizeTemp);
2037 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2039 else if (var = smb_stristr(p, VNLCComputerName))
2041 sizeTemp = lengthof(temp);
2042 GetComputerName((LPTSTR)temp, &sizeTemp);
2043 cm_ClientStrLwr(temp);
2044 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2049 *pathNamep = cm_ClientStrDup(p);
2054 /* First lookup shareName in root.afs */
2056 smb_findShare_rock_t vrock;
2058 fschar_t ftemp[1024];
2059 clientchar_t * p = shareName;
2062 /* attempt to locate a partial match in root.afs. This is because
2063 when using the ANSI RAP calls, the share name is limited to 13 chars
2064 and hence is truncated. Of course we prefer exact matches. */
2066 thyper.HighPart = 0;
2069 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2070 if (vrock.shareName == NULL)
2073 vrock.matchType = 0;
2075 cm_HoldSCache(cm_data.rootSCachep);
2076 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2077 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2078 cm_ReleaseSCache(cm_data.rootSCachep);
2080 free(vrock.shareName);
2081 vrock.shareName = NULL;
2083 if (vrock.matchType) {
2084 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2085 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2090 /* if we get here, there was no match for the share in root.afs */
2091 /* so try to create \\<netbiosName>\<cellname> */
2096 /* Get the full name for this cell */
2097 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2098 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2099 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2100 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2101 #ifdef AFS_AFSDB_ENV
2102 if (code && cm_dnsEnabled) {
2104 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2110 /* construct the path */
2112 clientchar_t temp[1024];
2114 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2115 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2116 rw ? _C("/.%S/") : _C("/%S/"), temp);
2117 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2127 /* Client-side offline caching policy types */
2128 #define CSC_POLICY_MANUAL 0
2129 #define CSC_POLICY_DOCUMENTS 1
2130 #define CSC_POLICY_PROGRAMS 2
2131 #define CSC_POLICY_DISABLE 3
2133 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2136 clientchar_t policy[1024];
2139 int retval = CSC_POLICY_MANUAL;
2141 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2142 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2145 REG_OPTION_NON_VOLATILE,
2151 len = sizeof(policy);
2152 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2154 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2156 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2158 retval = CSC_POLICY_DOCUMENTS;
2160 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2162 retval = CSC_POLICY_PROGRAMS;
2164 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2166 retval = CSC_POLICY_DISABLE;
2169 RegCloseKey(hkCSCPolicy);
2173 /* find a dir search structure by cookie value, and return it held.
2174 * Must be called with smb_globalLock held.
2176 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2178 smb_dirSearch_t *dsp;
2180 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2181 if (dsp->cookie == cookie) {
2182 if (dsp != smb_firstDirSearchp) {
2183 /* move to head of LRU queue, too, if we're not already there */
2184 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2185 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2186 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2187 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2188 if (!smb_lastDirSearchp)
2189 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2197 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2198 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2199 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2205 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2207 lock_ObtainMutex(&dsp->mx);
2208 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2209 dsp->cookie, dsp, dsp->scp);
2210 dsp->flags |= SMB_DIRSEARCH_DELETE;
2211 if (dsp->scp != NULL) {
2212 lock_ObtainWrite(&dsp->scp->rw);
2213 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2214 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2215 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2216 dsp->scp->bulkStatProgress = hzero;
2218 lock_ReleaseWrite(&dsp->scp->rw);
2220 lock_ReleaseMutex(&dsp->mx);
2223 /* Must be called with the smb_globalLock held */
2224 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2226 cm_scache_t *scp = NULL;
2228 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2229 if (dsp->refCount == 0) {
2230 lock_ObtainMutex(&dsp->mx);
2231 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2232 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2233 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2234 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2235 lock_ReleaseMutex(&dsp->mx);
2236 lock_FinalizeMutex(&dsp->mx);
2238 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2239 dsp->cookie, dsp, scp);
2242 lock_ReleaseMutex(&dsp->mx);
2245 /* do this now to avoid spurious locking hierarchy creation */
2247 cm_ReleaseSCache(scp);
2250 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2252 lock_ObtainWrite(&smb_globalLock);
2253 smb_ReleaseDirSearchNoLock(dsp);
2254 lock_ReleaseWrite(&smb_globalLock);
2257 /* find a dir search structure by cookie value, and return it held */
2258 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2260 smb_dirSearch_t *dsp;
2262 lock_ObtainWrite(&smb_globalLock);
2263 dsp = smb_FindDirSearchNoLock(cookie);
2264 lock_ReleaseWrite(&smb_globalLock);
2268 /* GC some dir search entries, in the address space expected by the specific protocol.
2269 * Must be called with smb_globalLock held; release the lock temporarily.
2271 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2272 void smb_GCDirSearches(int isV3)
2274 smb_dirSearch_t *prevp;
2275 smb_dirSearch_t *dsp;
2276 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2280 victimCount = 0; /* how many have we got so far */
2281 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2282 /* we'll move tp from queue, so
2285 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2286 /* if no one is using this guy, and we're either in the new protocol,
2287 * or we're in the old one and this is a small enough ID to be useful
2288 * to the old protocol, GC this guy.
2290 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2291 /* hold and delete */
2292 lock_ObtainMutex(&dsp->mx);
2293 dsp->flags |= SMB_DIRSEARCH_DELETE;
2294 lock_ReleaseMutex(&dsp->mx);
2295 victimsp[victimCount++] = dsp;
2299 /* don't do more than this */
2300 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2304 /* now release them */
2305 for (i = 0; i < victimCount; i++) {
2306 smb_ReleaseDirSearchNoLock(victimsp[i]);
2310 /* function for allocating a dir search entry. We need these to remember enough context
2311 * since we don't get passed the path from call to call during a directory search.
2313 * Returns a held dir search structure, and bumps the reference count on the vnode,
2314 * since it saves a pointer to the vnode.
2316 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2318 smb_dirSearch_t *dsp;
2324 lock_ObtainWrite(&smb_globalLock);
2327 /* what's the biggest ID allowed in this version of the protocol */
2328 /* TODO: do we really want a non v3 dir search request to wrap
2329 smb_dirSearchCounter? */
2330 maxAllowed = isV3 ? 65535 : 255;
2331 if (smb_dirSearchCounter > maxAllowed)
2332 smb_dirSearchCounter = 1;
2334 start = smb_dirSearchCounter;
2337 /* twice so we have enough tries to find guys we GC after one pass;
2338 * 10 extra is just in case I mis-counted.
2340 if (++counter > 2*maxAllowed+10)
2341 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2343 if (smb_dirSearchCounter > maxAllowed) {
2344 smb_dirSearchCounter = 1;
2346 if (smb_dirSearchCounter == start) {
2348 smb_GCDirSearches(isV3);
2351 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2353 /* don't need to watch for refcount zero and deleted, since
2354 * we haven't dropped the global lock.
2357 ++smb_dirSearchCounter;
2361 dsp = malloc(sizeof(*dsp));
2362 memset(dsp, 0, sizeof(*dsp));
2363 dsp->cookie = smb_dirSearchCounter;
2364 ++smb_dirSearchCounter;
2366 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2367 dsp->lastTime = osi_Time();
2368 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2369 if (!smb_lastDirSearchp)
2370 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2372 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2376 lock_ReleaseWrite(&smb_globalLock);
2380 static smb_packet_t *smb_GetPacket(void)
2384 lock_ObtainWrite(&smb_globalLock);
2385 tbp = smb_packetFreeListp;
2387 smb_packetFreeListp = tbp->nextp;
2388 lock_ReleaseWrite(&smb_globalLock);
2390 tbp = calloc(sizeof(*tbp),1);
2391 tbp->magic = SMB_PACKETMAGIC;
2394 tbp->resumeCode = 0;
2400 tbp->ncb_length = 0;
2403 tbp->stringsp = NULL;
2405 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2410 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2413 tbp = smb_GetPacket();
2414 memcpy(tbp, pkt, sizeof(smb_packet_t));
2415 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2416 tbp->stringsp = NULL;
2418 smb_HoldVC(tbp->vcp);
2422 static NCB *smb_GetNCB(void)
2427 lock_ObtainWrite(&smb_globalLock);
2428 tbp = smb_ncbFreeListp;
2430 smb_ncbFreeListp = tbp->nextp;
2431 lock_ReleaseWrite(&smb_globalLock);
2433 tbp = calloc(sizeof(*tbp),1);
2434 tbp->magic = SMB_NCBMAGIC;
2437 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2439 memset(&tbp->ncb, 0, sizeof(NCB));
2444 static void FreeSMBStrings(smb_packet_t * pkt)
2449 for (s = pkt->stringsp; s; s = ns) {
2453 pkt->stringsp = NULL;
2456 void smb_FreePacket(smb_packet_t *tbp)
2458 smb_vc_t * vcp = NULL;
2459 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2461 lock_ObtainWrite(&smb_globalLock);
2462 tbp->nextp = smb_packetFreeListp;
2463 smb_packetFreeListp = tbp;
2464 tbp->magic = SMB_PACKETMAGIC;
2468 tbp->resumeCode = 0;
2474 tbp->ncb_length = 0;
2476 FreeSMBStrings(tbp);
2477 lock_ReleaseWrite(&smb_globalLock);
2483 static void smb_FreeNCB(NCB *bufferp)
2487 tbp = (smb_ncb_t *) bufferp;
2488 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2490 lock_ObtainWrite(&smb_globalLock);
2491 tbp->nextp = smb_ncbFreeListp;
2492 smb_ncbFreeListp = tbp;
2493 lock_ReleaseWrite(&smb_globalLock);
2496 /* get a ptr to the data part of a packet, and its count */
2497 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2501 unsigned char *afterParmsp;
2503 parmBytes = *smbp->wctp << 1;
2504 afterParmsp = smbp->wctp + parmBytes + 1;
2506 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2507 if (nbytesp) *nbytesp = dataBytes;
2509 /* don't forget to skip the data byte count, since it follows
2510 * the parameters; that's where the "2" comes from below.
2512 return (unsigned char *) (afterParmsp + 2);
2515 /* must set all the returned parameters before playing around with the
2516 * data region, since the data region is located past the end of the
2517 * variable number of parameters.
2519 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2521 unsigned char *afterParmsp;
2523 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2525 *afterParmsp++ = dsize & 0xff;
2526 *afterParmsp = (dsize>>8) & 0xff;
2529 /* return the parm'th parameter in the smbp packet */
2530 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2533 unsigned char *parmDatap;
2535 parmCount = *smbp->wctp;
2537 if (parm >= parmCount) {
2540 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2541 parm, parmCount, smbp->ncb_length);
2542 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2543 parm, parmCount, smbp->ncb_length);
2544 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2545 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2546 osi_panic(s, __FILE__, __LINE__);
2548 parmDatap = smbp->wctp + (2*parm) + 1;
2550 return parmDatap[0] + (parmDatap[1] << 8);
2553 /* return the parm'th parameter in the smbp packet */
2554 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2557 unsigned char *parmDatap;
2559 parmCount = *smbp->wctp;
2561 if (parm >= parmCount) {
2564 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2565 parm, parmCount, smbp->ncb_length);
2566 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2567 parm, parmCount, smbp->ncb_length);
2568 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2569 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2570 osi_panic(s, __FILE__, __LINE__);
2572 parmDatap = smbp->wctp + (2*parm) + 1;
2574 return parmDatap[0];
2577 /* return the parm'th parameter in the smbp packet */
2578 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2581 unsigned char *parmDatap;
2583 parmCount = *smbp->wctp;
2585 if (parm + 1 >= parmCount) {
2588 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2589 parm, parmCount, smbp->ncb_length);
2590 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2591 parm, parmCount, smbp->ncb_length);
2592 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2593 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2594 osi_panic(s, __FILE__, __LINE__);
2596 parmDatap = smbp->wctp + (2*parm) + 1;
2598 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2601 /* return the parm'th parameter in the smbp packet */
2602 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2605 unsigned char *parmDatap;
2607 parmCount = *smbp->wctp;
2609 if (parm * 2 + offset >= parmCount * 2) {
2612 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2613 parm, offset, parmCount, smbp->ncb_length);
2614 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2615 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2616 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2617 parm, offset, parmCount, smbp->ncb_length);
2618 osi_panic(s, __FILE__, __LINE__);
2620 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2622 return parmDatap[0] + (parmDatap[1] << 8);
2625 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2627 unsigned char *parmDatap;
2629 /* make sure we have enough slots */
2630 if (*smbp->wctp <= slot)
2631 *smbp->wctp = slot+1;
2633 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2634 *parmDatap++ = parmValue & 0xff;
2635 *parmDatap = (parmValue>>8) & 0xff;
2638 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2640 unsigned char *parmDatap;
2642 /* make sure we have enough slots */
2643 if (*smbp->wctp <= slot)
2644 *smbp->wctp = slot+2;
2646 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2647 *parmDatap++ = parmValue & 0xff;
2648 *parmDatap++ = (parmValue>>8) & 0xff;
2649 *parmDatap++ = (parmValue>>16) & 0xff;
2650 *parmDatap = (parmValue>>24) & 0xff;
2653 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2655 unsigned char *parmDatap;
2658 /* make sure we have enough slots */
2659 if (*smbp->wctp <= slot)
2660 *smbp->wctp = slot+4;
2662 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2664 *parmDatap++ = *parmValuep++;
2667 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2669 unsigned char *parmDatap;
2671 /* make sure we have enough slots */
2672 if (*smbp->wctp <= slot) {
2673 if (smbp->oddByte) {
2675 *smbp->wctp = slot+1;
2680 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2681 *parmDatap++ = parmValue & 0xff;
2686 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2687 clientchar_t *inPathp)
2689 clientchar_t *lastSlashp;
2691 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2693 *lastComponentp = lastSlashp;
2696 if (inPathp == lastSlashp)
2698 *outPathp++ = *inPathp++;
2707 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2708 char **chainpp, int flags)
2711 afs_uint32 type = *inp++;
2714 * The first byte specifies the type of the input string.
2715 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2719 /* Length Counted */
2720 case 0x1: /* Data Block */
2721 case 0x5: /* Variable Block */
2722 cb = *inp++ << 16 | *inp++;
2725 /* Null-terminated string */
2726 case 0x4: /* ASCII */
2727 case 0x3: /* Pathname */
2728 case 0x2: /* Dialect */
2729 cb = sizeof(pktp->data) - (inp - pktp->data);
2730 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2731 #ifdef DEBUG_UNICODE
2734 cb = sizeof(pktp->data);
2739 return NULL; /* invalid input */
2743 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2744 flags |= SMB_STRF_FORCEASCII;
2747 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2750 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2751 char ** chainpp, int flags)
2756 if (!WANTS_UNICODE(pktp))
2757 flags |= SMB_STRF_FORCEASCII;
2760 cb = sizeof(pktp->data) - (inp - pktp->data);
2761 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2762 #ifdef DEBUG_UNICODE
2765 cb = sizeof(pktp->data);
2767 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2768 flags | SMB_STRF_SRCNULTERM);
2771 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2772 size_t cb, char ** chainpp, int flags)
2775 if (!WANTS_UNICODE(pktp))
2776 flags |= SMB_STRF_FORCEASCII;
2779 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2782 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2783 size_t cch, char ** chainpp, int flags)
2788 if (!WANTS_UNICODE(pktp))
2789 flags |= SMB_STRF_FORCEASCII;
2791 cb = cch * sizeof(wchar_t);
2794 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2798 smb_ParseStringBuf(const unsigned char * bufbase,
2799 cm_space_t ** stringspp,
2800 unsigned char *inp, size_t *pcb_max,
2801 char **chainpp, int flags)
2804 if (!(flags & SMB_STRF_FORCEASCII)) {
2806 cm_space_t * spacep;
2809 if (bufbase && ((inp - bufbase) % 2) != 0) {
2810 inp++; /* unicode strings are always word aligned */
2814 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2816 cch_src = *pcb_max / sizeof(wchar_t);
2820 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2827 spacep = cm_GetSpace();
2828 spacep->nextp = *stringspp;
2829 *stringspp = spacep;
2833 *chainpp = inp + sizeof(wchar_t);
2836 *(spacep->wdata) = 0;
2837 return spacep->wdata;
2840 StringCchCopyNW(spacep->wdata,
2841 lengthof(spacep->wdata),
2842 (const clientchar_t *) inp, cch_src);
2845 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2847 return spacep->wdata;
2851 cm_space_t * spacep;
2854 /* Not using Unicode */
2856 *chainpp = inp + strlen(inp) + 1;
2859 spacep = cm_GetSpace();
2860 spacep->nextp = *stringspp;
2861 *stringspp = spacep;
2863 cchdest = lengthof(spacep->wdata);
2864 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2865 spacep->wdata, cchdest);
2867 return spacep->wdata;
2873 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2875 size_t * plen, int flags)
2881 /* we are only calculating the required size */
2888 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2890 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2891 if (!(flags & SMB_STRF_IGNORENUL))
2892 *plen += sizeof(wchar_t);
2894 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2904 cch_str = cm_ClientStrLen(str);
2905 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2908 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2916 /* if outp != NULL ... */
2918 /* Number of bytes left in the buffer.
2920 If outp lies inside the packet data buffer, we assume that the
2921 buffer is the packet data buffer. Otherwise we assume that the
2922 buffer is sizeof(packet->data).
2925 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2926 align = (int)((outp - pktp->data) % 2);
2927 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2929 align = (int)(((size_t) outp) % 2);
2930 buffersize = (int)sizeof(pktp->data);
2935 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2941 if (*str == _C('\0')) {
2943 if (buffersize < sizeof(wchar_t))
2946 *((wchar_t *) outp) = L'\0';
2947 if (plen && !(flags & SMB_STRF_IGNORENUL))
2948 *plen += sizeof(wchar_t);
2949 return outp + sizeof(wchar_t);
2952 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2954 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2955 osi_LogSaveClientString(smb_logp, str),
2961 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2963 return outp + sizeof(wchar_t) * nchars;
2971 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2974 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2976 return outp + cch_dest;
2980 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2986 tlen = inp[0] + (inp[1]<<8);
2987 inp += 2; /* skip length field */
2990 *chainpp = inp + tlen;
2999 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3003 if (*inp++ != 0x1) return NULL;
3004 tlen = inp[0] + (inp[1]<<8);
3005 inp += 2; /* skip length field */
3008 *chainpp = inp + tlen;
3011 if (lengthp) *lengthp = tlen;
3016 /* format a packet as a response */
3017 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3022 outp = (smb_t *) op;
3024 /* zero the basic structure through the smb_wct field, and zero the data
3025 * size field, assuming that wct stays zero; otherwise, you have to
3026 * explicitly set the data size field, too.
3028 inSmbp = (smb_t *) inp;
3029 memset(outp, 0, sizeof(smb_t)+2);
3035 outp->com = inSmbp->com;
3036 outp->tid = inSmbp->tid;
3037 outp->pid = inSmbp->pid;
3038 outp->uid = inSmbp->uid;
3039 outp->mid = inSmbp->mid;
3040 outp->res[0] = inSmbp->res[0];
3041 outp->res[1] = inSmbp->res[1];
3042 op->inCom = inSmbp->com;
3044 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3045 #ifdef SEND_CANONICAL_PATHNAMES
3046 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3048 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3050 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3051 outp->flg2 |= SMB_FLAGS2_UNICODE;
3054 /* copy fields in generic packet area */
3055 op->wctp = &outp->wct;
3058 /* send a (probably response) packet; vcp tells us to whom to send it.
3059 * we compute the length by looking at wct and bcc fields.
3061 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3071 ncbp = smb_GetNCB();
3075 memset((char *)ncbp, 0, sizeof(NCB));
3077 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3078 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3079 extra += tp[0] + (tp[1]<<8);
3080 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3081 extra += 3; /* wct and length fields */
3083 ncbp->ncb_length = extra; /* bytes to send */
3084 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3085 ncbp->ncb_lana_num = vcp->lana;
3086 ncbp->ncb_command = NCBSEND; /* op means send data */
3087 ncbp->ncb_buffer = (char *) inp;/* packet */
3088 code = Netbios(ncbp);
3091 const char * s = ncb_error_string(code);
3092 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3093 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3095 lock_ObtainMutex(&vcp->mx);
3096 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3097 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3099 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3100 lock_ReleaseMutex(&vcp->mx);
3101 lock_ObtainWrite(&smb_globalLock);
3102 dead_sessions[vcp->session] = TRUE;
3103 lock_ReleaseWrite(&smb_globalLock);
3104 smb_CleanupDeadVC(vcp);
3106 lock_ReleaseMutex(&vcp->mx);
3114 void smb_MapNTError(long code, unsigned long *NTStatusp)
3116 unsigned long NTStatus;
3118 /* map CM_ERROR_* errors to NT 32-bit status codes */
3119 /* NT Status codes are listed in ntstatus.h not winerror.h */
3123 else if (code == CM_ERROR_NOSUCHCELL) {
3124 NTStatus = 0xC000000FL; /* No such file */
3126 else if (code == CM_ERROR_NOSUCHVOLUME) {
3127 NTStatus = 0xC000000FL; /* No such file */
3129 else if (code == CM_ERROR_TIMEDOUT) {
3131 NTStatus = 0xC00000CFL; /* Sharing Paused */
3133 NTStatus = 0x00000102L; /* Timeout */
3136 else if (code == CM_ERROR_RETRY) {
3137 NTStatus = 0xC000022DL; /* Retry */
3139 else if (code == CM_ERROR_NOACCESS) {
3140 NTStatus = 0xC0000022L; /* Access denied */
3142 else if (code == CM_ERROR_READONLY) {
3143 NTStatus = 0xC00000A2L; /* Write protected */
3145 else if (code == CM_ERROR_NOSUCHFILE ||
3146 code == CM_ERROR_BPLUS_NOMATCH) {
3147 NTStatus = 0xC000000FL; /* No such file */
3149 else if (code == CM_ERROR_NOSUCHPATH) {
3150 NTStatus = 0xC000003AL; /* Object path not found */
3152 else if (code == CM_ERROR_TOOBIG) {
3153 NTStatus = 0xC000007BL; /* Invalid image format */
3155 else if (code == CM_ERROR_INVAL) {
3156 NTStatus = 0xC000000DL; /* Invalid parameter */
3158 else if (code == CM_ERROR_BADFD) {
3159 NTStatus = 0xC0000008L; /* Invalid handle */
3161 else if (code == CM_ERROR_BADFDOP) {
3162 NTStatus = 0xC0000022L; /* Access denied */
3164 else if (code == CM_ERROR_EXISTS) {
3165 NTStatus = 0xC0000035L; /* Object name collision */
3167 else if (code == CM_ERROR_NOTEMPTY) {
3168 NTStatus = 0xC0000101L; /* Directory not empty */
3170 else if (code == CM_ERROR_CROSSDEVLINK) {
3171 NTStatus = 0xC00000D4L; /* Not same device */
3173 else if (code == CM_ERROR_NOTDIR) {
3174 NTStatus = 0xC0000103L; /* Not a directory */
3176 else if (code == CM_ERROR_ISDIR) {
3177 NTStatus = 0xC00000BAL; /* File is a directory */
3179 else if (code == CM_ERROR_BADOP) {
3181 /* I have no idea where this comes from */
3182 NTStatus = 0xC09820FFL; /* SMB no support */
3184 NTStatus = 0xC00000BBL; /* Not supported */
3185 #endif /* COMMENT */
3187 else if (code == CM_ERROR_BADSHARENAME) {
3188 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3190 else if (code == CM_ERROR_NOIPC) {
3192 NTStatus = 0xC0000022L; /* Access Denied */
3194 NTStatus = 0xC000013DL; /* Remote Resources */
3197 else if (code == CM_ERROR_CLOCKSKEW) {
3198 NTStatus = 0xC0000133L; /* Time difference at DC */
3200 else if (code == CM_ERROR_BADTID) {
3201 NTStatus = 0xC0982005L; /* SMB bad TID */
3203 else if (code == CM_ERROR_USESTD) {
3204 NTStatus = 0xC09820FBL; /* SMB use standard */
3206 else if (code == CM_ERROR_QUOTA) {
3207 NTStatus = 0xC0000044L; /* Quota exceeded */
3209 else if (code == CM_ERROR_SPACE) {
3210 NTStatus = 0xC000007FL; /* Disk full */
3212 else if (code == CM_ERROR_ATSYS) {
3213 NTStatus = 0xC0000033L; /* Object name invalid */
3215 else if (code == CM_ERROR_BADNTFILENAME) {
3216 NTStatus = 0xC0000033L; /* Object name invalid */
3218 else if (code == CM_ERROR_WOULDBLOCK) {
3219 NTStatus = 0xC00000D8L; /* Can't wait */
3221 else if (code == CM_ERROR_SHARING_VIOLATION) {
3222 NTStatus = 0xC0000043L; /* Sharing violation */
3224 else if (code == CM_ERROR_LOCK_CONFLICT) {
3225 NTStatus = 0xC0000054L; /* Lock conflict */
3227 else if (code == CM_ERROR_PARTIALWRITE) {
3228 NTStatus = 0xC000007FL; /* Disk full */
3230 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3231 NTStatus = 0xC0000023L; /* Buffer too small */
3233 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3234 NTStatus = 0xC0000035L; /* Object name collision */
3236 else if (code == CM_ERROR_BADPASSWORD) {
3237 NTStatus = 0xC000006DL; /* unknown username or bad password */
3239 else if (code == CM_ERROR_BADLOGONTYPE) {
3240 NTStatus = 0xC000015BL; /* logon type not granted */
3242 else if (code == CM_ERROR_GSSCONTINUE) {
3243 NTStatus = 0xC0000016L; /* more processing required */
3245 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3247 NTStatus = 0xC0000280L; /* reparse point not resolved */
3249 NTStatus = 0xC0000022L; /* Access Denied */
3252 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3253 NTStatus = 0xC0000257L; /* Path Not Covered */
3255 else if (code == CM_ERROR_ALLBUSY) {
3256 NTStatus = 0xC000022DL; /* Retry */
3258 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3259 NTStatus = 0xC000003AL; /* Path not found */
3261 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3262 NTStatus = 0xC0000322L; /* No Kerberos key */
3264 else if (code == CM_ERROR_BAD_LEVEL) {
3265 NTStatus = 0xC0000148L; /* Invalid Level */
3267 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3268 NTStatus = 0xC000007EL; /* Range Not Locked */
3270 else if (code == CM_ERROR_NOSUCHDEVICE) {
3271 NTStatus = 0xC000000EL; /* No Such Device */
3273 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3274 NTStatus = 0xC0000055L; /* Lock Not Granted */
3275 } else if (code == ENOMEM) {
3276 NTStatus = 0xC0000017L; /* Out of Memory */
3278 NTStatus = 0xC0982001L; /* SMB non-specific error */
3281 *NTStatusp = NTStatus;
3282 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3285 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3286 unsigned char *classp)
3288 unsigned char class;
3289 unsigned short error;
3291 /* map CM_ERROR_* errors to SMB errors */
3292 if (code == CM_ERROR_NOSUCHCELL) {
3294 error = 3; /* bad path */
3296 else if (code == CM_ERROR_NOSUCHVOLUME) {
3298 error = 3; /* bad path */
3300 else if (code == CM_ERROR_TIMEDOUT) {
3302 error = 81; /* server is paused */
3304 else if (code == CM_ERROR_RETRY) {
3305 class = 2; /* shouldn't happen */
3308 else if (code == CM_ERROR_NOACCESS) {
3310 error = 4; /* bad access */
3312 else if (code == CM_ERROR_READONLY) {
3314 error = 19; /* read only */
3316 else if (code == CM_ERROR_NOSUCHFILE ||
3317 code == CM_ERROR_BPLUS_NOMATCH) {
3319 error = 2; /* ENOENT! */
3321 else if (code == CM_ERROR_NOSUCHPATH) {
3323 error = 3; /* Bad path */
3325 else if (code == CM_ERROR_TOOBIG) {
3327 error = 11; /* bad format */
3329 else if (code == CM_ERROR_INVAL) {
3330 class = 2; /* server non-specific error code */
3333 else if (code == CM_ERROR_BADFD) {
3335 error = 6; /* invalid file handle */
3337 else if (code == CM_ERROR_BADFDOP) {
3338 class = 1; /* invalid op on FD */
3341 else if (code == CM_ERROR_EXISTS) {
3343 error = 80; /* file already exists */
3345 else if (code == CM_ERROR_NOTEMPTY) {
3347 error = 5; /* delete directory not empty */
3349 else if (code == CM_ERROR_CROSSDEVLINK) {
3351 error = 17; /* EXDEV */
3353 else if (code == CM_ERROR_NOTDIR) {
3354 class = 1; /* bad path */
3357 else if (code == CM_ERROR_ISDIR) {
3358 class = 1; /* access denied; DOS doesn't have a good match */
3361 else if (code == CM_ERROR_BADOP) {
3365 else if (code == CM_ERROR_BADSHARENAME) {
3369 else if (code == CM_ERROR_NOIPC) {
3371 error = 4; /* bad access */
3373 else if (code == CM_ERROR_CLOCKSKEW) {
3374 class = 1; /* invalid function */
3377 else if (code == CM_ERROR_BADTID) {
3381 else if (code == CM_ERROR_USESTD) {
3385 else if (code == CM_ERROR_REMOTECONN) {
3389 else if (code == CM_ERROR_QUOTA) {
3390 if (vcp->flags & SMB_VCFLAG_USEV3) {
3392 error = 39; /* disk full */
3396 error = 5; /* access denied */
3399 else if (code == CM_ERROR_SPACE) {
3400 if (vcp->flags & SMB_VCFLAG_USEV3) {
3402 error = 39; /* disk full */
3406 error = 5; /* access denied */
3409 else if (code == CM_ERROR_PARTIALWRITE) {
3411 error = 39; /* disk full */
3413 else if (code == CM_ERROR_ATSYS) {
3415 error = 2; /* ENOENT */
3417 else if (code == CM_ERROR_WOULDBLOCK) {
3419 error = 33; /* lock conflict */
3421 else if (code == CM_ERROR_LOCK_CONFLICT) {
3423 error = 33; /* lock conflict */
3425 else if (code == CM_ERROR_SHARING_VIOLATION) {
3427 error = 33; /* lock conflict */
3429 else if (code == CM_ERROR_NOFILES) {
3431 error = 18; /* no files in search */
3433 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3435 error = 183; /* Samba uses this */
3437 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3438 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3440 error = 2; /* bad password */
3442 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3444 error = 3; /* bad path */
3453 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3456 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3458 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3459 return CM_ERROR_BADOP;
3463 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3465 unsigned short EchoCount, i;
3466 char *data, *outdata;
3469 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3471 for (i=1; i<=EchoCount; i++) {
3472 data = smb_GetSMBData(inp, &dataSize);
3473 smb_SetSMBParm(outp, 0, i);
3474 smb_SetSMBDataLength(outp, dataSize);
3475 outdata = smb_GetSMBData(outp, NULL);
3476 memcpy(outdata, data, dataSize);
3477 smb_SendPacket(vcp, outp);
3483 /* SMB_COM_READ_RAW */
3484 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3487 long count, minCount, finalCount;
3491 smb_t *smbp = (smb_t*) inp;
3493 cm_user_t *userp = NULL;
3496 char *rawBuf = NULL;
3501 fd = smb_GetSMBParm(inp, 0);
3502 count = smb_GetSMBParm(inp, 3);
3503 minCount = smb_GetSMBParm(inp, 4);
3504 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3506 if (*inp->wctp == 10) {
3507 /* we were sent a request with 64-bit file offsets */
3508 #ifdef AFS_LARGEFILES
3509 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3511 if (LargeIntegerLessThanZero(offset)) {
3512 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3516 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3517 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3520 offset.HighPart = 0;
3524 /* we were sent a request with 32-bit file offsets */
3525 offset.HighPart = 0;
3528 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3529 fd, offset.HighPart, offset.LowPart, count);
3531 fidp = smb_FindFID(vcp, fd, 0);
3535 lock_ObtainMutex(&fidp->mx);
3537 lock_ReleaseMutex(&fidp->mx);
3538 smb_ReleaseFID(fidp);
3539 return CM_ERROR_BADFD;
3542 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3543 lock_ReleaseMutex(&fidp->mx);
3544 smb_CloseFID(vcp, fidp, NULL, 0);
3545 code = CM_ERROR_NOSUCHFILE;
3551 LARGE_INTEGER LOffset, LLength;
3554 key = cm_GenerateKey(vcp->vcID, pid, fd);
3556 LOffset.HighPart = offset.HighPart;
3557 LOffset.LowPart = offset.LowPart;
3558 LLength.HighPart = 0;
3559 LLength.LowPart = count;
3561 lock_ObtainWrite(&fidp->scp->rw);
3562 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3563 lock_ReleaseWrite(&fidp->scp->rw);
3566 lock_ReleaseMutex(&fidp->mx);
3570 lock_ObtainMutex(&smb_RawBufLock);
3572 /* Get a raw buf, from head of list */
3573 rawBuf = smb_RawBufs;
3574 smb_RawBufs = *(char **)smb_RawBufs;
3576 lock_ReleaseMutex(&smb_RawBufLock);
3578 lock_ReleaseMutex(&fidp->mx);
3582 if (fidp->flags & SMB_FID_IOCTL)
3584 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3586 /* Give back raw buffer */
3587 lock_ObtainMutex(&smb_RawBufLock);
3588 *((char **) rawBuf) = smb_RawBufs;
3590 smb_RawBufs = rawBuf;
3591 lock_ReleaseMutex(&smb_RawBufLock);
3594 lock_ReleaseMutex(&fidp->mx);
3595 smb_ReleaseFID(fidp);
3598 lock_ReleaseMutex(&fidp->mx);
3600 userp = smb_GetUserFromVCP(vcp, inp);
3602 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3608 cm_ReleaseUser(userp);
3611 smb_ReleaseFID(fidp);
3615 memset((char *)ncbp, 0, sizeof(NCB));
3617 ncbp->ncb_length = (unsigned short) finalCount;
3618 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3619 ncbp->ncb_lana_num = vcp->lana;
3620 ncbp->ncb_command = NCBSEND;
3621 ncbp->ncb_buffer = rawBuf;
3623 code = Netbios(ncbp);
3625 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3628 /* Give back raw buffer */
3629 lock_ObtainMutex(&smb_RawBufLock);
3630 *((char **) rawBuf) = smb_RawBufs;
3632 smb_RawBufs = rawBuf;
3633 lock_ReleaseMutex(&smb_RawBufLock);
3639 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3641 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3646 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3648 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3653 /* SMB_COM_NEGOTIATE */
3654 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3661 int VistaProtoIndex;
3662 int protoIndex; /* index we're using */
3667 char protocol_array[10][1024]; /* protocol signature of the client */
3668 int caps; /* capabilities */
3671 TIME_ZONE_INFORMATION tzi;
3673 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3676 namep = smb_GetSMBData(inp, &dbytes);
3679 coreProtoIndex = -1; /* not found */
3682 VistaProtoIndex = -1;
3683 while(namex < dbytes) {
3684 osi_Log1(smb_logp, "Protocol %s",
3685 osi_LogSaveString(smb_logp, namep+1));
3686 strcpy(protocol_array[tcounter], namep+1);
3688 /* namep points at the first protocol, or really, a 0x02
3689 * byte preceding the null-terminated ASCII name.
3691 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3692 coreProtoIndex = tcounter;
3694 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3695 v3ProtoIndex = tcounter;
3697 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3698 NTProtoIndex = tcounter;
3700 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3701 VistaProtoIndex = tcounter;
3704 /* compute size of protocol entry */
3705 entryLength = (int)strlen(namep+1);
3706 entryLength += 2; /* 0x02 bytes and null termination */
3708 /* advance over this protocol entry */
3709 namex += entryLength;
3710 namep += entryLength;
3711 tcounter++; /* which proto entry we're looking at */
3714 lock_ObtainMutex(&vcp->mx);
3716 if (VistaProtoIndex != -1) {
3717 protoIndex = VistaProtoIndex;
3718 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3721 if (NTProtoIndex != -1) {
3722 protoIndex = NTProtoIndex;
3723 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3725 else if (v3ProtoIndex != -1) {
3726 protoIndex = v3ProtoIndex;
3727 vcp->flags |= SMB_VCFLAG_USEV3;
3729 else if (coreProtoIndex != -1) {
3730 protoIndex = coreProtoIndex;
3731 vcp->flags |= SMB_VCFLAG_USECORE;
3733 else protoIndex = -1;
3734 lock_ReleaseMutex(&vcp->mx);
3736 if (protoIndex == -1)
3737 return CM_ERROR_INVAL;
3738 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3739 smb_SetSMBParm(outp, 0, protoIndex);
3740 if (smb_authType != SMB_AUTH_NONE) {
3741 smb_SetSMBParmByte(outp, 1,
3742 NEGOTIATE_SECURITY_USER_LEVEL |
3743 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3745 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3747 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3748 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3749 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3750 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3751 /* The session key is not a well documented field however most clients
3752 * will echo back the session key to the server. Currently we are using
3753 * the same value for all sessions. We should generate a random value
3754 * and store it into the vcp
3756 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3757 smb_SetSMBParm(outp, 8, 1);
3759 * Tried changing the capabilities to support for W2K - defect 117695
3760 * Maybe something else needs to be changed here?
3764 smb_SetSMBParmLong(outp, 9, 0x43fd);
3766 smb_SetSMBParmLong(outp, 9, 0x251);
3769 * 32-bit error codes *
3775 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3777 NTNEGOTIATE_CAPABILITY_DFS |
3779 #ifdef AFS_LARGEFILES
3780 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3782 NTNEGOTIATE_CAPABILITY_NTFIND |
3783 NTNEGOTIATE_CAPABILITY_RAWMODE |
3784 NTNEGOTIATE_CAPABILITY_NTSMB;
3786 if ( smb_authType == SMB_AUTH_EXTENDED )
3787 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3790 if ( smb_UseUnicode ) {
3791 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3795 smb_SetSMBParmLong(outp, 9, caps);
3797 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3798 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3799 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3801 GetTimeZoneInformation(&tzi);
3802 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3804 if (smb_authType == SMB_AUTH_NTLM) {
3805 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3806 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3807 /* paste in encryption key */
3808 datap = smb_GetSMBData(outp, NULL);
3809 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3810 /* and the faux domain name */
3811 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3812 datap + MSV1_0_CHALLENGE_LENGTH,
3813 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3814 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3818 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3820 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3822 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3824 datap = smb_GetSMBData(outp, NULL);
3825 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3828 datap += sizeof(smb_ServerGUID);
3829 memcpy(datap, secBlob, secBlobLength);
3833 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3834 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3837 else if (v3ProtoIndex != -1) {
3838 smb_SetSMBParm(outp, 0, protoIndex);
3840 /* NOTE: Extended authentication cannot be negotiated with v3
3841 * therefore we fail over to NTLM
3843 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3844 smb_SetSMBParm(outp, 1,
3845 NEGOTIATE_SECURITY_USER_LEVEL |
3846 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3848 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3850 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3851 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3852 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3853 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3854 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3855 smb_SetSMBParm(outp, 7, 1);
3857 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3858 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3859 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3861 GetTimeZoneInformation(&tzi);
3862 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3864 /* NOTE: Extended authentication cannot be negotiated with v3
3865 * therefore we fail over to NTLM
3867 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3868 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3869 smb_SetSMBParm(outp, 12, 0); /* resvd */
3870 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3871 datap = smb_GetSMBData(outp, NULL);
3872 /* paste in a new encryption key */
3873 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3874 /* and the faux domain name */
3875 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3876 datap + MSV1_0_CHALLENGE_LENGTH,
3877 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3879 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3880 smb_SetSMBParm(outp, 12, 0); /* resvd */
3881 smb_SetSMBDataLength(outp, 0);
3884 else if (coreProtoIndex != -1) { /* not really supported anymore */
3885 smb_SetSMBParm(outp, 0, protoIndex);
3886 smb_SetSMBDataLength(outp, 0);
3891 void smb_CheckVCs(void)
3893 smb_vc_t * vcp, *nextp;
3894 smb_packet_t * outp = smb_GetPacket();
3897 lock_ObtainWrite(&smb_rctLock);
3898 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3900 if (vcp->magic != SMB_VC_MAGIC)
3901 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3902 __FILE__, __LINE__);
3904 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3906 smb_HoldVCNoLock(vcp);
3909 * obtain a reference to 'nextp' now because we drop the
3910 * smb_rctLock later and the list contents could change
3911 * or 'vcp' could be destroyed when released.
3915 smb_HoldVCNoLock(nextp);
3917 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3918 smb_ReleaseVCNoLock(vcp);
3922 smb_FormatResponsePacket(vcp, NULL, outp);
3923 smbp = (smb_t *)outp;
3924 outp->inCom = smbp->com = 0x2b /* Echo */;
3932 smb_SetSMBParm(outp, 0, 0);
3933 smb_SetSMBDataLength(outp, 0);
3934 lock_ReleaseWrite(&smb_rctLock);
3936 smb_SendPacket(vcp, outp);
3938 lock_ObtainWrite(&smb_rctLock);
3939 smb_ReleaseVCNoLock(vcp);
3941 lock_ReleaseWrite(&smb_rctLock);
3942 smb_FreePacket(outp);
3945 void smb_Daemon(void *parmp)
3947 afs_uint32 count = 0;
3948 smb_username_t **unpp;
3951 while(smbShutdownFlag == 0) {
3955 if (smbShutdownFlag == 1)
3958 if ((count % 72) == 0) { /* every five minutes */
3960 time_t old_localZero = smb_localZero;
3962 /* Initialize smb_localZero */
3963 myTime.tm_isdst = -1; /* compute whether on DST or not */
3964 myTime.tm_year = 70;
3970 smb_localZero = mktime(&myTime);
3972 #ifndef USE_NUMERIC_TIME_CONV
3973 smb_CalculateNowTZ();
3974 #endif /* USE_NUMERIC_TIME_CONV */
3975 #ifdef AFS_FREELANCE
3976 if ( smb_localZero != old_localZero )
3977 cm_noteLocalMountPointChange();
3983 /* GC smb_username_t objects that will no longer be used */
3985 lock_ObtainWrite(&smb_rctLock);
3986 for ( unpp=&usernamesp; *unpp; ) {
3988 smb_username_t *unp;
3990 lock_ObtainMutex(&(*unpp)->mx);
3991 if ( (*unpp)->refCount > 0 ||
3992 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3993 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3995 else if (!smb_LogoffTokenTransfer ||
3996 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3998 lock_ReleaseMutex(&(*unpp)->mx);
4006 lock_FinalizeMutex(&unp->mx);
4012 cm_ReleaseUser(userp);
4014 unpp = &(*unpp)->nextp;
4017 lock_ReleaseWrite(&smb_rctLock);
4019 /* XXX GC dir search entries */
4023 void smb_WaitingLocksDaemon()
4025 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4026 smb_waitingLock_t *wl, *wlNext;
4029 smb_packet_t *inp, *outp;
4033 while (smbShutdownFlag == 0) {
4034 lock_ObtainWrite(&smb_globalLock);
4035 nwlRequest = smb_allWaitingLocks;
4036 if (nwlRequest == NULL) {
4037 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4042 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4049 lock_ObtainWrite(&smb_globalLock);
4051 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4053 wlRequest = nwlRequest;
4054 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4055 lock_ReleaseWrite(&smb_globalLock);
4059 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4060 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4063 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4064 code = CM_ERROR_LOCK_NOT_GRANTED;
4068 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4070 /* wl->state is either _DONE or _WAITING. _ERROR
4071 would no longer be on the queue. */
4072 code = cm_RetryLock( wl->lockp,
4073 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4076 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4077 } else if (code != CM_ERROR_WOULDBLOCK) {
4078 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4083 if (code == CM_ERROR_WOULDBLOCK) {
4086 if (wlRequest->msTimeout != 0xffffffff
4087 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4099 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4102 scp = wlRequest->scp;
4103 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4107 lock_ObtainWrite(&scp->rw);
4109 for (wl = wlRequest->locks; wl; wl = wlNext) {
4110 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4112 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4113 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4114 wl->LLength, wl->key, 0, NULL, &req);
4116 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4121 lock_ReleaseWrite(&scp->rw);
4125 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4128 for (wl = wlRequest->locks; wl; wl = wlNext) {
4129 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4130 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4135 vcp = wlRequest->vcp;
4136 inp = wlRequest->inp;
4137 outp = wlRequest->outp;
4138 ncbp = smb_GetNCB();
4139 ncbp->ncb_length = inp->ncb_length;
4140 inp->spacep = cm_GetSpace();
4142 /* Remove waitingLock from list */
4143 lock_ObtainWrite(&smb_globalLock);
4144 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4146 lock_ReleaseWrite(&smb_globalLock);
4148 /* Resume packet processing */
4150 smb_SetSMBDataLength(outp, 0);
4151 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4152 outp->resumeCode = code;
4154 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4157 cm_FreeSpace(inp->spacep);
4158 smb_FreePacket(inp);
4159 smb_FreePacket(outp);
4161 cm_ReleaseSCache(wlRequest->scp);
4164 } while (nwlRequest && smbShutdownFlag == 0);
4169 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4171 osi_Log0(smb_logp, "SMB receive get disk attributes");
4173 smb_SetSMBParm(outp, 0, 32000);
4174 smb_SetSMBParm(outp, 1, 64);
4175 smb_SetSMBParm(outp, 2, 1024);
4176 smb_SetSMBParm(outp, 3, 30000);
4177 smb_SetSMBParm(outp, 4, 0);
4178 smb_SetSMBDataLength(outp, 0);
4182 /* SMB_COM_TREE_CONNECT */
4183 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4187 unsigned short newTid;
4188 clientchar_t shareName[AFSPATHMAX];
4189 clientchar_t *sharePath;
4192 clientchar_t *pathp;
4195 osi_Log0(smb_logp, "SMB receive tree connect");
4197 /* parse input parameters */
4200 tbp = smb_GetSMBData(inp, NULL);
4201 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4203 return CM_ERROR_BADSMB;
4205 tp = cm_ClientStrRChr(pathp, '\\');
4207 return CM_ERROR_BADSMB;
4208 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4210 lock_ObtainMutex(&vcp->mx);
4211 newTid = vcp->tidCounter++;
4212 lock_ReleaseMutex(&vcp->mx);
4214 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4215 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4217 return CM_ERROR_BADSMB;
4218 userp = smb_GetUserFromUID(uidp);
4219 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4220 smb_ReleaseUID(uidp);
4222 smb_ReleaseTID(tidp, FALSE);
4223 return CM_ERROR_BADSHARENAME;
4225 lock_ObtainMutex(&tidp->mx);
4226 tidp->userp = userp;
4227 tidp->pathname = sharePath;
4228 lock_ReleaseMutex(&tidp->mx);
4229 smb_ReleaseTID(tidp, FALSE);
4231 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4232 smb_SetSMBParm(rsp, 1, newTid);
4233 smb_SetSMBDataLength(rsp, 0);
4235 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4239 /* set maskp to the mask part of the incoming path.
4240 * Mask is 11 bytes long (8.3 with the dot elided).
4241 * Returns true if succeeds with a valid name, otherwise it does
4242 * its best, but returns false.
4244 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4252 /* starts off valid */
4255 /* mask starts out all blanks */
4256 memset(maskp, ' ', 11);
4259 /* find last backslash, or use whole thing if there is none */
4260 tp = cm_ClientStrRChr(pathp, '\\');
4264 tp++; /* skip slash */
4268 /* names starting with a dot are illegal */
4276 if (tc == '.' || tc == '"')
4284 /* if we get here, tp point after the dot */
4285 up = maskp+8; /* ext goes here */
4292 if (tc == '.' || tc == '"')
4295 /* copy extension if not too long */
4305 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4307 clientchar_t umask[11];
4315 /* XXX redo this, calling cm_MatchMask with a converted mask */
4317 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4321 /* otherwise, we have a valid 8.3 name; see if we have a match,
4322 * treating '?' as a wildcard in maskp (but not in the file name).
4324 tp1 = umask; /* real name, in mask format */
4325 tp2 = maskp; /* mask, in mask format */
4326 for(i=0; i<11; i++) {
4327 tc1 = *tp1++; /* clientchar_t from real name */
4328 tc2 = *tp2++; /* clientchar_t from mask */
4329 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4330 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4333 if (tc2 == '?' && tc1 != ' ')
4340 /* we got a match */
4344 clientchar_t *smb_FindMask(clientchar_t *pathp)
4348 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4351 return tp+1; /* skip the slash */
4353 return pathp; /* no slash, return the entire path */
4356 /* SMB_COM_SEARCH for a volume label
4358 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4359 dispatch function.) */
4360 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4362 clientchar_t *pathp;
4364 clientchar_t mask[12];
4365 unsigned char *statBlockp;
4366 unsigned char initStatBlock[21];
4369 osi_Log0(smb_logp, "SMB receive search volume");
4371 /* pull pathname and stat block out of request */
4372 tp = smb_GetSMBData(inp, NULL);
4373 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4374 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4376 return CM_ERROR_BADSMB;
4377 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4378 osi_assertx(statBlockp != NULL, "null statBlock");
4380 statBlockp = initStatBlock;
4384 /* for returning to caller */
4385 smb_Get8Dot3MaskFromPath(mask, pathp);
4387 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4388 tp = smb_GetSMBData(outp, NULL);
4390 *tp++ = 43; /* bytes in a dir entry */
4391 *tp++ = 0; /* high byte in counter */
4393 /* now marshall the dir entry, starting with the search status */
4394 *tp++ = statBlockp[0]; /* Reserved */
4395 memcpy(tp, mask, 11); tp += 11; /* FileName */
4397 /* now pass back server use info, with 1st byte non-zero */
4399 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4401 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4403 *tp++ = 0x8; /* attribute: volume */