2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
240 case 0x03: s = "NRC_ILLCMD illegal command"; break;
241 case 0x05: s = "NRC_CMDTMO command timed out"; break;
242 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
243 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
244 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
245 case 0x09: s = "NRC_NORES no resource available"; break;
246 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
247 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
248 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
249 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
250 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
251 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
252 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
253 case 0x13: s = "NRC_ILLNN illegal name number"; break;
254 case 0x14: s = "NRC_NOCALL no callname"; break;
255 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
256 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
257 case 0x17: s = "NRC_NAMERR name deleted"; break;
258 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
259 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
260 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
261 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
263 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
264 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
265 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
266 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
267 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
268 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
269 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
270 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
271 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
272 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
273 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
274 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
275 case 0x40: s = "NRC_SYSTEM system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 #ifdef DEBUG_SMB_REFCOUNT
823 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
825 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
830 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
831 lock_ObtainWrite(&smb_rctLock);
832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
833 if (vcp->magic != SMB_VC_MAGIC)
834 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
837 if (lsn == vcp->lsn && lana == vcp->lana &&
838 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
839 smb_HoldVCNoLock(vcp);
843 if (!vcp && (flags & SMB_FLAG_CREATE)) {
844 vcp = malloc(sizeof(*vcp));
845 memset(vcp, 0, sizeof(*vcp));
846 vcp->vcID = ++numVCs;
847 vcp->magic = SMB_VC_MAGIC;
848 vcp->refCount = 2; /* smb_allVCsp and caller */
851 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
852 vcp->nextp = smb_allVCsp;
854 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
859 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
860 /* We must obtain a challenge for extended auth
861 * in case the client negotiates smb v3
863 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
864 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
865 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
866 ULONG lsaRespSize = 0;
868 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
870 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
877 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
878 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
879 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
880 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
881 nts, ntsEx, lsaRespSize);
883 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
885 if (ntsEx == STATUS_SUCCESS) {
886 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
889 * This will cause the subsequent authentication to fail but
890 * that is better than us dereferencing a NULL pointer and
893 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 LsaFreeReturnBuffer(lsaResp);
899 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
901 if (numVCs >= CM_SESSION_RESERVED) {
903 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
906 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
913 lock_ReleaseWrite(&smb_globalLock);
917 int smb_IsStarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 #ifdef DEBUG_SMB_REFCOUNT
931 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
932 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
934 void smb_ReleaseVCInternal(smb_vc_t *vcp)
940 lock_AssertWrite(&smb_rctLock);
943 if (vcp->refCount == 0) {
944 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
945 #ifdef DEBUG_SMB_REFCOUNT
946 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
947 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
949 /* remove VCP from smb_deadVCsp */
950 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
956 lock_FinalizeMutex(&vcp->mx);
957 memset(vcp,0,sizeof(smb_vc_t));
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
963 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
967 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
968 avcp?"":"not ",vcp, vcp->refCount);
970 /* This is a wrong. However, I suspect that there is an undercount
971 * and I don't want to release 1.4.1 in a state that will allow
972 * smb_vc_t objects to be deallocated while still in the
973 * smb_allVCsp list. The list is supposed to keep a reference
974 * to the smb_vc_t. Put it back.
978 #ifdef DEBUG_SMB_REFCOUNT
979 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
980 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
984 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
985 /* The reference count is non-zero but the VC is dead.
986 * This implies that some FIDs, TIDs, etc on the VC have yet to
987 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
988 * add a reference that will be dropped by
989 * smb_CleanupDeadVC() and try to cleanup the VC again.
990 * Eventually the refCount will drop to zero when all of the
991 * active threads working with the VC end their task.
993 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
994 vcp->refCount++; /* put the refCount back */
995 lock_ReleaseWrite(&smb_rctLock);
996 smb_CleanupDeadVC(vcp);
997 #ifdef DEBUG_SMB_REFCOUNT
998 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
999 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1001 lock_ObtainWrite(&smb_rctLock);
1004 #ifdef DEBUG_SMB_REFCOUNT
1005 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1006 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1011 #ifdef DEBUG_SMB_REFCOUNT
1012 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1014 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1017 lock_AssertWrite(&smb_rctLock);
1018 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1019 smb_ReleaseVCInternal(vcp);
1022 #ifdef DEBUG_SMB_REFCOUNT
1023 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1025 void smb_ReleaseVC(smb_vc_t *vcp)
1028 lock_ObtainWrite(&smb_rctLock);
1029 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1030 smb_ReleaseVCInternal(vcp);
1031 lock_ReleaseWrite(&smb_rctLock);
1034 #ifdef DEBUG_SMB_REFCOUNT
1035 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1037 void smb_HoldVCNoLock(smb_vc_t *vcp)
1040 lock_AssertWrite(&smb_rctLock);
1042 #ifdef DEBUG_SMB_REFCOUNT
1043 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1044 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1046 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1050 #ifdef DEBUG_SMB_REFCOUNT
1051 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1053 void smb_HoldVC(smb_vc_t *vcp)
1056 lock_ObtainWrite(&smb_rctLock);
1058 #ifdef DEBUG_SMB_REFCOUNT
1059 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1060 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1062 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1064 lock_ReleaseWrite(&smb_rctLock);
1067 void smb_CleanupDeadVC(smb_vc_t *vcp)
1069 smb_fid_t *fidpIter;
1070 smb_fid_t *fidpNext;
1072 smb_tid_t *tidpIter;
1073 smb_tid_t *tidpNext;
1075 smb_user_t *uidpIter;
1076 smb_user_t *uidpNext;
1078 afs_uint32 refCount = 0;
1080 lock_ObtainMutex(&vcp->mx);
1081 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1082 lock_ReleaseMutex(&vcp->mx);
1083 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1086 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1087 lock_ReleaseMutex(&vcp->mx);
1088 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1090 lock_ObtainWrite(&smb_rctLock);
1091 /* remove VCP from smb_allVCsp */
1092 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1093 if ((*vcpp)->magic != SMB_VC_MAGIC)
1094 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1095 __FILE__, __LINE__);
1098 vcp->nextp = smb_deadVCsp;
1100 /* Hold onto the reference until we are done with this function */
1105 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1106 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1108 if (fidpIter->deleteOk)
1111 fid = fidpIter->fid;
1112 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1114 smb_HoldFIDNoLock(fidpIter);
1115 lock_ReleaseWrite(&smb_rctLock);
1117 smb_CloseFID(vcp, fidpIter, NULL, 0);
1118 smb_ReleaseFID(fidpIter);
1120 lock_ObtainWrite(&smb_rctLock);
1121 fidpNext = vcp->fidsp;
1124 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1125 tidpNext = tidpIter->nextp;
1126 if (tidpIter->deleteOk)
1128 tidpIter->deleteOk = 1;
1130 tid = tidpIter->tid;
1131 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1133 smb_HoldTIDNoLock(tidpIter);
1134 smb_ReleaseTID(tidpIter, TRUE);
1135 tidpNext = vcp->tidsp;
1138 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1139 uidpNext = uidpIter->nextp;
1140 if (uidpIter->deleteOk)
1142 uidpIter->deleteOk = 1;
1144 /* do not add an additional reference count for the smb_user_t
1145 * as the smb_vc_t already is holding a reference */
1146 lock_ReleaseWrite(&smb_rctLock);
1148 smb_ReleaseUID(uidpIter);
1150 lock_ObtainWrite(&smb_rctLock);
1151 uidpNext = vcp->usersp;
1154 /* The vcp is now on the deadVCsp list. We intentionally drop the
1155 * reference so that the refcount can reach 0 and we can delete it
1157 * If the refCount == 1 going into the ReleaseVCNoLock call
1158 * the object will be freed and it won't be safe to clear
1161 refCount = vcp->refCount;
1162 smb_ReleaseVCNoLock(vcp);
1164 lock_ObtainMutex(&vcp->mx);
1165 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1166 lock_ReleaseMutex(&vcp->mx);
1169 lock_ReleaseWrite(&smb_rctLock);
1170 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1173 #ifdef DEBUG_SMB_REFCOUNT
1174 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1176 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1181 lock_ObtainWrite(&smb_rctLock);
1183 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1184 if (tidp->refCount == 0 && tidp->deleteOk) {
1186 smb_ReleaseTID(tidp, TRUE);
1190 if (tid == tidp->tid) {
1195 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1196 tidp = malloc(sizeof(*tidp));
1197 memset(tidp, 0, sizeof(*tidp));
1198 tidp->nextp = vcp->tidsp;
1201 smb_HoldVCNoLock(vcp);
1203 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1206 #ifdef DEBUG_SMB_REFCOUNT
1208 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1209 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1212 lock_ReleaseWrite(&smb_rctLock);
1216 #ifdef DEBUG_SMB_REFCOUNT
1217 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1219 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1222 lock_AssertWrite(&smb_rctLock);
1224 #ifdef DEBUG_SMB_REFCOUNT
1225 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1226 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1230 #ifdef DEBUG_SMB_REFCOUNT
1231 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1233 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1238 cm_user_t *userp = NULL;
1239 smb_vc_t *vcp = NULL;
1242 lock_ObtainWrite(&smb_rctLock);
1244 lock_AssertWrite(&smb_rctLock);
1246 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1247 #ifdef DEBUG_SMB_REFCOUNT
1248 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1249 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1251 if (tidp->refCount == 0) {
1252 if (tidp->deleteOk) {
1253 ltpp = &tidp->vcp->tidsp;
1254 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1258 osi_assertx(tp != NULL, "null smb_tid_t");
1260 lock_FinalizeMutex(&tidp->mx);
1261 userp = tidp->userp; /* remember to drop ref later */
1269 lock_ReleaseWrite(&smb_rctLock);
1271 cm_ReleaseUser(userp);
1273 smb_ReleaseVCNoLock(vcp);
1276 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1278 smb_user_t *uidp = NULL;
1280 lock_ObtainWrite(&smb_rctLock);
1281 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1282 if (uid == uidp->userID) {
1284 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1286 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1290 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1291 uidp = malloc(sizeof(*uidp));
1292 memset(uidp, 0, sizeof(*uidp));
1293 uidp->nextp = vcp->usersp;
1294 uidp->refCount = 2; /* one for the vcp and one for the caller */
1296 smb_HoldVCNoLock(vcp);
1298 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1300 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1302 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1304 lock_ReleaseWrite(&smb_rctLock);
1308 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1311 smb_username_t *unp= NULL;
1313 lock_ObtainWrite(&smb_rctLock);
1314 for(unp = usernamesp; unp; unp = unp->nextp) {
1315 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1316 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1321 if (!unp && (flags & SMB_FLAG_CREATE)) {
1322 unp = malloc(sizeof(*unp));
1323 memset(unp, 0, sizeof(*unp));
1325 unp->nextp = usernamesp;
1326 unp->name = cm_ClientStrDup(usern);
1327 unp->machine = cm_ClientStrDup(machine);
1329 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1330 if (flags & SMB_FLAG_AFSLOGON)
1331 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1334 lock_ReleaseWrite(&smb_rctLock);
1338 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1340 smb_user_t *uidp= NULL;
1342 lock_ObtainWrite(&smb_rctLock);
1343 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1346 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1348 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1349 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1354 lock_ReleaseWrite(&smb_rctLock);
1358 void smb_ReleaseUsername(smb_username_t *unp)
1361 smb_username_t **lupp;
1362 cm_user_t *userp = NULL;
1363 time_t now = osi_Time();
1365 lock_ObtainWrite(&smb_rctLock);
1366 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1367 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1368 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1370 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1374 osi_assertx(up != NULL, "null smb_username_t");
1376 up->nextp = NULL; /* do not remove this */
1377 lock_FinalizeMutex(&unp->mx);
1383 lock_ReleaseWrite(&smb_rctLock);
1385 cm_ReleaseUser(userp);
1388 void smb_HoldUIDNoLock(smb_user_t *uidp)
1390 lock_AssertWrite(&smb_rctLock);
1394 void smb_ReleaseUID(smb_user_t *uidp)
1398 smb_username_t *unp = NULL;
1400 lock_ObtainWrite(&smb_rctLock);
1401 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1402 if (uidp->refCount == 0) {
1403 lupp = &uidp->vcp->usersp;
1404 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1408 osi_assertx(up != NULL, "null smb_user_t");
1410 lock_FinalizeMutex(&uidp->mx);
1412 smb_ReleaseVCNoLock(uidp->vcp);
1416 lock_ReleaseWrite(&smb_rctLock);
1420 cm_ReleaseUserVCRef(unp->userp);
1421 smb_ReleaseUsername(unp);
1425 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1427 cm_user_t *up = NULL;
1432 lock_ObtainMutex(&uidp->mx);
1434 up = uidp->unp->userp;
1437 lock_ReleaseMutex(&uidp->mx);
1443 /* retrieve a held reference to a user structure corresponding to an incoming
1445 * corresponding release function is cm_ReleaseUser.
1447 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1450 cm_user_t *up = NULL;
1453 smbp = (smb_t *) inp;
1454 uidp = smb_FindUID(vcp, smbp->uid, 0);
1458 up = smb_GetUserFromUID(uidp);
1460 smb_ReleaseUID(uidp);
1465 * Return a pointer to a pathname extracted from a TID structure. The
1466 * TID structure is not held; assume it won't go away.
1468 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1473 tidp = smb_FindTID(vcp, tid, 0);
1477 if (tidp->flags & SMB_TIDFLAG_IPC) {
1478 code = CM_ERROR_TIDIPC;
1479 /* tidp->pathname would be NULL, but that's fine */
1481 *treepath = tidp->pathname;
1482 smb_ReleaseTID(tidp, FALSE);
1487 /* check to see if we have a chained fid, that is, a fid that comes from an
1488 * OpenAndX message that ran earlier in this packet. In this case, the fid
1489 * field in a read, for example, request, isn't set, since the value is
1490 * supposed to be inherited from the openAndX call.
1492 int smb_ChainFID(int fid, smb_packet_t *inp)
1494 if (inp->fid == 0 || inp->inCount == 0)
1500 /* are we a priv'd user? What does this mean on NT? */
1501 int smb_SUser(cm_user_t *userp)
1506 /* find a file ID. If we pass in 0 we select an unused File ID.
1507 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1508 * smb_fid_t data structure if desired File ID cannot be found.
1510 #ifdef DEBUG_SMB_REFCOUNT
1511 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1513 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1519 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1522 lock_ObtainWrite(&smb_rctLock);
1523 /* figure out if we need to allocate a new file ID */
1526 fid = vcp->fidCounter;
1530 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1531 if (fidp->refCount == 0 && fidp->deleteOk) {
1533 lock_ReleaseWrite(&smb_rctLock);
1534 smb_ReleaseFID(fidp);
1535 lock_ObtainWrite(&smb_rctLock);
1538 if (fid == fidp->fid) {
1541 if (fid == 0xFFFF) {
1543 "New FID number wraps on vcp 0x%x", vcp);
1553 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1554 char eventName[MAX_PATH];
1556 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1557 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1558 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1559 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1560 thrd_CloseHandle(event);
1562 if (fid == 0xFFFF) {
1563 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1569 fidp = malloc(sizeof(*fidp));
1570 memset(fidp, 0, sizeof(*fidp));
1571 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1574 smb_HoldVCNoLock(vcp);
1575 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1577 fidp->curr_chunk = fidp->prev_chunk = -2;
1578 fidp->raw_write_event = event;
1580 vcp->fidCounter = fid+1;
1581 if (vcp->fidCounter == 0xFFFF) {
1582 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1584 vcp->fidCounter = 1;
1589 #ifdef DEBUG_SMB_REFCOUNT
1591 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 lock_ReleaseWrite(&smb_rctLock);
1599 #ifdef DEBUG_SMB_REFCOUNT
1600 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1602 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1605 smb_fid_t *fidp = NULL;
1611 lock_ObtainWrite(&smb_rctLock);
1612 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1613 if (scp == fidp->scp) {
1618 #ifdef DEBUG_SMB_REFCOUNT
1620 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1621 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1624 lock_ReleaseWrite(&smb_rctLock);
1628 #ifdef DEBUG_SMB_REFCOUNT
1629 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1631 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1634 lock_AssertWrite(&smb_rctLock);
1636 #ifdef DEBUG_SMB_REFCOUNT
1637 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1638 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1643 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1644 /* the sm_fid_t->mx and smb_rctLock must not be held */
1645 #ifdef DEBUG_SMB_REFCOUNT
1646 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1648 void smb_ReleaseFID(smb_fid_t *fidp)
1651 cm_scache_t *scp = NULL;
1652 cm_user_t *userp = NULL;
1653 smb_vc_t *vcp = NULL;
1654 smb_ioctl_t *ioctlp;
1656 lock_ObtainMutex(&fidp->mx);
1657 lock_ObtainWrite(&smb_rctLock);
1658 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1659 #ifdef DEBUG_SMB_REFCOUNT
1660 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1661 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1663 if (fidp->refCount == 0) {
1664 if (fidp->deleteOk) {
1667 scp = fidp->scp; /* release after lock is released */
1669 lock_ObtainWrite(&scp->rw);
1670 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1671 lock_ReleaseWrite(&scp->rw);
1672 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1675 userp = fidp->userp;
1679 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1680 thrd_CloseHandle(fidp->raw_write_event);
1682 /* and see if there is ioctl stuff to free */
1683 ioctlp = fidp->ioctlp;
1686 cm_FreeSpace(ioctlp->prefix);
1687 if (ioctlp->ioctl.inAllocp)
1688 free(ioctlp->ioctl.inAllocp);
1689 if (ioctlp->ioctl.outAllocp)
1690 free(ioctlp->ioctl.outAllocp);
1693 lock_ReleaseMutex(&fidp->mx);
1694 lock_FinalizeMutex(&fidp->mx);
1699 smb_ReleaseVCNoLock(vcp);
1703 lock_ReleaseMutex(&fidp->mx);
1705 lock_ReleaseWrite(&smb_rctLock);
1707 /* now release the scache structure */
1709 cm_ReleaseSCache(scp);
1712 cm_ReleaseUser(userp);
1716 * Case-insensitive search for one string in another;
1717 * used to find variable names in submount pathnames.
1719 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1721 clientchar_t *cursor;
1723 for (cursor = str1; *cursor; cursor++)
1724 if (cm_ClientStrCmpI(cursor, str2) == 0)
1731 * Substitute a variable value for its name in a submount pathname. Variable
1732 * name has been identified by smb_stristr() and is in substr. Variable name
1733 * length (plus one) is in substr_size. Variable value is in newstr.
1735 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1736 unsigned int substr_size, clientchar_t *newstr)
1738 clientchar_t temp[1024];
1740 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1741 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1742 cm_ClientStrCat(str1, cchstr1, temp);
1745 clientchar_t VNUserName[] = _C("%USERNAME%");
1746 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1747 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1748 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1750 typedef struct smb_findShare_rock {
1751 clientchar_t * shareName;
1752 clientchar_t * match;
1754 } smb_findShare_rock_t;
1756 #define SMB_FINDSHARE_EXACT_MATCH 1
1757 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1759 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1763 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1764 normchar_t normName[MAX_PATH];
1766 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1767 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1768 osi_LogSaveString(smb_logp, dep->name));
1772 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1773 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1774 matchType = SMB_FINDSHARE_EXACT_MATCH;
1776 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1779 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1780 vrock->matchType = matchType;
1782 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1783 return CM_ERROR_STOPNOW;
1789 /* find a shareName in the table of submounts */
1790 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1791 clientchar_t *shareName,
1792 clientchar_t **pathNamep)
1796 clientchar_t pathName[1024];
1799 clientchar_t *p, *q;
1800 fschar_t *cellname = NULL;
1803 DWORD allSubmount = 1;
1805 /* if allSubmounts == 0, only return the //mountRoot/all share
1806 * if in fact it has been been created in the subMounts table.
1807 * This is to allow sites that want to restrict access to the
1810 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1811 0, KEY_QUERY_VALUE, &parmKey);
1812 if (code == ERROR_SUCCESS) {
1813 cblen = sizeof(allSubmount);
1814 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1815 (BYTE *) &allSubmount, &cblen);
1816 if (code != ERROR_SUCCESS) {
1819 RegCloseKey (parmKey);
1822 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1827 /* In case, the all share is disabled we need to still be able
1828 * to handle ioctl requests
1830 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1831 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1835 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1836 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1837 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1838 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1839 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1845 /* Check for volume references
1847 * They look like <cell>{%,#}<volume>
1849 if (cm_ClientStrChr(shareName, '%') != NULL ||
1850 cm_ClientStrChr(shareName, '#') != NULL) {
1851 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1852 /* make room for '/@vol:' + mountchar + NULL terminator*/
1854 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1855 osi_LogSaveClientString(smb_logp, shareName));
1857 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1858 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1859 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1861 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1863 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1864 cm_ClientStrLwr(*pathNamep);
1865 osi_Log1(smb_logp, " returning pathname [%S]",
1866 osi_LogSaveClientString(smb_logp, *pathNamep));
1874 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1875 0, KEY_QUERY_VALUE, &parmKey);
1876 if (code == ERROR_SUCCESS) {
1877 cblen = sizeof(pathName);
1878 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1879 (BYTE *) pathName, &cblen);
1880 if (code != ERROR_SUCCESS)
1882 RegCloseKey (parmKey);
1886 cchlen = cblen / sizeof(clientchar_t);
1887 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1888 /* We can accept either unix or PC style AFS pathnames. Convert
1889 * Unix-style to PC style here for internal use.
1892 cchlen = lengthof(pathName);
1894 /* within this code block, we maintain, cchlen = writeable
1895 buffer length of p */
1897 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1898 p += cm_mountRootCLen; /* skip mount path */
1899 cchlen -= (DWORD)(p - pathName);
1904 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1910 clientchar_t temp[1024];
1912 if (var = smb_stristr(p, VNUserName)) {
1913 if (uidp && uidp->unp)
1914 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1916 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1918 else if (var = smb_stristr(p, VNLCUserName))
1920 if (uidp && uidp->unp)
1921 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1923 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1924 cm_ClientStrLwr(temp);
1925 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1927 else if (var = smb_stristr(p, VNComputerName))
1929 sizeTemp = lengthof(temp);
1930 GetComputerNameW(temp, &sizeTemp);
1931 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1933 else if (var = smb_stristr(p, VNLCComputerName))
1935 sizeTemp = lengthof(temp);
1936 GetComputerName((LPTSTR)temp, &sizeTemp);
1937 cm_ClientStrLwr(temp);
1938 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1943 *pathNamep = cm_ClientStrDup(p);
1948 /* First lookup shareName in root.afs */
1950 smb_findShare_rock_t vrock;
1952 fschar_t ftemp[1024];
1953 clientchar_t * p = shareName;
1956 /* attempt to locate a partial match in root.afs. This is because
1957 when using the ANSI RAP calls, the share name is limited to 13 chars
1958 and hence is truncated. Of course we prefer exact matches. */
1960 thyper.HighPart = 0;
1963 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1964 if (vrock.shareName == NULL)
1967 vrock.matchType = 0;
1969 cm_HoldSCache(cm_data.rootSCachep);
1970 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1971 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1972 cm_ReleaseSCache(cm_data.rootSCachep);
1974 free(vrock.shareName);
1975 vrock.shareName = NULL;
1977 if (vrock.matchType) {
1978 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1979 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1984 /* if we get here, there was no match for the share in root.afs */
1985 /* so try to create \\<netbiosName>\<cellname> */
1990 /* Get the full name for this cell */
1991 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1992 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1993 #ifdef AFS_AFSDB_ENV
1994 if (code && cm_dnsEnabled) {
1996 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2002 /* construct the path */
2004 clientchar_t temp[1024];
2006 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2007 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2008 rw ? _C("/.%S/") : _C("/%S/"), temp);
2009 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2019 /* Client-side offline caching policy types */
2020 #define CSC_POLICY_MANUAL 0
2021 #define CSC_POLICY_DOCUMENTS 1
2022 #define CSC_POLICY_PROGRAMS 2
2023 #define CSC_POLICY_DISABLE 3
2025 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2028 clientchar_t policy[1024];
2031 int retval = CSC_POLICY_MANUAL;
2033 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2034 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2037 REG_OPTION_NON_VOLATILE,
2043 len = sizeof(policy);
2044 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2046 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2048 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2050 retval = CSC_POLICY_DOCUMENTS;
2052 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2054 retval = CSC_POLICY_PROGRAMS;
2056 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2058 retval = CSC_POLICY_DISABLE;
2061 RegCloseKey(hkCSCPolicy);
2065 /* find a dir search structure by cookie value, and return it held.
2066 * Must be called with smb_globalLock held.
2068 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2070 smb_dirSearch_t *dsp;
2072 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2073 if (dsp->cookie == cookie) {
2074 if (dsp != smb_firstDirSearchp) {
2075 /* move to head of LRU queue, too, if we're not already there */
2076 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2077 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2078 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2079 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2080 if (!smb_lastDirSearchp)
2081 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2089 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2090 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2091 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2097 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2099 lock_ObtainMutex(&dsp->mx);
2100 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2101 dsp->cookie, dsp, dsp->scp);
2102 dsp->flags |= SMB_DIRSEARCH_DELETE;
2103 if (dsp->scp != NULL) {
2104 lock_ObtainWrite(&dsp->scp->rw);
2105 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2106 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2107 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2108 dsp->scp->bulkStatProgress = hzero;
2110 lock_ReleaseWrite(&dsp->scp->rw);
2112 lock_ReleaseMutex(&dsp->mx);
2115 /* Must be called with the smb_globalLock held */
2116 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2118 cm_scache_t *scp = NULL;
2120 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2121 if (dsp->refCount == 0) {
2122 lock_ObtainMutex(&dsp->mx);
2123 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2124 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2125 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2126 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2127 lock_ReleaseMutex(&dsp->mx);
2128 lock_FinalizeMutex(&dsp->mx);
2130 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2131 dsp->cookie, dsp, scp);
2134 lock_ReleaseMutex(&dsp->mx);
2137 /* do this now to avoid spurious locking hierarchy creation */
2139 cm_ReleaseSCache(scp);
2142 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2144 lock_ObtainWrite(&smb_globalLock);
2145 smb_ReleaseDirSearchNoLock(dsp);
2146 lock_ReleaseWrite(&smb_globalLock);
2149 /* find a dir search structure by cookie value, and return it held */
2150 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2152 smb_dirSearch_t *dsp;
2154 lock_ObtainWrite(&smb_globalLock);
2155 dsp = smb_FindDirSearchNoLock(cookie);
2156 lock_ReleaseWrite(&smb_globalLock);
2160 /* GC some dir search entries, in the address space expected by the specific protocol.
2161 * Must be called with smb_globalLock held; release the lock temporarily.
2163 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2164 void smb_GCDirSearches(int isV3)
2166 smb_dirSearch_t *prevp;
2167 smb_dirSearch_t *dsp;
2168 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2172 victimCount = 0; /* how many have we got so far */
2173 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2174 /* we'll move tp from queue, so
2177 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2178 /* if no one is using this guy, and we're either in the new protocol,
2179 * or we're in the old one and this is a small enough ID to be useful
2180 * to the old protocol, GC this guy.
2182 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2183 /* hold and delete */
2184 lock_ObtainMutex(&dsp->mx);
2185 dsp->flags |= SMB_DIRSEARCH_DELETE;
2186 lock_ReleaseMutex(&dsp->mx);
2187 victimsp[victimCount++] = dsp;
2191 /* don't do more than this */
2192 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2196 /* now release them */
2197 for (i = 0; i < victimCount; i++) {
2198 smb_ReleaseDirSearchNoLock(victimsp[i]);
2202 /* function for allocating a dir search entry. We need these to remember enough context
2203 * since we don't get passed the path from call to call during a directory search.
2205 * Returns a held dir search structure, and bumps the reference count on the vnode,
2206 * since it saves a pointer to the vnode.
2208 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2210 smb_dirSearch_t *dsp;
2216 lock_ObtainWrite(&smb_globalLock);
2219 /* what's the biggest ID allowed in this version of the protocol */
2220 /* TODO: do we really want a non v3 dir search request to wrap
2221 smb_dirSearchCounter? */
2222 maxAllowed = isV3 ? 65535 : 255;
2223 if (smb_dirSearchCounter > maxAllowed)
2224 smb_dirSearchCounter = 1;
2226 start = smb_dirSearchCounter;
2229 /* twice so we have enough tries to find guys we GC after one pass;
2230 * 10 extra is just in case I mis-counted.
2232 if (++counter > 2*maxAllowed+10)
2233 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2235 if (smb_dirSearchCounter > maxAllowed) {
2236 smb_dirSearchCounter = 1;
2238 if (smb_dirSearchCounter == start) {
2240 smb_GCDirSearches(isV3);
2243 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2245 /* don't need to watch for refcount zero and deleted, since
2246 * we haven't dropped the global lock.
2249 ++smb_dirSearchCounter;
2253 dsp = malloc(sizeof(*dsp));
2254 memset(dsp, 0, sizeof(*dsp));
2255 dsp->cookie = smb_dirSearchCounter;
2256 ++smb_dirSearchCounter;
2258 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2259 dsp->lastTime = osi_Time();
2260 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2261 if (!smb_lastDirSearchp)
2262 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2264 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2268 lock_ReleaseWrite(&smb_globalLock);
2272 static smb_packet_t *smb_GetPacket(void)
2276 lock_ObtainWrite(&smb_globalLock);
2277 tbp = smb_packetFreeListp;
2279 smb_packetFreeListp = tbp->nextp;
2280 lock_ReleaseWrite(&smb_globalLock);
2282 tbp = calloc(sizeof(*tbp),1);
2283 tbp->magic = SMB_PACKETMAGIC;
2286 tbp->resumeCode = 0;
2292 tbp->ncb_length = 0;
2295 tbp->stringsp = NULL;
2297 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2302 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2305 tbp = smb_GetPacket();
2306 memcpy(tbp, pkt, sizeof(smb_packet_t));
2307 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2308 tbp->stringsp = NULL;
2310 smb_HoldVC(tbp->vcp);
2314 static NCB *smb_GetNCB(void)
2319 lock_ObtainWrite(&smb_globalLock);
2320 tbp = smb_ncbFreeListp;
2322 smb_ncbFreeListp = tbp->nextp;
2323 lock_ReleaseWrite(&smb_globalLock);
2325 tbp = calloc(sizeof(*tbp),1);
2326 tbp->magic = SMB_NCBMAGIC;
2329 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2331 memset(&tbp->ncb, 0, sizeof(NCB));
2336 static void FreeSMBStrings(smb_packet_t * pkt)
2341 for (s = pkt->stringsp; s; s = ns) {
2345 pkt->stringsp = NULL;
2348 void smb_FreePacket(smb_packet_t *tbp)
2350 smb_vc_t * vcp = NULL;
2351 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2353 lock_ObtainWrite(&smb_globalLock);
2354 tbp->nextp = smb_packetFreeListp;
2355 smb_packetFreeListp = tbp;
2356 tbp->magic = SMB_PACKETMAGIC;
2360 tbp->resumeCode = 0;
2366 tbp->ncb_length = 0;
2368 FreeSMBStrings(tbp);
2369 lock_ReleaseWrite(&smb_globalLock);
2375 static void smb_FreeNCB(NCB *bufferp)
2379 tbp = (smb_ncb_t *) bufferp;
2380 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2382 lock_ObtainWrite(&smb_globalLock);
2383 tbp->nextp = smb_ncbFreeListp;
2384 smb_ncbFreeListp = tbp;
2385 lock_ReleaseWrite(&smb_globalLock);
2388 /* get a ptr to the data part of a packet, and its count */
2389 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2393 unsigned char *afterParmsp;
2395 parmBytes = *smbp->wctp << 1;
2396 afterParmsp = smbp->wctp + parmBytes + 1;
2398 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2399 if (nbytesp) *nbytesp = dataBytes;
2401 /* don't forget to skip the data byte count, since it follows
2402 * the parameters; that's where the "2" comes from below.
2404 return (unsigned char *) (afterParmsp + 2);
2407 /* must set all the returned parameters before playing around with the
2408 * data region, since the data region is located past the end of the
2409 * variable number of parameters.
2411 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2413 unsigned char *afterParmsp;
2415 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2417 *afterParmsp++ = dsize & 0xff;
2418 *afterParmsp = (dsize>>8) & 0xff;
2421 /* return the parm'th parameter in the smbp packet */
2422 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2425 unsigned char *parmDatap;
2427 parmCount = *smbp->wctp;
2429 if (parm >= parmCount) {
2432 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2433 parm, parmCount, smbp->ncb_length);
2434 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2435 parm, parmCount, smbp->ncb_length);
2436 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2437 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2438 osi_panic(s, __FILE__, __LINE__);
2440 parmDatap = smbp->wctp + (2*parm) + 1;
2442 return parmDatap[0] + (parmDatap[1] << 8);
2445 /* return the parm'th parameter in the smbp packet */
2446 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2449 unsigned char *parmDatap;
2451 parmCount = *smbp->wctp;
2453 if (parm >= parmCount) {
2456 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2457 parm, parmCount, smbp->ncb_length);
2458 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2459 parm, parmCount, smbp->ncb_length);
2460 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2461 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2462 osi_panic(s, __FILE__, __LINE__);
2464 parmDatap = smbp->wctp + (2*parm) + 1;
2466 return parmDatap[0];
2469 /* return the parm'th parameter in the smbp packet */
2470 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2473 unsigned char *parmDatap;
2475 parmCount = *smbp->wctp;
2477 if (parm + 1 >= parmCount) {
2480 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2481 parm, parmCount, smbp->ncb_length);
2482 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2483 parm, parmCount, smbp->ncb_length);
2484 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2485 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2486 osi_panic(s, __FILE__, __LINE__);
2488 parmDatap = smbp->wctp + (2*parm) + 1;
2490 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2493 /* return the parm'th parameter in the smbp packet */
2494 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2497 unsigned char *parmDatap;
2499 parmCount = *smbp->wctp;
2501 if (parm * 2 + offset >= parmCount * 2) {
2504 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2505 parm, offset, parmCount, smbp->ncb_length);
2506 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2507 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2508 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2509 parm, offset, parmCount, smbp->ncb_length);
2510 osi_panic(s, __FILE__, __LINE__);
2512 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2514 return parmDatap[0] + (parmDatap[1] << 8);
2517 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2519 unsigned char *parmDatap;
2521 /* make sure we have enough slots */
2522 if (*smbp->wctp <= slot)
2523 *smbp->wctp = slot+1;
2525 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2526 *parmDatap++ = parmValue & 0xff;
2527 *parmDatap = (parmValue>>8) & 0xff;
2530 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2532 unsigned char *parmDatap;
2534 /* make sure we have enough slots */
2535 if (*smbp->wctp <= slot)
2536 *smbp->wctp = slot+2;
2538 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2539 *parmDatap++ = parmValue & 0xff;
2540 *parmDatap++ = (parmValue>>8) & 0xff;
2541 *parmDatap++ = (parmValue>>16) & 0xff;
2542 *parmDatap = (parmValue>>24) & 0xff;
2545 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2547 unsigned char *parmDatap;
2550 /* make sure we have enough slots */
2551 if (*smbp->wctp <= slot)
2552 *smbp->wctp = slot+4;
2554 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2556 *parmDatap++ = *parmValuep++;
2559 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2561 unsigned char *parmDatap;
2563 /* make sure we have enough slots */
2564 if (*smbp->wctp <= slot) {
2565 if (smbp->oddByte) {
2567 *smbp->wctp = slot+1;
2572 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2573 *parmDatap++ = parmValue & 0xff;
2578 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2579 clientchar_t *inPathp)
2581 clientchar_t *lastSlashp;
2583 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2585 *lastComponentp = lastSlashp;
2588 if (inPathp == lastSlashp)
2590 *outPathp++ = *inPathp++;
2599 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2600 char **chainpp, int flags)
2608 if (!WANTS_UNICODE(pktp))
2609 flags |= SMB_STRF_FORCEASCII;
2612 cb = sizeof(pktp->data) - (inp - pktp->data);
2613 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2614 #ifdef DEBUG_UNICODE
2617 cb = sizeof(pktp->data);
2619 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2622 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2623 char ** chainpp, int flags)
2628 if (!WANTS_UNICODE(pktp))
2629 flags |= SMB_STRF_FORCEASCII;
2632 cb = sizeof(pktp->data) - (inp - pktp->data);
2633 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2634 #ifdef DEBUG_UNICODE
2637 cb = sizeof(pktp->data);
2639 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2640 flags | SMB_STRF_SRCNULTERM);
2643 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2644 size_t cb, char ** chainpp, int flags)
2647 if (!WANTS_UNICODE(pktp))
2648 flags |= SMB_STRF_FORCEASCII;
2651 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2654 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2655 size_t cch, char ** chainpp, int flags)
2660 if (!WANTS_UNICODE(pktp))
2661 flags |= SMB_STRF_FORCEASCII;
2663 cb = cch * sizeof(wchar_t);
2666 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2670 smb_ParseStringBuf(const unsigned char * bufbase,
2671 cm_space_t ** stringspp,
2672 unsigned char *inp, size_t *pcb_max,
2673 char **chainpp, int flags)
2676 if (!(flags & SMB_STRF_FORCEASCII)) {
2678 cm_space_t * spacep;
2681 if (bufbase && ((inp - bufbase) % 2) != 0) {
2682 inp++; /* unicode strings are always word aligned */
2686 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2688 cch_src = *pcb_max / sizeof(wchar_t);
2692 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2699 spacep = cm_GetSpace();
2700 spacep->nextp = *stringspp;
2701 *stringspp = spacep;
2705 *chainpp = inp + sizeof(wchar_t);
2708 *(spacep->wdata) = 0;
2709 return spacep->wdata;
2712 StringCchCopyNW(spacep->wdata,
2713 lengthof(spacep->wdata),
2714 (const clientchar_t *) inp, cch_src);
2717 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2719 return spacep->wdata;
2723 cm_space_t * spacep;
2726 /* Not using Unicode */
2728 *chainpp = inp + strlen(inp) + 1;
2731 spacep = cm_GetSpace();
2732 spacep->nextp = *stringspp;
2733 *stringspp = spacep;
2735 cchdest = lengthof(spacep->wdata);
2736 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2737 spacep->wdata, cchdest);
2739 return spacep->wdata;
2745 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2747 size_t * plen, int flags)
2753 /* we are only calculating the required size */
2760 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2762 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2763 if (!(flags & SMB_STRF_IGNORENUL))
2764 *plen += sizeof(wchar_t);
2766 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2776 cch_str = cm_ClientStrLen(str);
2777 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2780 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2788 /* if outp != NULL ... */
2790 /* Number of bytes left in the buffer.
2792 If outp lies inside the packet data buffer, we assume that the
2793 buffer is the packet data buffer. Otherwise we assume that the
2794 buffer is sizeof(packet->data).
2797 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2798 align = (int)((outp - pktp->data) % 2);
2799 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2801 align = (int)(((size_t) outp) % 2);
2802 buffersize = (int)sizeof(pktp->data);
2807 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2813 if (*str == _C('\0')) {
2815 if (buffersize < sizeof(wchar_t))
2818 *((wchar_t *) outp) = L'\0';
2819 if (plen && !(flags & SMB_STRF_IGNORENUL))
2820 *plen += sizeof(wchar_t);
2821 return outp + sizeof(wchar_t);
2824 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2826 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2827 osi_LogSaveClientString(smb_logp, str),
2833 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2835 return outp + sizeof(wchar_t) * nchars;
2843 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2846 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2848 return outp + cch_dest;
2852 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2858 tlen = inp[0] + (inp[1]<<8);
2859 inp += 2; /* skip length field */
2862 *chainpp = inp + tlen;
2871 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2875 if (*inp++ != 0x1) return NULL;
2876 tlen = inp[0] + (inp[1]<<8);
2877 inp += 2; /* skip length field */
2880 *chainpp = inp + tlen;
2883 if (lengthp) *lengthp = tlen;
2888 /* format a packet as a response */
2889 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2894 outp = (smb_t *) op;
2896 /* zero the basic structure through the smb_wct field, and zero the data
2897 * size field, assuming that wct stays zero; otherwise, you have to
2898 * explicitly set the data size field, too.
2900 inSmbp = (smb_t *) inp;
2901 memset(outp, 0, sizeof(smb_t)+2);
2907 outp->com = inSmbp->com;
2908 outp->tid = inSmbp->tid;
2909 outp->pid = inSmbp->pid;
2910 outp->uid = inSmbp->uid;
2911 outp->mid = inSmbp->mid;
2912 outp->res[0] = inSmbp->res[0];
2913 outp->res[1] = inSmbp->res[1];
2914 op->inCom = inSmbp->com;
2916 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2917 #ifdef SEND_CANONICAL_PATHNAMES
2918 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2920 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2922 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2923 outp->flg2 |= SMB_FLAGS2_UNICODE;
2926 /* copy fields in generic packet area */
2927 op->wctp = &outp->wct;
2930 /* send a (probably response) packet; vcp tells us to whom to send it.
2931 * we compute the length by looking at wct and bcc fields.
2933 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2943 ncbp = smb_GetNCB();
2947 memset((char *)ncbp, 0, sizeof(NCB));
2949 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2950 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2951 extra += tp[0] + (tp[1]<<8);
2952 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2953 extra += 3; /* wct and length fields */
2955 ncbp->ncb_length = extra; /* bytes to send */
2956 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2957 ncbp->ncb_lana_num = vcp->lana;
2958 ncbp->ncb_command = NCBSEND; /* op means send data */
2959 ncbp->ncb_buffer = (char *) inp;/* packet */
2960 code = Netbios(ncbp);
2963 const char * s = ncb_error_string(code);
2964 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2965 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2967 lock_ObtainMutex(&vcp->mx);
2968 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2969 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2971 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2972 lock_ReleaseMutex(&vcp->mx);
2973 lock_ObtainWrite(&smb_globalLock);
2974 dead_sessions[vcp->session] = TRUE;
2975 lock_ReleaseWrite(&smb_globalLock);
2976 smb_CleanupDeadVC(vcp);
2978 lock_ReleaseMutex(&vcp->mx);
2986 void smb_MapNTError(long code, unsigned long *NTStatusp)
2988 unsigned long NTStatus;
2990 /* map CM_ERROR_* errors to NT 32-bit status codes */
2991 /* NT Status codes are listed in ntstatus.h not winerror.h */
2995 else if (code == CM_ERROR_NOSUCHCELL) {
2996 NTStatus = 0xC000000FL; /* No such file */
2998 else if (code == CM_ERROR_NOSUCHVOLUME) {
2999 NTStatus = 0xC000000FL; /* No such file */
3001 else if (code == CM_ERROR_TIMEDOUT) {
3003 NTStatus = 0xC00000CFL; /* Sharing Paused */
3005 NTStatus = 0x00000102L; /* Timeout */
3008 else if (code == CM_ERROR_RETRY) {
3009 NTStatus = 0xC000022DL; /* Retry */
3011 else if (code == CM_ERROR_NOACCESS) {
3012 NTStatus = 0xC0000022L; /* Access denied */
3014 else if (code == CM_ERROR_READONLY) {
3015 NTStatus = 0xC00000A2L; /* Write protected */
3017 else if (code == CM_ERROR_NOSUCHFILE ||
3018 code == CM_ERROR_BPLUS_NOMATCH) {
3019 NTStatus = 0xC000000FL; /* No such file */
3021 else if (code == CM_ERROR_NOSUCHPATH) {
3022 NTStatus = 0xC000003AL; /* Object path not found */
3024 else if (code == CM_ERROR_TOOBIG) {
3025 NTStatus = 0xC000007BL; /* Invalid image format */
3027 else if (code == CM_ERROR_INVAL) {
3028 NTStatus = 0xC000000DL; /* Invalid parameter */
3030 else if (code == CM_ERROR_BADFD) {
3031 NTStatus = 0xC0000008L; /* Invalid handle */
3033 else if (code == CM_ERROR_BADFDOP) {
3034 NTStatus = 0xC0000022L; /* Access denied */
3036 else if (code == CM_ERROR_EXISTS) {
3037 NTStatus = 0xC0000035L; /* Object name collision */
3039 else if (code == CM_ERROR_NOTEMPTY) {
3040 NTStatus = 0xC0000101L; /* Directory not empty */
3042 else if (code == CM_ERROR_CROSSDEVLINK) {
3043 NTStatus = 0xC00000D4L; /* Not same device */
3045 else if (code == CM_ERROR_NOTDIR) {
3046 NTStatus = 0xC0000103L; /* Not a directory */
3048 else if (code == CM_ERROR_ISDIR) {
3049 NTStatus = 0xC00000BAL; /* File is a directory */
3051 else if (code == CM_ERROR_BADOP) {
3053 /* I have no idea where this comes from */
3054 NTStatus = 0xC09820FFL; /* SMB no support */
3056 NTStatus = 0xC00000BBL; /* Not supported */
3057 #endif /* COMMENT */
3059 else if (code == CM_ERROR_BADSHARENAME) {
3060 NTStatus = 0xC00000CCL; /* Bad network name */
3062 else if (code == CM_ERROR_NOIPC) {
3064 NTStatus = 0xC0000022L; /* Access Denied */
3066 NTStatus = 0xC000013DL; /* Remote Resources */
3069 else if (code == CM_ERROR_CLOCKSKEW) {
3070 NTStatus = 0xC0000133L; /* Time difference at DC */
3072 else if (code == CM_ERROR_BADTID) {
3073 NTStatus = 0xC0982005L; /* SMB bad TID */
3075 else if (code == CM_ERROR_USESTD) {
3076 NTStatus = 0xC09820FBL; /* SMB use standard */
3078 else if (code == CM_ERROR_QUOTA) {
3079 NTStatus = 0xC0000044L; /* Quota exceeded */
3081 else if (code == CM_ERROR_SPACE) {
3082 NTStatus = 0xC000007FL; /* Disk full */
3084 else if (code == CM_ERROR_ATSYS) {
3085 NTStatus = 0xC0000033L; /* Object name invalid */
3087 else if (code == CM_ERROR_BADNTFILENAME) {
3088 NTStatus = 0xC0000033L; /* Object name invalid */
3090 else if (code == CM_ERROR_WOULDBLOCK) {
3091 NTStatus = 0xC0000055L; /* Lock not granted */
3093 else if (code == CM_ERROR_SHARING_VIOLATION) {
3094 NTStatus = 0xC0000043L; /* Sharing violation */
3096 else if (code == CM_ERROR_LOCK_CONFLICT) {
3097 NTStatus = 0xC0000054L; /* Lock conflict */
3099 else if (code == CM_ERROR_PARTIALWRITE) {
3100 NTStatus = 0xC000007FL; /* Disk full */
3102 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3103 NTStatus = 0xC0000023L; /* Buffer too small */
3105 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3106 NTStatus = 0xC0000035L; /* Object name collision */
3108 else if (code == CM_ERROR_BADPASSWORD) {
3109 NTStatus = 0xC000006DL; /* unknown username or bad password */
3111 else if (code == CM_ERROR_BADLOGONTYPE) {
3112 NTStatus = 0xC000015BL; /* logon type not granted */
3114 else if (code == CM_ERROR_GSSCONTINUE) {
3115 NTStatus = 0xC0000016L; /* more processing required */
3117 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3119 NTStatus = 0xC0000280L; /* reparse point not resolved */
3121 NTStatus = 0xC0000022L; /* Access Denied */
3124 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3125 NTStatus = 0xC0000257L; /* Path Not Covered */
3127 else if (code == CM_ERROR_ALLBUSY) {
3128 NTStatus = 0xC000022DL; /* Retry */
3130 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3131 NTStatus = 0xC00000BEL; /* Bad Network Path */
3133 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3134 NTStatus = 0xC0000322L; /* No Kerberos key */
3136 else if (code == CM_ERROR_BAD_LEVEL) {
3137 NTStatus = 0xC0000148L; /* Invalid Level */
3139 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3140 NTStatus = 0xC000007EL; /* Range Not Locked */
3142 else if (code == CM_ERROR_NOSUCHDEVICE) {
3143 NTStatus = 0xC000000EL; /* No Such Device */
3145 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3146 NTStatus = 0xC0000055L; /* Lock Not Granted */
3148 NTStatus = 0xC0982001L; /* SMB non-specific error */
3151 *NTStatusp = NTStatus;
3152 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3155 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3156 unsigned char *classp)
3158 unsigned char class;
3159 unsigned short error;
3161 /* map CM_ERROR_* errors to SMB errors */
3162 if (code == CM_ERROR_NOSUCHCELL) {
3164 error = 3; /* bad path */
3166 else if (code == CM_ERROR_NOSUCHVOLUME) {
3168 error = 3; /* bad path */
3170 else if (code == CM_ERROR_TIMEDOUT) {
3172 error = 81; /* server is paused */
3174 else if (code == CM_ERROR_RETRY) {
3175 class = 2; /* shouldn't happen */
3178 else if (code == CM_ERROR_NOACCESS) {
3180 error = 4; /* bad access */
3182 else if (code == CM_ERROR_READONLY) {
3184 error = 19; /* read only */
3186 else if (code == CM_ERROR_NOSUCHFILE ||
3187 code == CM_ERROR_BPLUS_NOMATCH) {
3189 error = 2; /* ENOENT! */
3191 else if (code == CM_ERROR_NOSUCHPATH) {
3193 error = 3; /* Bad path */
3195 else if (code == CM_ERROR_TOOBIG) {
3197 error = 11; /* bad format */
3199 else if (code == CM_ERROR_INVAL) {
3200 class = 2; /* server non-specific error code */
3203 else if (code == CM_ERROR_BADFD) {
3205 error = 6; /* invalid file handle */
3207 else if (code == CM_ERROR_BADFDOP) {
3208 class = 1; /* invalid op on FD */
3211 else if (code == CM_ERROR_EXISTS) {
3213 error = 80; /* file already exists */
3215 else if (code == CM_ERROR_NOTEMPTY) {
3217 error = 5; /* delete directory not empty */
3219 else if (code == CM_ERROR_CROSSDEVLINK) {
3221 error = 17; /* EXDEV */
3223 else if (code == CM_ERROR_NOTDIR) {
3224 class = 1; /* bad path */
3227 else if (code == CM_ERROR_ISDIR) {
3228 class = 1; /* access denied; DOS doesn't have a good match */
3231 else if (code == CM_ERROR_BADOP) {
3235 else if (code == CM_ERROR_BADSHARENAME) {
3239 else if (code == CM_ERROR_NOIPC) {
3241 error = 4; /* bad access */
3243 else if (code == CM_ERROR_CLOCKSKEW) {
3244 class = 1; /* invalid function */
3247 else if (code == CM_ERROR_BADTID) {
3251 else if (code == CM_ERROR_USESTD) {
3255 else if (code == CM_ERROR_REMOTECONN) {
3259 else if (code == CM_ERROR_QUOTA) {
3260 if (vcp->flags & SMB_VCFLAG_USEV3) {
3262 error = 39; /* disk full */
3266 error = 5; /* access denied */
3269 else if (code == CM_ERROR_SPACE) {
3270 if (vcp->flags & SMB_VCFLAG_USEV3) {
3272 error = 39; /* disk full */
3276 error = 5; /* access denied */
3279 else if (code == CM_ERROR_PARTIALWRITE) {
3281 error = 39; /* disk full */
3283 else if (code == CM_ERROR_ATSYS) {
3285 error = 2; /* ENOENT */
3287 else if (code == CM_ERROR_WOULDBLOCK) {
3289 error = 33; /* lock conflict */
3291 else if (code == CM_ERROR_LOCK_CONFLICT) {
3293 error = 33; /* lock conflict */
3295 else if (code == CM_ERROR_SHARING_VIOLATION) {
3297 error = 33; /* lock conflict */
3299 else if (code == CM_ERROR_NOFILES) {
3301 error = 18; /* no files in search */
3303 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3305 error = 183; /* Samba uses this */
3307 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3308 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3310 error = 2; /* bad password */
3312 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3314 error = 3; /* bad path */
3323 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3326 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3328 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3329 return CM_ERROR_BADOP;
3333 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3335 unsigned short EchoCount, i;
3336 char *data, *outdata;
3339 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3341 for (i=1; i<=EchoCount; i++) {
3342 data = smb_GetSMBData(inp, &dataSize);
3343 smb_SetSMBParm(outp, 0, i);
3344 smb_SetSMBDataLength(outp, dataSize);
3345 outdata = smb_GetSMBData(outp, NULL);
3346 memcpy(outdata, data, dataSize);
3347 smb_SendPacket(vcp, outp);
3353 /* SMB_COM_READ_RAW */
3354 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3357 long count, minCount, finalCount;
3361 smb_t *smbp = (smb_t*) inp;
3363 cm_user_t *userp = NULL;
3366 char *rawBuf = NULL;
3371 fd = smb_GetSMBParm(inp, 0);
3372 count = smb_GetSMBParm(inp, 3);
3373 minCount = smb_GetSMBParm(inp, 4);
3374 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3376 if (*inp->wctp == 10) {
3377 /* we were sent a request with 64-bit file offsets */
3378 #ifdef AFS_LARGEFILES
3379 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3381 if (LargeIntegerLessThanZero(offset)) {
3382 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3386 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3387 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3390 offset.HighPart = 0;
3394 /* we were sent a request with 32-bit file offsets */
3395 offset.HighPart = 0;
3398 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3399 fd, offset.HighPart, offset.LowPart, count);
3401 fidp = smb_FindFID(vcp, fd, 0);
3405 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3406 smb_CloseFID(vcp, fidp, NULL, 0);
3407 code = CM_ERROR_NOSUCHFILE;
3414 LARGE_INTEGER LOffset, LLength;
3417 key = cm_GenerateKey(vcp->vcID, pid, fd);
3419 LOffset.HighPart = offset.HighPart;
3420 LOffset.LowPart = offset.LowPart;
3421 LLength.HighPart = 0;
3422 LLength.LowPart = count;
3424 lock_ObtainWrite(&fidp->scp->rw);
3425 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3426 lock_ReleaseWrite(&fidp->scp->rw);
3432 lock_ObtainMutex(&smb_RawBufLock);
3434 /* Get a raw buf, from head of list */
3435 rawBuf = smb_RawBufs;
3436 smb_RawBufs = *(char **)smb_RawBufs;
3438 lock_ReleaseMutex(&smb_RawBufLock);
3442 lock_ObtainMutex(&fidp->mx);
3443 if (fidp->flags & SMB_FID_IOCTL)
3445 lock_ReleaseMutex(&fidp->mx);
3446 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3448 /* Give back raw buffer */
3449 lock_ObtainMutex(&smb_RawBufLock);
3450 *((char **) rawBuf) = smb_RawBufs;
3452 smb_RawBufs = rawBuf;
3453 lock_ReleaseMutex(&smb_RawBufLock);
3456 lock_ReleaseMutex(&fidp->mx);
3457 smb_ReleaseFID(fidp);
3460 lock_ReleaseMutex(&fidp->mx);
3462 userp = smb_GetUserFromVCP(vcp, inp);
3464 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3470 cm_ReleaseUser(userp);
3473 smb_ReleaseFID(fidp);
3477 memset((char *)ncbp, 0, sizeof(NCB));
3479 ncbp->ncb_length = (unsigned short) finalCount;
3480 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3481 ncbp->ncb_lana_num = vcp->lana;
3482 ncbp->ncb_command = NCBSEND;
3483 ncbp->ncb_buffer = rawBuf;
3485 code = Netbios(ncbp);
3487 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3490 /* Give back raw buffer */
3491 lock_ObtainMutex(&smb_RawBufLock);
3492 *((char **) rawBuf) = smb_RawBufs;
3494 smb_RawBufs = rawBuf;
3495 lock_ReleaseMutex(&smb_RawBufLock);
3501 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3503 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3508 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3510 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3515 /* SMB_COM_NEGOTIATE */
3516 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3523 int VistaProtoIndex;
3524 int protoIndex; /* index we're using */
3529 char protocol_array[10][1024]; /* protocol signature of the client */
3530 int caps; /* capabilities */
3533 TIME_ZONE_INFORMATION tzi;
3535 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3538 namep = smb_GetSMBData(inp, &dbytes);
3541 coreProtoIndex = -1; /* not found */
3544 VistaProtoIndex = -1;
3545 while(namex < dbytes) {
3546 osi_Log1(smb_logp, "Protocol %s",
3547 osi_LogSaveString(smb_logp, namep+1));
3548 strcpy(protocol_array[tcounter], namep+1);
3550 /* namep points at the first protocol, or really, a 0x02
3551 * byte preceding the null-terminated ASCII name.
3553 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3554 coreProtoIndex = tcounter;
3556 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3557 v3ProtoIndex = tcounter;
3559 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3560 NTProtoIndex = tcounter;
3562 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3563 VistaProtoIndex = tcounter;
3566 /* compute size of protocol entry */
3567 entryLength = (int)strlen(namep+1);
3568 entryLength += 2; /* 0x02 bytes and null termination */
3570 /* advance over this protocol entry */
3571 namex += entryLength;
3572 namep += entryLength;
3573 tcounter++; /* which proto entry we're looking at */
3576 lock_ObtainMutex(&vcp->mx);
3578 if (VistaProtoIndex != -1) {
3579 protoIndex = VistaProtoIndex;
3580 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3583 if (NTProtoIndex != -1) {
3584 protoIndex = NTProtoIndex;
3585 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3587 else if (v3ProtoIndex != -1) {
3588 protoIndex = v3ProtoIndex;
3589 vcp->flags |= SMB_VCFLAG_USEV3;
3591 else if (coreProtoIndex != -1) {
3592 protoIndex = coreProtoIndex;
3593 vcp->flags |= SMB_VCFLAG_USECORE;
3595 else protoIndex = -1;
3596 lock_ReleaseMutex(&vcp->mx);
3598 if (protoIndex == -1)
3599 return CM_ERROR_INVAL;
3600 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3601 smb_SetSMBParm(outp, 0, protoIndex);
3602 if (smb_authType != SMB_AUTH_NONE) {
3603 smb_SetSMBParmByte(outp, 1,
3604 NEGOTIATE_SECURITY_USER_LEVEL |
3605 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3607 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3609 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3610 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3611 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3612 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3613 /* The session key is not a well documented field however most clients
3614 * will echo back the session key to the server. Currently we are using
3615 * the same value for all sessions. We should generate a random value
3616 * and store it into the vcp
3618 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3619 smb_SetSMBParm(outp, 8, 1);
3621 * Tried changing the capabilities to support for W2K - defect 117695
3622 * Maybe something else needs to be changed here?
3626 smb_SetSMBParmLong(outp, 9, 0x43fd);
3628 smb_SetSMBParmLong(outp, 9, 0x251);
3631 * 32-bit error codes *
3637 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3639 NTNEGOTIATE_CAPABILITY_DFS |
3641 #ifdef AFS_LARGEFILES
3642 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3644 NTNEGOTIATE_CAPABILITY_NTFIND |
3645 NTNEGOTIATE_CAPABILITY_RAWMODE |
3646 NTNEGOTIATE_CAPABILITY_NTSMB;
3648 if ( smb_authType == SMB_AUTH_EXTENDED )
3649 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3652 if ( smb_UseUnicode ) {
3653 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3657 smb_SetSMBParmLong(outp, 9, caps);
3659 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3660 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3661 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3663 GetTimeZoneInformation(&tzi);
3664 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3666 if (smb_authType == SMB_AUTH_NTLM) {
3667 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3668 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3669 /* paste in encryption key */
3670 datap = smb_GetSMBData(outp, NULL);
3671 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3672 /* and the faux domain name */
3673 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3674 datap + MSV1_0_CHALLENGE_LENGTH,
3675 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3676 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3680 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3682 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3684 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3686 datap = smb_GetSMBData(outp, NULL);
3687 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3690 datap += sizeof(smb_ServerGUID);
3691 memcpy(datap, secBlob, secBlobLength);
3695 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3696 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3699 else if (v3ProtoIndex != -1) {
3700 smb_SetSMBParm(outp, 0, protoIndex);
3702 /* NOTE: Extended authentication cannot be negotiated with v3
3703 * therefore we fail over to NTLM
3705 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3706 smb_SetSMBParm(outp, 1,
3707 NEGOTIATE_SECURITY_USER_LEVEL |
3708 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3710 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3712 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3713 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3714 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3715 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3716 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3717 smb_SetSMBParm(outp, 7, 1);
3719 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3720 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3721 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3723 GetTimeZoneInformation(&tzi);
3724 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3726 /* NOTE: Extended authentication cannot be negotiated with v3
3727 * therefore we fail over to NTLM
3729 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3730 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3731 smb_SetSMBParm(outp, 12, 0); /* resvd */
3732 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3733 datap = smb_GetSMBData(outp, NULL);
3734 /* paste in a new encryption key */
3735 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3736 /* and the faux domain name */
3737 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3738 datap + MSV1_0_CHALLENGE_LENGTH,
3739 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3741 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3742 smb_SetSMBParm(outp, 12, 0); /* resvd */
3743 smb_SetSMBDataLength(outp, 0);
3746 else if (coreProtoIndex != -1) { /* not really supported anymore */
3747 smb_SetSMBParm(outp, 0, protoIndex);
3748 smb_SetSMBDataLength(outp, 0);
3753 void smb_CheckVCs(void)
3755 smb_vc_t * vcp, *nextp;
3756 smb_packet_t * outp = smb_GetPacket();
3759 lock_ObtainWrite(&smb_rctLock);
3760 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3762 if (vcp->magic != SMB_VC_MAGIC)
3763 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3764 __FILE__, __LINE__);
3766 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3768 smb_HoldVCNoLock(vcp);
3771 * obtain a reference to 'nextp' now because we drop the
3772 * smb_rctLock later and the list contents could change
3773 * or 'vcp' could be destroyed when released.
3777 smb_HoldVCNoLock(nextp);
3779 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3780 smb_ReleaseVCNoLock(vcp);
3784 smb_FormatResponsePacket(vcp, NULL, outp);
3785 smbp = (smb_t *)outp;
3786 outp->inCom = smbp->com = 0x2b /* Echo */;
3794 smb_SetSMBParm(outp, 0, 0);
3795 smb_SetSMBDataLength(outp, 0);
3796 lock_ReleaseWrite(&smb_rctLock);
3798 smb_SendPacket(vcp, outp);
3800 lock_ObtainWrite(&smb_rctLock);
3801 smb_ReleaseVCNoLock(vcp);
3803 lock_ReleaseWrite(&smb_rctLock);
3804 smb_FreePacket(outp);
3807 void smb_Daemon(void *parmp)
3809 afs_uint32 count = 0;
3810 smb_username_t **unpp;
3813 while(smbShutdownFlag == 0) {
3817 if (smbShutdownFlag == 1)
3820 if ((count % 72) == 0) { /* every five minutes */
3822 time_t old_localZero = smb_localZero;
3824 /* Initialize smb_localZero */
3825 myTime.tm_isdst = -1; /* compute whether on DST or not */
3826 myTime.tm_year = 70;
3832 smb_localZero = mktime(&myTime);
3834 #ifndef USE_NUMERIC_TIME_CONV
3835 smb_CalculateNowTZ();
3836 #endif /* USE_NUMERIC_TIME_CONV */
3837 #ifdef AFS_FREELANCE
3838 if ( smb_localZero != old_localZero )
3839 cm_noteLocalMountPointChange();
3845 /* GC smb_username_t objects that will no longer be used */
3847 lock_ObtainWrite(&smb_rctLock);
3848 for ( unpp=&usernamesp; *unpp; ) {
3850 smb_username_t *unp;
3852 lock_ObtainMutex(&(*unpp)->mx);
3853 if ( (*unpp)->refCount > 0 ||
3854 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3855 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3857 else if (!smb_LogoffTokenTransfer ||
3858 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3860 lock_ReleaseMutex(&(*unpp)->mx);
3868 lock_FinalizeMutex(&unp->mx);
3874 cm_ReleaseUser(userp);
3876 unpp = &(*unpp)->nextp;
3879 lock_ReleaseWrite(&smb_rctLock);
3881 /* XXX GC dir search entries */
3885 void smb_WaitingLocksDaemon()
3887 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3888 smb_waitingLock_t *wl, *wlNext;
3891 smb_packet_t *inp, *outp;
3895 while (smbShutdownFlag == 0) {
3896 lock_ObtainWrite(&smb_globalLock);
3897 nwlRequest = smb_allWaitingLocks;
3898 if (nwlRequest == NULL) {
3899 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3904 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3911 lock_ObtainWrite(&smb_globalLock);
3913 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3915 wlRequest = nwlRequest;
3916 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3917 lock_ReleaseWrite(&smb_globalLock);
3921 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3922 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3925 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3926 code = CM_ERROR_LOCK_NOT_GRANTED;
3930 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3932 /* wl->state is either _DONE or _WAITING. _ERROR
3933 would no longer be on the queue. */
3934 code = cm_RetryLock( wl->lockp,
3935 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3938 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3939 } else if (code != CM_ERROR_WOULDBLOCK) {
3940 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3945 if (code == CM_ERROR_WOULDBLOCK) {
3948 if (wlRequest->msTimeout != 0xffffffff
3949 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3961 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3964 scp = wlRequest->scp;
3965 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3969 lock_ObtainWrite(&scp->rw);
3971 for (wl = wlRequest->locks; wl; wl = wlNext) {
3972 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3974 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3975 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3976 wl->LLength, wl->key, NULL, &req);
3978 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3983 lock_ReleaseWrite(&scp->rw);
3987 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3990 for (wl = wlRequest->locks; wl; wl = wlNext) {
3991 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3992 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3997 vcp = wlRequest->vcp;
3998 inp = wlRequest->inp;
3999 outp = wlRequest->outp;
4000 ncbp = smb_GetNCB();
4001 ncbp->ncb_length = inp->ncb_length;
4002 inp->spacep = cm_GetSpace();
4004 /* Remove waitingLock from list */
4005 lock_ObtainWrite(&smb_globalLock);
4006 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4008 lock_ReleaseWrite(&smb_globalLock);
4010 /* Resume packet processing */
4012 smb_SetSMBDataLength(outp, 0);
4013 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4014 outp->resumeCode = code;
4016 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4019 cm_FreeSpace(inp->spacep);
4020 smb_FreePacket(inp);
4021 smb_FreePacket(outp);
4023 cm_ReleaseSCache(wlRequest->scp);
4026 } while (nwlRequest && smbShutdownFlag == 0);
4031 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4033 osi_Log0(smb_logp, "SMB receive get disk attributes");
4035 smb_SetSMBParm(outp, 0, 32000);
4036 smb_SetSMBParm(outp, 1, 64);
4037 smb_SetSMBParm(outp, 2, 1024);
4038 smb_SetSMBParm(outp, 3, 30000);
4039 smb_SetSMBParm(outp, 4, 0);
4040 smb_SetSMBDataLength(outp, 0);
4044 /* SMB_COM_TREE_CONNECT */
4045 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4049 unsigned short newTid;
4050 clientchar_t shareName[AFSPATHMAX];
4051 clientchar_t *sharePath;
4054 clientchar_t *pathp;
4057 osi_Log0(smb_logp, "SMB receive tree connect");
4059 /* parse input parameters */
4062 tbp = smb_GetSMBData(inp, NULL);
4063 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4065 tp = cm_ClientStrRChr(pathp, '\\');
4067 return CM_ERROR_BADSMB;
4068 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4070 lock_ObtainMutex(&vcp->mx);
4071 newTid = vcp->tidCounter++;
4072 lock_ReleaseMutex(&vcp->mx);
4074 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4075 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4077 return CM_ERROR_BADSMB;
4078 userp = smb_GetUserFromUID(uidp);
4079 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4080 smb_ReleaseUID(uidp);
4082 smb_ReleaseTID(tidp, FALSE);
4083 return CM_ERROR_BADSHARENAME;
4085 lock_ObtainMutex(&tidp->mx);
4086 tidp->userp = userp;
4087 tidp->pathname = sharePath;
4088 lock_ReleaseMutex(&tidp->mx);
4089 smb_ReleaseTID(tidp, FALSE);
4091 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4092 smb_SetSMBParm(rsp, 1, newTid);
4093 smb_SetSMBDataLength(rsp, 0);
4095 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4099 /* set maskp to the mask part of the incoming path.
4100 * Mask is 11 bytes long (8.3 with the dot elided).
4101 * Returns true if succeeds with a valid name, otherwise it does
4102 * its best, but returns false.
4104 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4112 /* starts off valid */
4115 /* mask starts out all blanks */
4116 memset(maskp, ' ', 11);
4119 /* find last backslash, or use whole thing if there is none */
4120 tp = cm_ClientStrRChr(pathp, '\\');
4124 tp++; /* skip slash */
4128 /* names starting with a dot are illegal */
4136 if (tc == '.' || tc == '"')
4144 /* if we get here, tp point after the dot */
4145 up = maskp+8; /* ext goes here */
4152 if (tc == '.' || tc == '"')
4155 /* copy extension if not too long */
4165 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4167 clientchar_t umask[11];
4175 /* XXX redo this, calling cm_MatchMask with a converted mask */
4177 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4181 /* otherwise, we have a valid 8.3 name; see if we have a match,
4182 * treating '?' as a wildcard in maskp (but not in the file name).
4184 tp1 = umask; /* real name, in mask format */
4185 tp2 = maskp; /* mask, in mask format */
4186 for(i=0; i<11; i++) {
4187 tc1 = *tp1++; /* clientchar_t from real name */
4188 tc2 = *tp2++; /* clientchar_t from mask */
4189 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4190 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4193 if (tc2 == '?' && tc1 != ' ')
4200 /* we got a match */
4204 clientchar_t *smb_FindMask(clientchar_t *pathp)
4208 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4211 return tp+1; /* skip the slash */
4213 return pathp; /* no slash, return the entire path */
4216 /* SMB_COM_SEARCH for a volume label
4218 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4219 dispatch function.) */
4220 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4222 clientchar_t *pathp;
4224 clientchar_t mask[12];
4225 unsigned char *statBlockp;
4226 unsigned char initStatBlock[21];
4229 osi_Log0(smb_logp, "SMB receive search volume");
4231 /* pull pathname and stat block out of request */
4232 tp = smb_GetSMBData(inp, NULL);
4233 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4234 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4235 osi_assertx(pathp != NULL, "null path");
4236 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4237 osi_assertx(statBlockp != NULL, "null statBlock");
4239 statBlockp = initStatBlock;
4243 /* for returning to caller */
4244 smb_Get8Dot3MaskFromPath(mask, pathp);
4246 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4247 tp = smb_GetSMBData(outp, NULL);
4249 *tp++ = 43; /* bytes in a dir entry */
4250 *tp++ = 0; /* high byte in counter */
4252 /* now marshall the dir entry, starting with the search status */
4253 *tp++ = statBlockp[0]; /* Reserved */
4254 memcpy(tp, mask, 11); tp += 11; /* FileName */
4256 /* now pass back server use info, with 1st byte non-zero */
4258 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4260 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4262 *tp++ = 0x8; /* attribute: volume */
4272 /* 4 byte file size */
4278 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4281 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4282 memset(tp, ' ', 13);
4285 /* set the length of the data part of the packet to 43 + 3, for the dir
4286 * entry plus the 5 and the length fields.
4288 smb_SetSMBDataLength(outp, 46);
4293 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4294 clientchar_t * tidPathp, clientchar_t * relPathp,
4295 cm_user_t *userp, cm_req_t *reqp)
4303 smb_dirListPatch_t *patchp;
4304 smb_dirListPatch_t *npatchp;
4305 clientchar_t path[AFSPATHMAX];
4307 afs_int32 mustFake = 0;
4309 code = cm_FindACLCache(dscp, userp, &rights);
4311 lock_ObtainWrite(&dscp->rw);
4312 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4313 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4314 lock_ReleaseWrite(&dscp->rw);
4315 if (code == CM_ERROR_NOACCESS) {
4323 if (!mustFake) { /* Bulk Stat */
4325 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4327 memset(bsp, 0, sizeof(cm_bulkStat_t));
4329 for (patchp = *dirPatchespp, count=0;
4331 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4332 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4336 if (lock_TryWrite(&tscp->rw)) {
4337 /* we have an entry that we can look at */
4338 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4339 /* we have a callback on it. Don't bother
4340 * fetching this stat entry, since we're happy
4341 * with the info we have.
4343 lock_ReleaseWrite(&tscp->rw);
4344 cm_ReleaseSCache(tscp);
4347 lock_ReleaseWrite(&tscp->rw);
4349 cm_ReleaseSCache(tscp);
4353 bsp->fids[i].Volume = patchp->fid.volume;
4354 bsp->fids[i].Vnode = patchp->fid.vnode;
4355 bsp->fids[i].Unique = patchp->fid.unique;
4357 if (bsp->counter == AFSCBMAX) {
4358 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4359 memset(bsp, 0, sizeof(cm_bulkStat_t));
4363 if (bsp->counter > 0)
4364 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4369 for (patchp = *dirPatchespp; patchp; patchp =
4370 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4372 dptr = patchp->dptr;
4374 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4375 relPathp ? relPathp : _C(""), patchp->dep->name);
4376 reqp->relPathp = path;
4377 reqp->tidPathp = tidPathp;
4379 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4380 reqp->relPathp = reqp->tidPathp = NULL;
4383 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4384 *dptr++ = SMB_ATTR_HIDDEN;
4387 lock_ObtainWrite(&scp->rw);
4388 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4389 lock_ReleaseWrite(&scp->rw);
4391 /* set the attribute */
4392 switch (scp->fileType) {
4393 case CM_SCACHETYPE_DIRECTORY:
4394 case CM_SCACHETYPE_MOUNTPOINT:
4395 case CM_SCACHETYPE_INVALID:
4396 attr = SMB_ATTR_DIRECTORY;
4398 case CM_SCACHETYPE_SYMLINK:
4399 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4400 attr = SMB_ATTR_DIRECTORY;
4402 attr = SMB_ATTR_NORMAL;
4405 /* if we get here we either have a normal file
4406 * or we have a file for which we have never
4407 * received status info. In this case, we can
4408 * check the even/odd value of the entry's vnode.
4409 * odd means it is to be treated as a directory
4410 * and even means it is to be treated as a file.
4412 if (mustFake && (scp->fid.vnode & 0x1))
4413 attr = SMB_ATTR_DIRECTORY;
4415 attr = SMB_ATTR_NORMAL;
4419 /* 1969-12-31 23:59:58 +00*/
4420 dosTime = 0xEBBFBF7D;
4423 shortTemp = (unsigned short) (dosTime & 0xffff);
4424 *((u_short *)dptr) = shortTemp;
4427 /* and copy out date */
4428 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4429 *((u_short *)dptr) = shortTemp;
4432 /* copy out file length */
4433 *((u_long *)dptr) = 0;
4436 lock_ConvertWToR(&scp->rw);
4437 attr = smb_Attributes(scp);
4438 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4439 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4440 attr |= SMB_ATTR_HIDDEN;
4444 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4447 shortTemp = (unsigned short) (dosTime & 0xffff);
4448 *((u_short *)dptr) = shortTemp;
4451 /* and copy out date */
4452 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4453 *((u_short *)dptr) = shortTemp;
4456 /* copy out file length */
4457 *((u_long *)dptr) = scp->length.LowPart;
4459 lock_ReleaseRead(&scp->rw);
4461 cm_ReleaseSCache(scp);
4464 /* now free the patches */
4465 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4466 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4470 /* and mark the list as empty */
4471 *dirPatchespp = NULL;
4477 /* SMB_COM_SEARCH */
4478 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4484 clientchar_t *pathp;
4485 cm_dirEntry_t *dep = 0;
4487 smb_dirListPatch_t *dirListPatchesp;
4488 smb_dirListPatch_t *curPatchp;
4492 osi_hyper_t dirLength;
4493 osi_hyper_t bufferOffset;
4494 osi_hyper_t curOffset;
4496 unsigned char *inCookiep;
4497 smb_dirSearch_t *dsp;
4501 unsigned long clientCookie;
4502 cm_pageHeader_t *pageHeaderp;
4503 cm_user_t *userp = NULL;
4505 clientchar_t mask[12];
4507 long nextEntryCookie;
4508 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4509 char resByte; /* reserved byte from the cookie */
4510 char *op; /* output data ptr */
4511 char *origOp; /* original value of op */
4512 cm_space_t *spacep; /* for pathname buffer */
4516 clientchar_t *tidPathp = 0;
4523 maxCount = smb_GetSMBParm(inp, 0);
4525 dirListPatchesp = NULL;
4527 caseFold = CM_FLAG_CASEFOLD;
4529 tp = smb_GetSMBData(inp, NULL);
4530 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4531 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4532 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4534 /* bail out if request looks bad */
4535 if (!tp || !pathp) {
4536 return CM_ERROR_BADSMB;
4539 /* We can handle long names */
4540 if (vcp->flags & SMB_VCFLAG_USENT)
4541 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4543 /* make sure we got a whole search status */
4544 if (dataLength < 21) {
4545 nextCookie = 0; /* start at the beginning of the dir */
4548 attribute = smb_GetSMBParm(inp, 1);
4550 /* handle volume info in another function */
4551 if (attribute & 0x8)
4552 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4554 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4555 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4557 if (*pathp == 0) { /* null pathp, treat as root dir */
4558 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4559 return CM_ERROR_NOFILES;
4563 dsp = smb_NewDirSearch(0);
4564 dsp->attribute = attribute;
4565 smb_Get8Dot3MaskFromPath(mask, pathp);
4566 memcpy(dsp->mask, mask, 12);
4568 /* track if this is likely to match a lot of entries */
4569 if (smb_IsStarMask(mask))
4574 /* pull the next cookie value out of the search status block */
4575 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4576 + (inCookiep[16]<<24);
4577 dsp = smb_FindDirSearch(inCookiep[12]);
4579 /* can't find dir search status; fatal error */
4580 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4581 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4582 return CM_ERROR_BADFD;
4584 attribute = dsp->attribute;
4585 resByte = inCookiep[0];
4587 /* copy out client cookie, in host byte order. Don't bother
4588 * interpreting it, since we're just passing it through, anyway.
4590 memcpy(&clientCookie, &inCookiep[17], 4);
4592 memcpy(mask, dsp->mask, 12);
4594 /* assume we're doing a star match if it has continued for more
4600 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4601 nextCookie, dsp->cookie, attribute);
4603 userp = smb_GetUserFromVCP(vcp, inp);
4605 /* try to get the vnode for the path name next */
4606 lock_ObtainMutex(&dsp->mx);
4609 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4613 spacep = inp->spacep;
4614 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4615 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4617 lock_ReleaseMutex(&dsp->mx);
4618 cm_ReleaseUser(userp);
4619 smb_DeleteDirSearch(dsp);
4620 smb_ReleaseDirSearch(dsp);
4621 return CM_ERROR_NOFILES;
4623 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4624 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4626 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4627 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4630 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4633 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4634 cm_ReleaseSCache(scp);
4635 lock_ReleaseMutex(&dsp->mx);
4636 cm_ReleaseUser(userp);
4637 smb_DeleteDirSearch(dsp);
4638 smb_ReleaseDirSearch(dsp);
4639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4640 return CM_ERROR_PATH_NOT_COVERED;
4642 return CM_ERROR_BADSHARENAME;
4644 #endif /* DFS_SUPPORT */
4647 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4648 /* we need one hold for the entry we just stored into,
4649 * and one for our own processing. When we're done with this
4650 * function, we'll drop the one for our own processing.
4651 * We held it once from the namei call, and so we do another hold
4655 lock_ObtainWrite(&scp->rw);
4656 dsp->flags |= SMB_DIRSEARCH_BULKST;
4657 lock_ReleaseWrite(&scp->rw);
4660 lock_ReleaseMutex(&dsp->mx);
4662 cm_ReleaseUser(userp);
4663 smb_DeleteDirSearch(dsp);
4664 smb_ReleaseDirSearch(dsp);
4668 /* reserves space for parameter; we'll adjust it again later to the
4669 * real count of the # of entries we returned once we've actually
4670 * assembled the directory listing.
4672 smb_SetSMBParm(outp, 0, 0);
4674 /* get the directory size */
4675 lock_ObtainWrite(&scp->rw);
4676 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4677 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4679 lock_ReleaseWrite(&scp->rw);
4680 cm_ReleaseSCache(scp);
4681 cm_ReleaseUser(userp);
4682 smb_DeleteDirSearch(dsp);
4683 smb_ReleaseDirSearch(dsp);
4687 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4689 dirLength = scp->length;
4691 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4692 curOffset.HighPart = 0;
4693 curOffset.LowPart = nextCookie;
4694 origOp = op = smb_GetSMBData(outp, NULL);
4695 /* and write out the basic header */
4696 *op++ = 5; /* variable block */
4697 op += 2; /* skip vbl block length; we'll fill it in later */
4701 clientchar_t *actualName = NULL;
4702 int free_actualName = 0;
4703 clientchar_t shortName[13];
4704 clientchar_t *shortNameEnd;
4706 /* make sure that curOffset.LowPart doesn't point to the first
4707 * 32 bytes in the 2nd through last dir page, and that it doesn't
4708 * point at the first 13 32-byte chunks in the first dir page,
4709 * since those are dir and page headers, and don't contain useful
4712 temp = curOffset.LowPart & (2048-1);
4713 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4714 /* we're in the first page */
4715 if (temp < 13*32) temp = 13*32;
4718 /* we're in a later dir page */
4719 if (temp < 32) temp = 32;
4722 /* make sure the low order 5 bits are zero */
4725 /* now put temp bits back ito curOffset.LowPart */
4726 curOffset.LowPart &= ~(2048-1);
4727 curOffset.LowPart |= temp;
4729 /* check if we've returned all the names that will fit in the
4732 if (returnedNames >= maxCount) {
4733 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4734 returnedNames, maxCount);
4738 /* check if we've passed the dir's EOF */
4739 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4741 /* see if we can use the bufferp we have now; compute in which page
4742 * the current offset would be, and check whether that's the offset
4743 * of the buffer we have. If not, get the buffer.
4745 thyper.HighPart = curOffset.HighPart;
4746 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4747 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4750 buf_Release(bufferp);
4753 lock_ReleaseWrite(&scp->rw);
4754 code = buf_Get(scp, &thyper, &bufferp);
4755 lock_ObtainMutex(&dsp->mx);
4757 /* now, if we're doing a star match, do bulk fetching of all of
4758 * the status info for files in the dir.
4761 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4763 lock_ObtainWrite(&scp->rw);
4764 lock_ReleaseMutex(&dsp->mx);
4766 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4770 bufferOffset = thyper;
4772 /* now get the data in the cache */
4774 code = cm_SyncOp(scp, bufferp, userp, &req,
4776 CM_SCACHESYNC_NEEDCALLBACK |
4777 CM_SCACHESYNC_READ);
4779 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4783 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4785 if (cm_HaveBuffer(scp, bufferp, 0)) {
4786 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4790 /* otherwise, load the buffer and try again */
4791 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4793 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4794 scp, bufferp, code);
4799 buf_Release(bufferp);
4803 } /* if (wrong buffer) ... */
4805 /* now we have the buffer containing the entry we're interested in; copy
4806 * it out if it represents a non-deleted entry.
4808 entryInDir = curOffset.LowPart & (2048-1);
4809 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4811 /* page header will help tell us which entries are free. Page header
4812 * can change more often than once per buffer, since AFS 3 dir page size
4813 * may be less than (but not more than a buffer package buffer.
4815 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4816 temp &= ~(2048 - 1); /* turn off intra-page bits */
4817 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4819 /* now determine which entry we're looking at in the page. If it is
4820 * free (there's a free bitmap at the start of the dir), we should
4821 * skip these 32 bytes.
4823 slotInPage = (entryInDir & 0x7e0) >> 5;
4824 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4825 /* this entry is free */
4826 numDirChunks = 1; /* only skip this guy */
4830 tp = bufferp->datap + entryInBuffer;
4831 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4833 /* while we're here, compute the next entry's location, too,
4834 * since we'll need it when writing out the cookie into the dir
4837 * XXXX Probably should do more sanity checking.
4839 numDirChunks = cm_NameEntries(dep->name, NULL);
4841 /* compute the offset of the cookie representing the next entry */
4842 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4844 /* Compute 8.3 name if necessary */
4845 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4846 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4849 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4850 actualName = shortName;
4851 free_actualName = 0;
4853 free_actualName = 1;
4856 if (actualName == NULL) {
4857 /* Couldn't convert the name for some reason */
4858 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4859 osi_LogSaveString(smb_logp, dep->name));
4863 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4864 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4865 osi_LogSaveClientString(smb_logp, actualName));
4867 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4868 /* this is one of the entries to use: it is not deleted
4869 * and it matches the star pattern we're looking for.
4872 /* Eliminate entries that don't match requested
4875 /* no hidden files */
4876 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4877 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4881 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4883 /* We have already done the cm_TryBulkStat above */
4884 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4885 fileType = cm_FindFileType(&fid);
4886 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4887 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4889 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4890 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4891 fileType == CM_SCACHETYPE_DFSLINK ||
4892 fileType == CM_SCACHETYPE_INVALID)
4893 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4898 memcpy(op, mask, 11); op += 11;
4899 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4900 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4901 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4902 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4903 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4904 memcpy(op, &clientCookie, 4); op += 4;
4906 /* now we emit the attribute. This is sort of tricky,
4907 * since we need to really stat the file to find out
4908 * what type of entry we've got. Right now, we're
4909 * copying out data from a buffer, while holding the
4910 * scp locked, so it isn't really convenient to stat
4911 * something now. We'll put in a place holder now,
4912 * and make a second pass before returning this to get
4913 * the real attributes. So, we just skip the data for
4914 * now, and adjust it later. We allocate a patch
4915 * record to make it easy to find this point later.
4916 * The replay will happen at a time when it is safe to
4917 * unlock the directory.
4919 curPatchp = malloc(sizeof(*curPatchp));
4920 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4921 curPatchp->dptr = op;
4922 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4924 /* do hidden attribute here since name won't be around when applying
4928 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4929 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4931 curPatchp->flags = 0;
4933 op += 9; /* skip attr, time, date and size */
4935 /* zero out name area. The spec says to pad with
4936 * spaces, but Samba doesn't, and neither do we.
4940 /* finally, we get to copy out the name; we know that
4941 * it fits in 8.3 or the pattern wouldn't match, but it
4942 * never hurts to be sure.
4944 cm_ClientStringToUtf8(actualName, -1, op, 13);
4945 if (smb_StoreAnsiFilenames)
4947 /* This is a UCHAR field, which is ASCII even if Unicode
4950 /* Uppercase if requested by client */
4951 if (!KNOWS_LONG_NAMES(inp))
4956 /* now, adjust the # of entries copied */
4958 } /* if we're including this name */
4961 if (free_actualName && actualName) {
4966 /* and adjust curOffset to be where the new cookie is */
4967 thyper.HighPart = 0;
4968 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4969 curOffset = LargeIntegerAdd(thyper, curOffset);
4970 } /* while copying data for dir listing */
4972 /* release the mutex */
4973 lock_ReleaseWrite(&scp->rw);
4975 buf_Release(bufferp);
4979 /* apply and free last set of patches; if not doing a star match, this
4980 * will be empty, but better safe (and freeing everything) than sorry.
4982 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4984 /* special return code for unsuccessful search */
4985 if (code == 0 && dataLength < 21 && returnedNames == 0)
4986 code = CM_ERROR_NOFILES;
4988 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4989 returnedNames, code);
4992 smb_DeleteDirSearch(dsp);
4993 smb_ReleaseDirSearch(dsp);
4994 cm_ReleaseSCache(scp);
4995 cm_ReleaseUser(userp);
4999 /* finalize the output buffer */
5000 smb_SetSMBParm(outp, 0, returnedNames);
5001 temp = (long) (op - origOp);
5002 smb_SetSMBDataLength(outp, temp);
5004 /* the data area is a variable block, which has a 5 (already there)
5005 * followed by the length of the # of data bytes. We now know this to
5006 * be "temp," although that includes the 3 bytes of vbl block header.
5007 * Deduct for them and fill in the length field.
5009 temp -= 3; /* deduct vbl block info */
5010 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5011 origOp[1] = (unsigned char)(temp & 0xff);
5012 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5013 if (returnedNames == 0)
5014 smb_DeleteDirSearch(dsp);
5015 smb_ReleaseDirSearch(dsp);
5016 cm_ReleaseSCache(scp);
5017 cm_ReleaseUser(userp);
5022 /* verify that this is a valid path to a directory. I don't know why they
5023 * don't use the get file attributes call.
5025 * SMB_COM_CHECK_DIRECTORY
5027 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5029 clientchar_t *pathp;
5031 cm_scache_t *rootScp;
5032 cm_scache_t *newScp;
5036 clientchar_t *tidPathp;
5042 pdata = smb_GetSMBData(inp, NULL);
5043 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5045 return CM_ERROR_BADFD;
5046 osi_Log1(smb_logp, "SMB receive check path %S",
5047 osi_LogSaveClientString(smb_logp, pathp));
5049 rootScp = cm_data.rootSCachep;
5051 userp = smb_GetUserFromVCP(vcp, inp);
5053 caseFold = CM_FLAG_CASEFOLD;
5055 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5057 cm_ReleaseUser(userp);
5058 return CM_ERROR_NOSUCHPATH;
5060 code = cm_NameI(rootScp, pathp,
5061 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5062 userp, tidPathp, &req, &newScp);
5065 cm_ReleaseUser(userp);
5070 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5071 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5072 cm_ReleaseSCache(newScp);
5073 cm_ReleaseUser(userp);
5074 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5075 return CM_ERROR_PATH_NOT_COVERED;
5077 return CM_ERROR_BADSHARENAME;
5079 #endif /* DFS_SUPPORT */
5081 /* now lock the vnode with a callback; returns with newScp locked */
5082 lock_ObtainWrite(&newScp->rw);
5083 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5084 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5086 if (code != CM_ERROR_NOACCESS) {
5087 lock_ReleaseWrite(&newScp->rw);
5088 cm_ReleaseSCache(newScp);
5089 cm_ReleaseUser(userp);
5093 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5096 attrs = smb_Attributes(newScp);
5098 if (!(attrs & SMB_ATTR_DIRECTORY))
5099 code = CM_ERROR_NOTDIR;
5101 lock_ReleaseWrite(&newScp->rw);
5103 cm_ReleaseSCache(newScp);
5104 cm_ReleaseUser(userp);
5108 /* SMB_COM_SET_INFORMATION */
5109 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5111 clientchar_t *pathp;
5113 cm_scache_t *rootScp;
5114 unsigned short attribute;
5116 cm_scache_t *newScp;
5120 clientchar_t *tidPathp;
5126 /* decode basic attributes we're passed */
5127 attribute = smb_GetSMBParm(inp, 0);
5128 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5130 datap = smb_GetSMBData(inp, NULL);
5131 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5133 return CM_ERROR_BADSMB;
5135 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5136 dosTime, attribute);
5138 rootScp = cm_data.rootSCachep;
5140 userp = smb_GetUserFromVCP(vcp, inp);
5142 caseFold = CM_FLAG_CASEFOLD;
5144 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5146 cm_ReleaseUser(userp);
5147 return CM_ERROR_NOSUCHFILE;
5149 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5150 tidPathp, &req, &newScp);
5153 cm_ReleaseUser(userp);
5158 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5159 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5160 cm_ReleaseSCache(newScp);
5161 cm_ReleaseUser(userp);
5162 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5163 return CM_ERROR_PATH_NOT_COVERED;
5165 return CM_ERROR_BADSHARENAME;
5167 #endif /* DFS_SUPPORT */
5169 /* now lock the vnode with a callback; returns with newScp locked; we
5170 * need the current status to determine what the new status is, in some
5173 lock_ObtainWrite(&newScp->rw);
5174 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5175 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5177 lock_ReleaseWrite(&newScp->rw);
5178 cm_ReleaseSCache(newScp);
5179 cm_ReleaseUser(userp);
5183 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5185 /* Check for RO volume */
5186 if (newScp->flags & CM_SCACHEFLAG_RO) {
5187 lock_ReleaseWrite(&newScp->rw);
5188 cm_ReleaseSCache(newScp);
5189 cm_ReleaseUser(userp);
5190 return CM_ERROR_READONLY;
5193 /* prepare for setattr call */
5196 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5197 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5199 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5200 /* we're told to make a writable file read-only */
5201 attr.unixModeBits = newScp->unixModeBits & ~0222;
5202 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5204 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5205 /* we're told to make a read-only file writable */
5206 attr.unixModeBits = newScp->unixModeBits | 0222;
5207 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5209 lock_ReleaseWrite(&newScp->rw);
5211 /* now call setattr */
5213 code = cm_SetAttr(newScp, &attr, userp, &req);
5217 cm_ReleaseSCache(newScp);
5218 cm_ReleaseUser(userp);
5224 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5226 clientchar_t *pathp;
5228 cm_scache_t *rootScp;
5229 cm_scache_t *newScp, *dscp;
5234 clientchar_t *tidPathp;
5236 clientchar_t *lastComp;
5242 datap = smb_GetSMBData(inp, NULL);
5243 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5245 return CM_ERROR_BADSMB;
5247 if (*pathp == 0) /* null path */
5250 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5251 osi_LogSaveClientString(smb_logp, pathp));
5253 rootScp = cm_data.rootSCachep;
5255 userp = smb_GetUserFromVCP(vcp, inp);
5257 /* we shouldn't need this for V3 requests, but we seem to */
5258 caseFold = CM_FLAG_CASEFOLD;
5260 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5262 cm_ReleaseUser(userp);
5263 return CM_ERROR_NOSUCHFILE;
5267 * XXX Strange hack XXX
5269 * As of Patch 5 (16 July 97), we are having the following problem:
5270 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5271 * requests to look up "desktop.ini" in all the subdirectories.
5272 * This can cause zillions of timeouts looking up non-existent cells
5273 * and volumes, especially in the top-level directory.
5275 * We have not found any way to avoid this or work around it except
5276 * to explicitly ignore the requests for mount points that haven't
5277 * yet been evaluated and for directories that haven't yet been
5280 * We should modify this hack to provide a fake desktop.ini file
5281 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5283 spacep = inp->spacep;
5284 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5285 #ifndef SPECIAL_FOLDERS
5286 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5287 code = cm_NameI(rootScp, spacep->wdata,
5288 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5289 userp, tidPathp, &req, &dscp);
5292 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5293 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5295 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5296 return CM_ERROR_PATH_NOT_COVERED;
5298 return CM_ERROR_BADSHARENAME;
5300 #endif /* DFS_SUPPORT */
5301 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5302 code = CM_ERROR_NOSUCHFILE;
5303 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5304 cm_buf_t *bp = buf_Find(dscp, &hzero);
5309 code = CM_ERROR_NOSUCHFILE;
5311 cm_ReleaseSCache(dscp);
5313 cm_ReleaseUser(userp);
5318 #endif /* SPECIAL_FOLDERS */
5320 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5321 tidPathp, &req, &newScp);
5323 cm_ReleaseUser(userp);
5328 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5329 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5330 cm_ReleaseSCache(newScp);
5331 cm_ReleaseUser(userp);
5332 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5333 return CM_ERROR_PATH_NOT_COVERED;
5335 return CM_ERROR_BADSHARENAME;
5337 #endif /* DFS_SUPPORT */
5339 /* now lock the vnode with a callback; returns with newScp locked */
5340 lock_ObtainWrite(&newScp->rw);
5341 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5342 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5344 lock_ReleaseWrite(&newScp->rw);
5345 cm_ReleaseSCache(newScp);
5346 cm_ReleaseUser(userp);
5350 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5352 attrs = smb_Attributes(newScp);
5354 smb_SetSMBParm(outp, 0, attrs);
5356 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5357 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5358 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5359 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5360 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5361 smb_SetSMBParm(outp, 5, 0);
5362 smb_SetSMBParm(outp, 6, 0);
5363 smb_SetSMBParm(outp, 7, 0);
5364 smb_SetSMBParm(outp, 8, 0);
5365 smb_SetSMBParm(outp, 9, 0);
5366 smb_SetSMBDataLength(outp, 0);
5367 lock_ReleaseWrite(&newScp->rw);
5369 cm_ReleaseSCache(newScp);
5370 cm_ReleaseUser(userp);
5375 /* SMB_COM_TREE_DISCONNECT */
5376 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5380 osi_Log0(smb_logp, "SMB receive tree disconnect");
5382 /* find the tree and free it */
5383 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5385 lock_ObtainWrite(&smb_rctLock);
5387 smb_ReleaseTID(tidp, TRUE);
5388 lock_ReleaseWrite(&smb_rctLock);
5395 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5398 clientchar_t *pathp;
5399 clientchar_t *lastNamep;
5408 clientchar_t *tidPathp;
5414 datap = smb_GetSMBData(inp, NULL);
5415 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5417 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5419 #ifdef DEBUG_VERBOSE
5423 hexpath = osi_HexifyString( pathp );
5424 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5429 if (!cm_IsValidClientString(pathp)) {
5431 clientchar_t * hexp;
5433 hexp = cm_GetRawCharsAlloc(pathp, -1);
5434 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5435 osi_LogSaveClientString(smb_logp, hexp));
5439 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5441 return CM_ERROR_BADNTFILENAME;
5444 share = smb_GetSMBParm(inp, 0);
5445 attribute = smb_GetSMBParm(inp, 1);
5447 spacep = inp->spacep;
5448 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5449 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5450 /* special case magic file name for receiving IOCTL requests
5451 * (since IOCTL calls themselves aren't getting through).
5453 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5454 smb_SetupIoctlFid(fidp, spacep);
5455 smb_SetSMBParm(outp, 0, fidp->fid);
5456 smb_SetSMBParm(outp, 1, 0); /* attrs */
5457 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5458 smb_SetSMBParm(outp, 3, 0);
5459 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5460 smb_SetSMBParm(outp, 5, 0x7fff);
5461 /* pass the open mode back */
5462 smb_SetSMBParm(outp, 6, (share & 0xf));
5463 smb_SetSMBDataLength(outp, 0);
5464 smb_ReleaseFID(fidp);
5468 userp = smb_GetUserFromVCP(vcp, inp);
5470 caseFold = CM_FLAG_CASEFOLD;
5472 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5474 cm_ReleaseUser(userp);
5475 return CM_ERROR_NOSUCHPATH;
5477 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5478 tidPathp, &req, &scp);
5481 cm_ReleaseUser(userp);
5486 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5487 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5488 cm_ReleaseSCache(scp);
5489 cm_ReleaseUser(userp);
5490 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5491 return CM_ERROR_PATH_NOT_COVERED;
5493 return CM_ERROR_BADSHARENAME;
5495 #endif /* DFS_SUPPORT */
5497 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5499 cm_ReleaseSCache(scp);
5500 cm_ReleaseUser(userp);
5504 /* don't need callback to check file type, since file types never
5505 * change, and namei and cm_Lookup all stat the object at least once on
5506 * a successful return.
5508 if (scp->fileType != CM_SCACHETYPE_FILE) {
5509 cm_ReleaseSCache(scp);
5510 cm_ReleaseUser(userp);
5511 return CM_ERROR_ISDIR;
5514 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5515 osi_assertx(fidp, "null smb_fid_t");
5517 /* save a pointer to the vnode */
5519 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5520 lock_ObtainWrite(&scp->rw);
5521 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5522 lock_ReleaseWrite(&scp->rw);
5526 fidp->userp = userp;
5528 lock_ObtainMutex(&fidp->mx);
5529 if ((share & 0xf) == 0)
5530 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5531 else if ((share & 0xf) == 1)
5532 fidp->flags |= SMB_FID_OPENWRITE;
5534 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5535 lock_ReleaseMutex(&fidp->mx);
5537 lock_ObtainRead(&scp->rw);
5538 smb_SetSMBParm(outp, 0, fidp->fid);
5539 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5540 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5541 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5542 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5543 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5544 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5545 /* pass the open mode back; XXXX add access checks */
5546 smb_SetSMBParm(outp, 6, (share & 0xf));
5547 smb_SetSMBDataLength(outp, 0);
5548 lock_ReleaseRead(&scp->rw);
5551 cm_Open(scp, 0, userp);
5553 /* send and free packet */
5554 smb_ReleaseFID(fidp);
5555 cm_ReleaseUser(userp);
5556 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5560 typedef struct smb_unlinkRock {
5565 clientchar_t *maskp; /* pointer to the star pattern */
5568 cm_dirEntryList_t * matches;
5571 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5574 smb_unlinkRock_t *rockp;
5577 normchar_t matchName[MAX_PATH];
5581 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5582 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5583 caseFold |= CM_FLAG_8DOT3;
5585 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5586 /* Can't convert name */
5587 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5588 osi_LogSaveString(smb_logp, dep->name));
5592 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5594 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5595 !cm_Is8Dot3(matchName)) {
5596 cm_Gen8Dot3Name(dep, matchName, NULL);
5597 /* 8.3 matches are always case insensitive */
5598 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5601 osi_Log1(smb_logp, "Found match %S",
5602 osi_LogSaveClientString(smb_logp, matchName));
5604 cm_DirEntryListAdd(dep->name, &rockp->matches);
5608 /* If we made a case sensitive exact match, we might as well quit now. */
5609 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5610 code = CM_ERROR_STOPNOW;
5619 /* SMB_COM_DELETE */
5620 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5624 clientchar_t *pathp;
5628 clientchar_t *lastNamep;
5629 smb_unlinkRock_t rock;
5633 clientchar_t *tidPathp;
5637 memset(&rock, 0, sizeof(rock));
5639 attribute = smb_GetSMBParm(inp, 0);
5641 tp = smb_GetSMBData(inp, NULL);
5642 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5644 osi_Log1(smb_logp, "SMB receive unlink %S",
5645 osi_LogSaveClientString(smb_logp, pathp));
5647 spacep = inp->spacep;
5648 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5650 userp = smb_GetUserFromVCP(vcp, inp);
5652 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5654 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5656 cm_ReleaseUser(userp);
5657 return CM_ERROR_NOSUCHPATH;
5659 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5662 cm_ReleaseUser(userp);
5667 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5668 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5669 cm_ReleaseSCache(dscp);
5670 cm_ReleaseUser(userp);
5671 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5672 return CM_ERROR_PATH_NOT_COVERED;
5674 return CM_ERROR_BADSHARENAME;
5676 #endif /* DFS_SUPPORT */
5678 /* otherwise, scp points to the parent directory. */
5685 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5687 code = CM_ERROR_NOSUCHFILE;
5690 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5693 thyper.HighPart = 0;
5698 rock.matches = NULL;
5700 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5701 * match. If that fails, we do a case insensitve match.
5703 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5704 !smb_IsStarMask(rock.maskp)) {
5705 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5708 thyper.HighPart = 0;
5709 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5714 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5716 if (code == CM_ERROR_STOPNOW)
5719 if (code == 0 && rock.matches) {
5720 cm_dirEntryList_t * entry;
5722 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5723 normchar_t normalizedName[MAX_PATH];
5725 /* Note: entry->name is a non-normalized name */
5727 osi_Log1(smb_logp, "Unlinking %s",
5728 osi_LogSaveString(smb_logp, entry->name));
5730 /* We assume this works because entry->name was
5731 successfully converted in smb_UnlinkProc() once. */
5732 cm_FsStringToNormString(entry->name, -1,
5733 normalizedName, lengthof(normalizedName));
5735 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5737 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5738 smb_NotifyChange(FILE_ACTION_REMOVED,
5739 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5740 dscp, normalizedName, NULL, TRUE);
5744 cm_DirEntryListFree(&rock.matches);
5748 cm_ReleaseUser(userp);
5751 cm_ReleaseSCache(dscp);
5756 if (code == 0 && !rock.any)
5757 code = CM_ERROR_NOSUCHFILE;
5761 typedef struct smb_renameRock {
5762 cm_scache_t *odscp; /* old dir */
5763 cm_scache_t *ndscp; /* new dir */
5764 cm_user_t *userp; /* user */
5765 cm_req_t *reqp; /* request struct */
5766 smb_vc_t *vcp; /* virtual circuit */
5767 normchar_t *maskp; /* pointer to star pattern of old file name */
5768 int flags; /* tilde, casefold, etc */
5769 clientchar_t *newNamep; /* ptr to the new file's name */
5770 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5771 clientchar_t clOldName[MAX_PATH]; /* client name */
5775 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5778 smb_renameRock_t *rockp;
5781 normchar_t matchName[MAX_PATH];
5783 rockp = (smb_renameRock_t *) vrockp;
5785 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5786 /* Can't convert string */
5787 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5788 osi_LogSaveString(smb_logp, dep->name));
5792 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5793 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5794 caseFold |= CM_FLAG_8DOT3;
5796 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5798 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5799 !cm_Is8Dot3(matchName)) {
5800 cm_Gen8Dot3Name(dep, matchName, NULL);
5801 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5806 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5807 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5809 code = CM_ERROR_STOPNOW;
5819 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5822 cm_space_t *spacep = NULL;
5823 smb_renameRock_t rock;
5824 cm_scache_t *oldDscp = NULL;
5825 cm_scache_t *newDscp = NULL;
5826 cm_scache_t *tmpscp= NULL;
5827 cm_scache_t *tmpscp2 = NULL;
5828 clientchar_t *oldLastNamep;
5829 clientchar_t *newLastNamep;
5833 clientchar_t *tidPathp;
5837 userp = smb_GetUserFromVCP(vcp, inp);
5838 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5840 cm_ReleaseUser(userp);
5841 return CM_ERROR_NOSUCHPATH;
5845 memset(&rock, 0, sizeof(rock));
5847 spacep = inp->spacep;
5848 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5850 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5851 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5852 userp, tidPathp, &req, &oldDscp);
5854 cm_ReleaseUser(userp);
5859 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5860 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5861 cm_ReleaseSCache(oldDscp);
5862 cm_ReleaseUser(userp);
5863 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5864 return CM_ERROR_PATH_NOT_COVERED;
5866 return CM_ERROR_BADSHARENAME;
5868 #endif /* DFS_SUPPORT */
5870 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5871 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5872 userp, tidPathp, &req, &newDscp);
5875 cm_ReleaseSCache(oldDscp);
5876 cm_ReleaseUser(userp);
5881 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5882 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5883 cm_ReleaseSCache(oldDscp);
5884 cm_ReleaseSCache(newDscp);
5885 cm_ReleaseUser(userp);
5886 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5887 return CM_ERROR_PATH_NOT_COVERED;
5889 return CM_ERROR_BADSHARENAME;
5891 #endif /* DFS_SUPPORT */
5894 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5895 * next, get the component names, and lower case them.
5898 /* handle the old name first */
5900 oldLastNamep = oldPathp;
5904 /* and handle the new name, too */
5906 newLastNamep = newPathp;
5910 /* TODO: The old name could be a wildcard. The new name must not be */
5912 /* Check if the file already exists; if so return error */
5913 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5914 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5915 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5917 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5918 osi_LogSaveClientString(smb_logp, newLastNamep));
5920 /* Check if the old and the new names differ only in case. If so return
5921 * success, else return CM_ERROR_EXISTS
5923 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5925 /* This would be a success only if the old file is *as same as* the new file */
5926 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5928 if (tmpscp == tmpscp2)
5931 code = CM_ERROR_EXISTS;
5932 cm_ReleaseSCache(tmpscp2);
5935 code = CM_ERROR_NOSUCHFILE;
5938 /* file exist, do not rename, also fixes move */
5939 osi_Log0(smb_logp, "Can't rename. Target already exists");
5940 code = CM_ERROR_EXISTS;
5945 /* do the vnode call */
5946 rock.odscp = oldDscp;
5947 rock.ndscp = newDscp;
5951 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5953 code = CM_ERROR_NOSUCHFILE;
5956 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5957 rock.newNamep = newLastNamep;
5958 rock.fsOldName[0] = '\0';
5959 rock.clOldName[0] = '\0';
5962 /* Now search the directory for the pattern, and do the appropriate rename when found */
5963 thyper.LowPart = 0; /* search dir from here */
5964 thyper.HighPart = 0;
5966 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5967 if (code == 0 && !rock.any) {
5969 thyper.HighPart = 0;
5970 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5971 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5973 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5975 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5976 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5977 rock.ndscp, rock.newNamep, rock.userp,
5979 /* if the call worked, stop doing the search now, since we
5980 * really only want to rename one file.
5983 osi_Log0(smb_logp, "cm_Rename failure");
5984 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5985 } else if (code == 0) {
5986 code = CM_ERROR_NOSUCHFILE;
5989 /* Handle Change Notification */
5991 * Being lazy, not distinguishing between files and dirs in this
5992 * filter, since we'd have to do a lookup.
5995 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5996 if (oldDscp == newDscp) {
5997 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5998 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5999 filter, oldDscp, rock.clOldName,
6000 newLastNamep, TRUE);
6002 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6003 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6004 filter, oldDscp, rock.clOldName,
6006 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6007 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6008 filter, newDscp, newLastNamep,
6015 cm_ReleaseSCache(tmpscp);
6017 cm_ReleaseUser(userp);
6019 cm_ReleaseSCache(oldDscp);
6021 cm_ReleaseSCache(newDscp);
6029 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6032 cm_space_t *spacep = NULL;
6033 cm_scache_t *oldDscp = NULL;
6034 cm_scache_t *newDscp = NULL;
6035 cm_scache_t *tmpscp= NULL;
6036 cm_scache_t *tmpscp2 = NULL;
6037 cm_scache_t *sscp = NULL;
6038 clientchar_t *oldLastNamep;
6039 clientchar_t *newLastNamep;
6042 clientchar_t *tidPathp;
6046 userp = smb_GetUserFromVCP(vcp, inp);
6048 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6050 cm_ReleaseUser(userp);
6051 return CM_ERROR_NOSUCHPATH;
6056 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6058 spacep = inp->spacep;
6059 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6061 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6062 userp, tidPathp, &req, &oldDscp);
6064 cm_ReleaseUser(userp);
6069 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6070 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6071 cm_ReleaseSCache(oldDscp);
6072 cm_ReleaseUser(userp);
6073 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6074 return CM_ERROR_PATH_NOT_COVERED;
6076 return CM_ERROR_BADSHARENAME;
6078 #endif /* DFS_SUPPORT */
6080 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6081 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6082 userp, tidPathp, &req, &newDscp);
6084 cm_ReleaseSCache(oldDscp);
6085 cm_ReleaseUser(userp);
6090 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6091 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6092 cm_ReleaseSCache(newDscp);
6093 cm_ReleaseSCache(oldDscp);
6094 cm_ReleaseUser(userp);
6095 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6096 return CM_ERROR_PATH_NOT_COVERED;
6098 return CM_ERROR_BADSHARENAME;
6100 #endif /* DFS_SUPPORT */
6102 /* Now, although we did two lookups for the two directories (because the same
6103 * directory can be referenced through different paths), we only allow hard links
6104 * within the same directory. */
6105 if (oldDscp != newDscp) {
6106 cm_ReleaseSCache(oldDscp);
6107 cm_ReleaseSCache(newDscp);
6108 cm_ReleaseUser(userp);
6109 return CM_ERROR_CROSSDEVLINK;
6112 /* handle the old name first */
6114 oldLastNamep = oldPathp;
6118 /* and handle the new name, too */
6120 newLastNamep = newPathp;
6124 /* now lookup the old name */
6125 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6126 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6128 cm_ReleaseSCache(oldDscp);
6129 cm_ReleaseSCache(newDscp);
6130 cm_ReleaseUser(userp);
6134 /* Check if the file already exists; if so return error */
6135 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6136 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6137 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6139 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6140 osi_LogSaveClientString(smb_logp, newLastNamep));
6142 /* if the existing link is to the same file, then we return success */
6144 if(sscp == tmpscp) {
6147 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6148 code = CM_ERROR_EXISTS;
6153 cm_ReleaseSCache(tmpscp);
6154 cm_ReleaseSCache(sscp);
6155 cm_ReleaseSCache(newDscp);
6156 cm_ReleaseSCache(oldDscp);
6157 cm_ReleaseUser(userp);
6161 /* now create the hardlink */
6162 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6163 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6164 osi_Log1(smb_logp," Link returns 0x%x", code);
6166 /* Handle Change Notification */
6168 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6169 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6170 smb_NotifyChange(FILE_ACTION_ADDED,
6171 filter, newDscp, newLastNamep,
6176 cm_ReleaseSCache(tmpscp);
6177 cm_ReleaseUser(userp);
6178 cm_ReleaseSCache(sscp);
6179 cm_ReleaseSCache(oldDscp);
6180 cm_ReleaseSCache(newDscp);
6184 /* SMB_COM_RENAME */
6186 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6188 clientchar_t *oldPathp;
6189 clientchar_t *newPathp;
6193 tp = smb_GetSMBData(inp, NULL);
6194 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6195 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6197 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6198 osi_LogSaveClientString(smb_logp, oldPathp),
6199 osi_LogSaveClientString(smb_logp, newPathp));
6201 if (!cm_IsValidClientString(newPathp)) {
6203 clientchar_t * hexp;
6205 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6206 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6207 osi_LogSaveClientString(smb_logp, hexp));
6211 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6213 return CM_ERROR_BADNTFILENAME;
6216 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6218 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6224 typedef struct smb_rmdirRock {
6228 normchar_t *maskp; /* pointer to the star pattern */
6231 cm_dirEntryList_t * matches;
6234 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6237 smb_rmdirRock_t *rockp;
6239 normchar_t matchName[MAX_PATH];
6241 rockp = (smb_rmdirRock_t *) vrockp;
6243 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6244 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6245 osi_LogSaveString(smb_logp, dep->name));
6249 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6250 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6252 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6254 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6255 !cm_Is8Dot3(matchName)) {
6256 cm_Gen8Dot3Name(dep, matchName, NULL);
6257 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6262 cm_DirEntryListAdd(dep->name, &rockp->matches);
6269 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6272 clientchar_t *pathp;
6276 clientchar_t *lastNamep;
6277 smb_rmdirRock_t rock;
6281 clientchar_t *tidPathp;
6285 memset(&rock, 0, sizeof(rock));
6287 tp = smb_GetSMBData(inp, NULL);
6288 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6290 spacep = inp->spacep;
6291 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6293 userp = smb_GetUserFromVCP(vcp, inp);
6295 caseFold = CM_FLAG_CASEFOLD;
6297 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6299 cm_ReleaseUser(userp);
6300 return CM_ERROR_NOSUCHPATH;
6302 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6303 userp, tidPathp, &req, &dscp);
6306 cm_ReleaseUser(userp);
6311 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6312 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6313 cm_ReleaseSCache(dscp);
6314 cm_ReleaseUser(userp);
6315 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6316 return CM_ERROR_PATH_NOT_COVERED;
6318 return CM_ERROR_BADSHARENAME;
6320 #endif /* DFS_SUPPORT */
6322 /* otherwise, scp points to the parent directory. */
6329 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6331 code = CM_ERROR_NOSUCHFILE;
6334 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6337 thyper.HighPart = 0;
6341 rock.matches = NULL;
6343 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6344 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6345 if (code == 0 && !rock.any) {
6347 thyper.HighPart = 0;
6348 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6349 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6352 if (code == 0 && rock.matches) {
6353 cm_dirEntryList_t * entry;
6355 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6356 clientchar_t clientName[MAX_PATH];
6358 /* We assume this will succeed because smb_RmdirProc()
6359 successfully converted entry->name once above. */
6360 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6362 osi_Log1(smb_logp, "Removing directory %s",
6363 osi_LogSaveString(smb_logp, entry->name));
6365 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6367 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6368 smb_NotifyChange(FILE_ACTION_REMOVED,
6369 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6370 dscp, clientName, NULL, TRUE);
6376 cm_DirEntryListFree(&rock.matches);
6379 cm_ReleaseUser(userp);
6382 cm_ReleaseSCache(dscp);
6384 if (code == 0 && !rock.any)
6385 code = CM_ERROR_NOSUCHFILE;
6394 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6404 fid = smb_GetSMBParm(inp, 0);
6406 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6408 fid = smb_ChainFID(fid, inp);
6409 fidp = smb_FindFID(vcp, fid, 0);
6411 return CM_ERROR_BADFD;
6413 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6414 smb_CloseFID(vcp, fidp, NULL, 0);
6415 smb_ReleaseFID(fidp);
6416 return CM_ERROR_NOSUCHFILE;
6419 lock_ObtainMutex(&fidp->mx);
6420 if (fidp->flags & SMB_FID_IOCTL) {
6421 lock_ReleaseMutex(&fidp->mx);
6422 smb_ReleaseFID(fidp);
6423 return CM_ERROR_BADFD;
6425 lock_ReleaseMutex(&fidp->mx);
6427 userp = smb_GetUserFromVCP(vcp, inp);
6429 lock_ObtainMutex(&fidp->mx);
6430 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6431 cm_scache_t * scp = fidp->scp;
6433 lock_ReleaseMutex(&fidp->mx);
6434 code = cm_FSync(scp, userp, &req);
6435 cm_ReleaseSCache(scp);
6438 lock_ReleaseMutex(&fidp->mx);
6441 smb_ReleaseFID(fidp);
6443 cm_ReleaseUser(userp);
6448 struct smb_FullNameRock {
6451 clientchar_t *fullName;
6452 fschar_t *originalName;
6455 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6458 normchar_t matchName[MAX_PATH];
6459 struct smb_FullNameRock *vrockp;
6461 vrockp = (struct smb_FullNameRock *)rockp;
6463 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6464 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6465 osi_LogSaveString(smb_logp, dep->name));
6469 if (!cm_Is8Dot3(matchName)) {
6470 clientchar_t shortName[13];
6472 cm_Gen8Dot3Name(dep, shortName, NULL);
6474 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6475 vrockp->fullName = cm_ClientStrDup(matchName);
6476 vrockp->originalName = cm_FsStrDup(dep->name);
6477 return CM_ERROR_STOPNOW;
6480 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6481 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6482 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6483 vrockp->fullName = cm_ClientStrDup(matchName);
6484 vrockp->originalName = cm_FsStrDup(dep->name);
6485 return CM_ERROR_STOPNOW;
6490 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6491 clientchar_t **newPathp, fschar_t ** originalPathp,
6492 cm_user_t *userp, cm_req_t *reqp)
6494 struct smb_FullNameRock rock;
6497 memset(&rock, 0, sizeof(rock));
6501 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6502 if (code == CM_ERROR_STOPNOW) {
6503 *newPathp = rock.fullName;
6504 *originalPathp = rock.originalName;
6506 *newPathp = cm_ClientStrDup(pathp);
6507 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6511 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6512 afs_uint32 dosTime) {
6515 cm_scache_t *dscp = NULL;
6516 clientchar_t *pathp = NULL;
6517 cm_scache_t * scp = NULL;
6518 cm_scache_t *delscp = NULL;
6519 int nullcreator = 0;
6521 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6522 fidp, fidp->fid, scp, vcp);
6525 lock_ObtainMutex(&fidp->mx);
6526 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6527 lock_ReleaseMutex(&fidp->mx);
6528 osi_Log0(smb_logp, " No user specified. Not closing fid");
6529 return CM_ERROR_BADFD;
6532 userp = fidp->userp; /* no hold required since fidp is held
6533 throughout the function */
6534 lock_ReleaseMutex(&fidp->mx);
6539 lock_ObtainWrite(&smb_rctLock);
6540 if (fidp->deleteOk) {
6541 osi_Log0(smb_logp, " Fid already closed.");
6542 lock_ReleaseWrite(&smb_rctLock);
6543 return CM_ERROR_BADFD;
6546 lock_ReleaseWrite(&smb_rctLock);
6548 lock_ObtainMutex(&fidp->mx);
6549 if (fidp->NTopen_dscp) {
6550 dscp = fidp->NTopen_dscp;
6551 cm_HoldSCache(dscp);
6554 if (fidp->NTopen_pathp) {
6555 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6563 /* Don't jump the gun on an async raw write */
6564 while (fidp->raw_writers) {
6565 lock_ReleaseMutex(&fidp->mx);
6566 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6567 lock_ObtainMutex(&fidp->mx);
6570 /* watch for ioctl closes, and read-only opens */
6572 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6573 == SMB_FID_OPENWRITE) {
6574 if (dosTime != 0 && dosTime != -1) {
6575 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6576 /* This fixes defect 10958 */
6577 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6578 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6580 if (smb_AsyncStore != 2) {
6581 lock_ReleaseMutex(&fidp->mx);
6582 code = cm_FSync(scp, userp, &req);
6583 lock_ObtainMutex(&fidp->mx);
6589 /* unlock any pending locks */
6590 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6591 scp->fileType == CM_SCACHETYPE_FILE) {
6595 lock_ReleaseMutex(&fidp->mx);
6597 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6599 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6600 lock_ObtainWrite(&scp->rw);
6602 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6603 CM_SCACHESYNC_NEEDCALLBACK
6604 | CM_SCACHESYNC_GETSTATUS
6605 | CM_SCACHESYNC_LOCK);
6609 "smb CoreClose SyncOp failure code 0x%x", tcode);
6610 goto post_syncopdone;
6613 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6615 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6619 lock_ReleaseWrite(&scp->rw);
6620 lock_ObtainMutex(&fidp->mx);
6623 if (fidp->flags & SMB_FID_DELONCLOSE) {
6624 clientchar_t *fullPathp = NULL;
6625 fschar_t *originalNamep = NULL;
6627 lock_ReleaseMutex(&fidp->mx);
6629 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6634 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6635 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6636 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6638 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6639 smb_NotifyChange(FILE_ACTION_REMOVED,
6640 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6641 dscp, fullPathp, NULL, TRUE);
6644 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6646 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6647 smb_NotifyChange(FILE_ACTION_REMOVED,
6648 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6649 dscp, fullPathp, NULL, TRUE);
6656 free(originalNamep);
6658 lock_ObtainMutex(&fidp->mx);
6659 fidp->flags &= ~SMB_FID_DELONCLOSE;
6662 /* if this was a newly created file, then clear the creator
6663 * in the stat cache entry. */
6664 if (fidp->flags & SMB_FID_CREATED) {
6666 fidp->flags &= ~SMB_FID_CREATED;
6669 if (fidp->flags & SMB_FID_NTOPEN) {
6670 cm_ReleaseSCache(fidp->NTopen_dscp);
6671 fidp->NTopen_dscp = NULL;
6672 free(fidp->NTopen_pathp);
6673 fidp->NTopen_pathp = NULL;
6674 fidp->flags &= ~SMB_FID_NTOPEN;
6676 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6677 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6680 if (fidp->NTopen_wholepathp) {
6681 free(fidp->NTopen_wholepathp);
6682 fidp->NTopen_wholepathp = NULL;
6686 cm_ReleaseSCache(fidp->scp);
6689 lock_ReleaseMutex(&fidp->mx);
6692 cm_ReleaseSCache(dscp);
6695 cm_ReleaseSCache(delscp);
6699 lock_ObtainWrite(&scp->rw);
6700 if (nullcreator && scp->creator == userp)
6701 scp->creator = NULL;
6702 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6703 lock_ReleaseWrite(&scp->rw);
6704 cm_ReleaseSCache(scp);
6714 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6722 fid = smb_GetSMBParm(inp, 0);
6723 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6725 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6727 fid = smb_ChainFID(fid, inp);
6728 fidp = smb_FindFID(vcp, fid, 0);
6730 return CM_ERROR_BADFD;
6733 userp = smb_GetUserFromVCP(vcp, inp);
6735 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6737 smb_ReleaseFID(fidp);
6738 cm_ReleaseUser(userp);
6743 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6745 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6746 cm_user_t *userp, long *readp)
6752 osi_hyper_t fileLength;
6754 osi_hyper_t lastByte;
6755 osi_hyper_t bufferOffset;
6759 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6762 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6763 fidp->fid, offsetp->LowPart, count);
6767 lock_ObtainMutex(&fidp->mx);
6768 /* make sure we have a readable FD */
6769 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6770 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6771 fidp->fid, fidp->flags);
6772 lock_ReleaseMutex(&fidp->mx);
6773 code = CM_ERROR_BADFDOP;
6784 lock_ObtainWrite(&scp->rw);
6786 if (offset.HighPart == 0) {
6787 chunk = offset.LowPart >> cm_logChunkSize;
6788 if (chunk != fidp->curr_chunk) {
6789 fidp->prev_chunk = fidp->curr_chunk;
6790 fidp->curr_chunk = chunk;
6792 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6795 lock_ReleaseMutex(&fidp->mx);
6797 /* start by looking up the file's end */
6798 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6799 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6803 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6805 /* now we have the entry locked, look up the length */
6806 fileLength = scp->length;
6808 /* adjust count down so that it won't go past EOF */
6809 thyper.LowPart = count;
6810 thyper.HighPart = 0;
6811 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6813 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6814 /* we'd read past EOF, so just stop at fileLength bytes.
6815 * Start by computing how many bytes remain in the file.
6817 thyper = LargeIntegerSubtract(fileLength, offset);
6819 /* if we are past EOF, read 0 bytes */
6820 if (LargeIntegerLessThanZero(thyper))
6823 count = thyper.LowPart;
6828 /* now, copy the data one buffer at a time,
6829 * until we've filled the request packet
6832 /* if we've copied all the data requested, we're done */
6833 if (count <= 0) break;
6835 /* otherwise, load up a buffer of data */
6836 thyper.HighPart = offset.HighPart;
6837 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6838 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6841 buf_Release(bufferp);
6844 lock_ReleaseWrite(&scp->rw);
6846 code = buf_Get(scp, &thyper, &bufferp);
6848 lock_ObtainWrite(&scp->rw);
6849 if (code) goto done;
6850 bufferOffset = thyper;
6852 /* now get the data in the cache */
6854 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6855 CM_SCACHESYNC_NEEDCALLBACK |
6856 CM_SCACHESYNC_READ);
6860 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6862 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6864 /* otherwise, load the buffer and try again */
6865 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6869 buf_Release(bufferp);
6873 } /* if (wrong buffer) ... */
6875 /* now we have the right buffer loaded. Copy out the
6876 * data from here to the user's buffer.
6878 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6880 /* and figure out how many bytes we want from this buffer */
6881 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6882 if (nbytes > count) nbytes = count; /* don't go past EOF */
6884 /* now copy the data */
6885 memcpy(op, bufferp->datap + bufIndex, nbytes);
6887 /* adjust counters, pointers, etc. */
6890 thyper.LowPart = nbytes;
6891 thyper.HighPart = 0;
6892 offset = LargeIntegerAdd(thyper, offset);
6896 lock_ReleaseWrite(&scp->rw);
6898 buf_Release(bufferp);
6900 if (code == 0 && sequential)
6901 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6903 cm_ReleaseSCache(scp);
6906 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6907 fidp->fid, code, *readp);
6912 * smb_WriteData -- common code for Write and Raw Write
6914 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6915 cm_user_t *userp, long *writtenp)
6917 osi_hyper_t offset = *offsetp;
6920 cm_scache_t *scp = NULL;
6921 osi_hyper_t fileLength; /* file's length at start of write */
6922 osi_hyper_t minLength; /* don't read past this */
6923 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6924 cm_buf_t *bufferp = NULL;
6925 osi_hyper_t thyper; /* hyper tmp variable */
6926 osi_hyper_t bufferOffset;
6927 afs_uint32 bufIndex; /* index in buffer where our data is */
6928 int doWriteBack = 0;
6929 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6933 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6934 fidp->fid, offsetp->LowPart, count);
6938 lock_ObtainMutex(&fidp->mx);
6939 /* make sure we have a writable FD */
6940 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6941 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6942 fidp->fid, fidp->flags);
6943 lock_ReleaseMutex(&fidp->mx);
6944 code = CM_ERROR_BADFDOP;
6952 lock_ReleaseMutex(&fidp->mx);
6954 lock_ObtainWrite(&scp->rw);
6955 /* start by looking up the file's end */
6956 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6957 CM_SCACHESYNC_NEEDCALLBACK
6958 | CM_SCACHESYNC_SETSTATUS
6959 | CM_SCACHESYNC_GETSTATUS);
6963 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6965 /* now we have the entry locked, look up the length */
6966 fileLength = scp->length;
6967 minLength = fileLength;
6968 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6969 minLength = scp->serverLength;
6971 /* adjust file length if we extend past EOF */
6972 thyper.LowPart = count;
6973 thyper.HighPart = 0;
6974 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6975 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6976 /* we'd write past EOF, so extend the file */
6977 scp->mask |= CM_SCACHEMASK_LENGTH;
6978 scp->length = thyper;
6979 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6981 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6983 /* now, if the new position (thyper) and the old (offset) are in
6984 * different storeback windows, remember to store back the previous
6985 * storeback window when we're done with the write.
6987 * the purpose of this logic is to slow down the CIFS client
6988 * in order to avoid the client disconnecting during the CLOSE
6989 * operation if there are too many dirty buffers left to write
6990 * than can be accomplished during 45 seconds. This used to be
6991 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6992 * so that we can read larger amounts of data at a time.
6994 if (smb_AsyncStore == 1 &&
6995 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6996 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6997 /* they're different */
6999 writeBackOffset.HighPart = offset.HighPart;
7000 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7005 /* now, copy the data one buffer at a time, until we've filled the
7008 /* if we've copied all the data requested, we're done */
7012 /* handle over quota or out of space */
7013 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7014 *writtenp = written;
7015 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7019 /* otherwise, load up a buffer of data */
7020 thyper.HighPart = offset.HighPart;
7021 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7022 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7025 lock_ReleaseMutex(&bufferp->mx);
7026 buf_Release(bufferp);
7029 lock_ReleaseWrite(&scp->rw);
7031 code = buf_Get(scp, &thyper, &bufferp);
7033 lock_ObtainMutex(&bufferp->mx);
7034 lock_ObtainWrite(&scp->rw);
7035 if (code) goto done;
7037 bufferOffset = thyper;
7039 /* now get the data in the cache */
7041 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7042 CM_SCACHESYNC_NEEDCALLBACK
7043 | CM_SCACHESYNC_WRITE
7044 | CM_SCACHESYNC_BUFLOCKED);
7048 cm_SyncOpDone(scp, bufferp,
7049 CM_SCACHESYNC_NEEDCALLBACK
7050 | CM_SCACHESYNC_WRITE
7051 | CM_SCACHESYNC_BUFLOCKED);
7053 /* If we're overwriting the entire buffer, or
7054 * if we're writing at or past EOF, mark the
7055 * buffer as current so we don't call
7056 * cm_GetBuffer. This skips the fetch from the
7057 * server in those cases where we're going to
7058 * obliterate all the data in the buffer anyway,
7059 * or in those cases where there is no useful
7060 * data at the server to start with.
7062 * Use minLength instead of scp->length, since
7063 * the latter has already been updated by this
7066 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7067 || LargeIntegerEqualTo(offset, bufferp->offset)
7068 && (count >= cm_data.buf_blockSize
7069 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7070 ConvertLongToLargeInteger(count)),
7072 if (count < cm_data.buf_blockSize
7073 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7074 memset(bufferp->datap, 0,
7075 cm_data.buf_blockSize);
7076 bufferp->dataVersion = scp->dataVersion;
7079 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7081 /* otherwise, load the buffer and try again */
7082 lock_ReleaseMutex(&bufferp->mx);
7083 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7085 lock_ReleaseWrite(&scp->rw);
7086 lock_ObtainMutex(&bufferp->mx);
7087 lock_ObtainWrite(&scp->rw);
7091 lock_ReleaseMutex(&bufferp->mx);
7092 buf_Release(bufferp);
7096 } /* if (wrong buffer) ... */
7098 /* now we have the right buffer loaded. Copy out the
7099 * data from here to the user's buffer.
7101 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7103 /* and figure out how many bytes we want from this buffer */
7104 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7106 nbytes = count; /* don't go past end of request */
7108 /* now copy the data */
7109 memcpy(bufferp->datap + bufIndex, op, nbytes);
7110 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7112 /* adjust counters, pointers, etc. */
7116 thyper.LowPart = nbytes;
7117 thyper.HighPart = 0;
7118 offset = LargeIntegerAdd(thyper, offset);
7122 lock_ReleaseWrite(&scp->rw);
7125 lock_ReleaseMutex(&bufferp->mx);
7126 buf_Release(bufferp);
7129 lock_ObtainMutex(&fidp->mx);
7130 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7131 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7133 lock_ReleaseMutex(&fidp->mx);
7134 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7135 fidp->NTopen_dscp, fidp->NTopen_pathp,
7138 lock_ReleaseMutex(&fidp->mx);
7142 if (smb_AsyncStore > 0) {
7146 lock_ObtainWrite(&scp->rw);
7147 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7149 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7150 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7152 lock_ReleaseWrite(&scp->rw);
7153 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7154 writeBackOffset.HighPart,
7155 smb_AsyncStoreSize, 0, userp);
7156 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7159 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7163 cm_ReleaseSCache(scp);
7166 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7167 fidp->fid, code, *writtenp);
7172 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7175 unsigned short count;
7177 unsigned short hint;
7178 long written = 0, total_written = 0;
7181 smb_t* smbp = (smb_t*) inp;
7184 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7186 int inDataBlockCount;
7188 fd = smb_GetSMBParm(inp, 0);
7189 count = smb_GetSMBParm(inp, 1);
7190 offset.HighPart = 0; /* too bad */
7191 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7192 hint = smb_GetSMBParm(inp, 4);
7194 op = smb_GetSMBData(inp, NULL);
7195 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7197 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7198 fd, offset.LowPart, count);
7200 fd = smb_ChainFID(fd, inp);
7201 fidp = smb_FindFID(vcp, fd, 0);
7203 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7204 return CM_ERROR_BADFD;
7207 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7208 smb_CloseFID(vcp, fidp, NULL, 0);
7209 smb_ReleaseFID(fidp);
7210 return CM_ERROR_NOSUCHFILE;
7213 lock_ObtainMutex(&fidp->mx);
7214 if (fidp->flags & SMB_FID_IOCTL) {
7215 lock_ReleaseMutex(&fidp->mx);
7216 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7217 smb_ReleaseFID(fidp);
7218 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7221 lock_ReleaseMutex(&fidp->mx);
7222 userp = smb_GetUserFromVCP(vcp, inp);
7226 LARGE_INTEGER LOffset;
7227 LARGE_INTEGER LLength;
7230 key = cm_GenerateKey(vcp->vcID, pid, fd);
7232 LOffset.HighPart = offset.HighPart;
7233 LOffset.LowPart = offset.LowPart;
7234 LLength.HighPart = 0;
7235 LLength.LowPart = count;
7237 lock_ObtainWrite(&fidp->scp->rw);
7238 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7239 lock_ReleaseWrite(&fidp->scp->rw);
7242 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7247 /* special case: 0 bytes transferred means truncate to this position */
7251 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7255 truncAttr.mask = CM_ATTRMASK_LENGTH;
7256 truncAttr.length.LowPart = offset.LowPart;
7257 truncAttr.length.HighPart = 0;
7258 lock_ObtainMutex(&fidp->mx);
7259 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7260 fidp->flags |= SMB_FID_LENGTHSETDONE;
7261 lock_ReleaseMutex(&fidp->mx);
7262 smb_SetSMBParm(outp, 0, 0 /* count */);
7263 smb_SetSMBDataLength(outp, 0);
7268 * Work around bug in NT client
7270 * When copying a file, the NT client should first copy the data,
7271 * then copy the last write time. But sometimes the NT client does
7272 * these in the wrong order, so the data copies would inadvertently
7273 * cause the last write time to be overwritten. We try to detect this,
7274 * and don't set client mod time if we think that would go against the
7277 lock_ObtainMutex(&fidp->mx);
7278 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7279 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7280 fidp->scp->clientModTime = time(NULL);
7282 lock_ReleaseMutex(&fidp->mx);
7285 while ( code == 0 && count > 0 ) {
7286 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7287 if (code == 0 && written == 0)
7288 code = CM_ERROR_PARTIALWRITE;
7290 offset = LargeIntegerAdd(offset,
7291 ConvertLongToLargeInteger(written));
7292 count -= (unsigned short)written;
7293 total_written += written;
7297 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7298 total_written, code);
7300 /* set the packet data length to 3 bytes for the data block header,
7301 * plus the size of the data.
7303 smb_SetSMBParm(outp, 0, total_written);
7304 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7305 smb_SetSMBParm(outp, 3, hint);
7306 smb_SetSMBDataLength(outp, 0);
7309 smb_ReleaseFID(fidp);
7310 cm_ReleaseUser(userp);
7315 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7316 NCB *ncbp, raw_write_cont_t *rwcp)
7325 fd = smb_GetSMBParm(inp, 0);
7326 fidp = smb_FindFID(vcp, fd, 0);
7328 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7329 smb_CloseFID(vcp, fidp, NULL, 0);
7330 smb_ReleaseFID(fidp);
7334 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7335 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7337 userp = smb_GetUserFromVCP(vcp, inp);
7340 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7342 if (rwcp->writeMode & 0x1) { /* synchronous */
7345 smb_FormatResponsePacket(vcp, inp, outp);
7346 op = (smb_t *) outp;
7347 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7348 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7349 smb_SetSMBDataLength(outp, 0);
7350 smb_SendPacket(vcp, outp);
7351 smb_FreePacket(outp);
7353 else { /* asynchronous */
7354 lock_ObtainMutex(&fidp->mx);
7355 fidp->raw_writers--;
7356 if (fidp->raw_writers == 0)
7357 thrd_SetEvent(fidp->raw_write_event);
7358 lock_ReleaseMutex(&fidp->mx);
7361 /* Give back raw buffer */
7362 lock_ObtainMutex(&smb_RawBufLock);
7363 *((char **)rawBuf) = smb_RawBufs;
7364 smb_RawBufs = rawBuf;
7365 lock_ReleaseMutex(&smb_RawBufLock);
7367 smb_ReleaseFID(fidp);
7368 cm_ReleaseUser(userp);
7371 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7376 /* SMB_COM_WRITE_RAW */
7377 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7380 long count, written = 0, total_written = 0;
7384 smb_t *smbp = (smb_t*) inp;
7388 unsigned short writeMode;
7390 fd = smb_GetSMBParm(inp, 0);
7391 totalCount = smb_GetSMBParm(inp, 1);
7392 count = smb_GetSMBParm(inp, 10);
7393 writeMode = smb_GetSMBParm(inp, 7);
7395 op = (char *) inp->data;
7396 op += smb_GetSMBParm(inp, 11);
7398 offset.HighPart = 0;
7399 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7401 if (*inp->wctp == 14) {
7402 /* we received a 64-bit file offset */
7403 #ifdef AFS_LARGEFILES
7404 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7406 if (LargeIntegerLessThanZero(offset)) {
7408 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7409 offset.HighPart, offset.LowPart);
7410 return CM_ERROR_BADSMB;
7413 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7415 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7416 return CM_ERROR_BADSMB;
7419 offset.HighPart = 0;
7422 offset.HighPart = 0; /* 32-bit file offset */
7426 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7427 fd, offset.HighPart, offset.LowPart, count);
7429 " WriteRaw WriteMode 0x%x",
7432 fd = smb_ChainFID(fd, inp);
7433 fidp = smb_FindFID(vcp, fd, 0);
7435 return CM_ERROR_BADFD;
7438 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7439 smb_CloseFID(vcp, fidp, NULL, 0);
7440 smb_ReleaseFID(fidp);
7441 return CM_ERROR_NOSUCHFILE;
7447 LARGE_INTEGER LOffset;
7448 LARGE_INTEGER LLength;
7451 key = cm_GenerateKey(vcp->vcID, pid, fd);
7453 LOffset.HighPart = offset.HighPart;
7454 LOffset.LowPart = offset.LowPart;
7455 LLength.HighPart = 0;
7456 LLength.LowPart = count;
7458 lock_ObtainWrite(&fidp->scp->rw);
7459 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7460 lock_ReleaseWrite(&fidp->scp->rw);
7463 smb_ReleaseFID(fidp);
7468 userp = smb_GetUserFromVCP(vcp, inp);
7471 * Work around bug in NT client
7473 * When copying a file, the NT client should first copy the data,
7474 * then copy the last write time. But sometimes the NT client does
7475 * these in the wrong order, so the data copies would inadvertently
7476 * cause the last write time to be overwritten. We try to detect this,
7477 * and don't set client mod time if we think that would go against the
7480 lock_ObtainMutex(&fidp->mx);
7481 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7482 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7483 fidp->scp->clientModTime = time(NULL);
7485 lock_ReleaseMutex(&fidp->mx);
7488 while ( code == 0 && count > 0 ) {
7489 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7490 if (code == 0 && written == 0)
7491 code = CM_ERROR_PARTIALWRITE;
7493 offset = LargeIntegerAdd(offset,
7494 ConvertLongToLargeInteger(written));
7497 total_written += written;
7501 /* Get a raw buffer */
7504 lock_ObtainMutex(&smb_RawBufLock);
7506 /* Get a raw buf, from head of list */
7507 rawBuf = smb_RawBufs;
7508 smb_RawBufs = *(char **)smb_RawBufs;
7511 code = CM_ERROR_USESTD;
7513 lock_ReleaseMutex(&smb_RawBufLock);
7516 /* Don't allow a premature Close */
7517 if (code == 0 && (writeMode & 1) == 0) {
7518 lock_ObtainMutex(&fidp->mx);
7519 fidp->raw_writers++;
7520 thrd_ResetEvent(fidp->raw_write_event);
7521 lock_ReleaseMutex(&fidp->mx);
7524 smb_ReleaseFID(fidp);
7525 cm_ReleaseUser(userp);
7528 smb_SetSMBParm(outp, 0, total_written);
7529 smb_SetSMBDataLength(outp, 0);
7530 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7535 offset = LargeIntegerAdd(offset,
7536 ConvertLongToLargeInteger(count));
7540 rwcp->offset.HighPart = offset.HighPart;
7541 rwcp->offset.LowPart = offset.LowPart;
7542 rwcp->count = totalCount - count;
7543 rwcp->writeMode = writeMode;
7544 rwcp->alreadyWritten = total_written;
7546 /* set the packet data length to 3 bytes for the data block header,
7547 * plus the size of the data.
7549 smb_SetSMBParm(outp, 0, 0xffff);
7550 smb_SetSMBDataLength(outp, 0);
7556 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7559 long count, finalCount;
7563 smb_t *smbp = (smb_t*) inp;
7568 fd = smb_GetSMBParm(inp, 0);
7569 count = smb_GetSMBParm(inp, 1);
7570 offset.HighPart = 0; /* too bad */
7571 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7573 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7574 fd, offset.LowPart, count);
7576 fd = smb_ChainFID(fd, inp);
7577 fidp = smb_FindFID(vcp, fd, 0);
7579 return CM_ERROR_BADFD;
7581 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7582 smb_CloseFID(vcp, fidp, NULL, 0);
7583 smb_ReleaseFID(fidp);
7584 return CM_ERROR_NOSUCHFILE;
7587 lock_ObtainMutex(&fidp->mx);
7588 if (fidp->flags & SMB_FID_IOCTL) {
7589 lock_ReleaseMutex(&fidp->mx);
7590 code = smb_IoctlRead(fidp, vcp, inp, outp);
7591 smb_ReleaseFID(fidp);
7594 lock_ReleaseMutex(&fidp->mx);
7597 LARGE_INTEGER LOffset, LLength;
7601 key = cm_GenerateKey(vcp->vcID, pid, fd);
7603 LOffset.HighPart = 0;
7604 LOffset.LowPart = offset.LowPart;
7605 LLength.HighPart = 0;
7606 LLength.LowPart = count;
7608 lock_ObtainWrite(&fidp->scp->rw);
7609 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7610 lock_ReleaseWrite(&fidp->scp->rw);
7613 smb_ReleaseFID(fidp);
7617 userp = smb_GetUserFromVCP(vcp, inp);
7619 /* remember this for final results */
7620 smb_SetSMBParm(outp, 0, count);
7621 smb_SetSMBParm(outp, 1, 0);
7622 smb_SetSMBParm(outp, 2, 0);
7623 smb_SetSMBParm(outp, 3, 0);
7624 smb_SetSMBParm(outp, 4, 0);
7626 /* set the packet data length to 3 bytes for the data block header,
7627 * plus the size of the data.
7629 smb_SetSMBDataLength(outp, count+3);
7631 /* get op ptr after putting in the parms, since otherwise we don't
7632 * know where the data really is.
7634 op = smb_GetSMBData(outp, NULL);
7636 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7637 *op++ = 1; /* data block marker */
7638 *op++ = (unsigned char) (count & 0xff);
7639 *op++ = (unsigned char) ((count >> 8) & 0xff);
7641 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7643 /* fix some things up */
7644 smb_SetSMBParm(outp, 0, finalCount);
7645 smb_SetSMBDataLength(outp, finalCount+3);
7647 smb_ReleaseFID(fidp);
7649 cm_ReleaseUser(userp);
7653 /* SMB_COM_CREATE_DIRECTORY */
7654 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7656 clientchar_t *pathp;
7661 cm_scache_t *dscp; /* dir we're dealing with */
7662 cm_scache_t *scp; /* file we're creating */
7664 int initialModeBits;
7665 clientchar_t *lastNamep;
7667 clientchar_t *tidPathp;
7674 /* compute initial mode bits based on read-only flag in attributes */
7675 initialModeBits = 0777;
7677 tp = smb_GetSMBData(inp, NULL);
7678 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7680 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7681 return CM_ERROR_EXISTS;
7683 spacep = inp->spacep;
7684 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7686 userp = smb_GetUserFromVCP(vcp, inp);
7688 caseFold = CM_FLAG_CASEFOLD;
7690 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7692 cm_ReleaseUser(userp);
7693 return CM_ERROR_NOSUCHPATH;
7696 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7697 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7698 userp, tidPathp, &req, &dscp);
7701 cm_ReleaseUser(userp);
7706 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7707 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7708 cm_ReleaseSCache(dscp);
7709 cm_ReleaseUser(userp);
7710 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7711 return CM_ERROR_PATH_NOT_COVERED;
7713 return CM_ERROR_BADSHARENAME;
7715 #endif /* DFS_SUPPORT */
7717 /* otherwise, scp points to the parent directory. Do a lookup, and
7718 * fail if we find it. Otherwise, we do the create.
7724 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7725 if (scp) cm_ReleaseSCache(scp);
7726 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7727 if (code == 0) code = CM_ERROR_EXISTS;
7728 cm_ReleaseSCache(dscp);
7729 cm_ReleaseUser(userp);
7733 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7734 setAttr.clientModTime = time(NULL);
7735 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7736 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7737 smb_NotifyChange(FILE_ACTION_ADDED,
7738 FILE_NOTIFY_CHANGE_DIR_NAME,
7739 dscp, lastNamep, NULL, TRUE);
7741 /* we don't need this any longer */
7742 cm_ReleaseSCache(dscp);
7745 /* something went wrong creating or truncating the file */
7746 cm_ReleaseUser(userp);
7750 /* otherwise we succeeded */
7751 smb_SetSMBDataLength(outp, 0);
7752 cm_ReleaseUser(userp);
7757 BOOL smb_IsLegalFilename(clientchar_t *filename)
7760 * Find the longest substring of filename that does not contain
7761 * any of the chars in illegalChars. If that substring is less
7762 * than the length of the whole string, then one or more of the
7763 * illegal chars is in filename.
7765 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7771 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7772 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7774 clientchar_t *pathp;
7780 cm_scache_t *dscp; /* dir we're dealing with */
7781 cm_scache_t *scp; /* file we're creating */
7783 int initialModeBits;
7786 clientchar_t *lastNamep;
7789 clientchar_t *tidPathp;
7791 int created = 0; /* the file was new */
7796 excl = (inp->inCom == 0x03)? 0 : 1;
7798 attributes = smb_GetSMBParm(inp, 0);
7799 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7801 /* compute initial mode bits based on read-only flag in attributes */
7802 initialModeBits = 0666;
7803 if (attributes & SMB_ATTR_READONLY)
7804 initialModeBits &= ~0222;
7806 tp = smb_GetSMBData(inp, NULL);
7807 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7809 if (!cm_IsValidClientString(pathp)) {
7811 clientchar_t * hexp;
7813 hexp = cm_GetRawCharsAlloc(pathp, -1);
7814 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7815 osi_LogSaveClientString(smb_logp, hexp));
7819 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7821 return CM_ERROR_BADNTFILENAME;
7824 spacep = inp->spacep;
7825 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7827 userp = smb_GetUserFromVCP(vcp, inp);
7829 caseFold = CM_FLAG_CASEFOLD;
7831 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7833 cm_ReleaseUser(userp);
7834 return CM_ERROR_NOSUCHPATH;
7836 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7837 userp, tidPathp, &req, &dscp);
7840 cm_ReleaseUser(userp);
7845 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7846 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7847 cm_ReleaseSCache(dscp);
7848 cm_ReleaseUser(userp);
7849 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7850 return CM_ERROR_PATH_NOT_COVERED;
7852 return CM_ERROR_BADSHARENAME;
7854 #endif /* DFS_SUPPORT */
7856 /* otherwise, scp points to the parent directory. Do a lookup, and
7857 * truncate the file if we find it, otherwise we create the file.
7864 if (!smb_IsLegalFilename(lastNamep))
7865 return CM_ERROR_BADNTFILENAME;
7867 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7868 #ifdef DEBUG_VERBOSE
7871 hexp = osi_HexifyString( lastNamep );
7872 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7877 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7878 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7879 cm_ReleaseSCache(dscp);
7880 cm_ReleaseUser(userp);
7884 /* if we get here, if code is 0, the file exists and is represented by
7885 * scp. Otherwise, we have to create it.
7889 /* oops, file shouldn't be there */
7890 cm_ReleaseSCache(dscp);
7891 cm_ReleaseSCache(scp);
7892 cm_ReleaseUser(userp);
7893 return CM_ERROR_EXISTS;
7896 setAttr.mask = CM_ATTRMASK_LENGTH;
7897 setAttr.length.LowPart = 0;
7898 setAttr.length.HighPart = 0;
7899 code = cm_SetAttr(scp, &setAttr, userp, &req);
7902 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7903 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7904 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7908 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7909 smb_NotifyChange(FILE_ACTION_ADDED,
7910 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7911 dscp, lastNamep, NULL, TRUE);
7912 } else if (!excl && code == CM_ERROR_EXISTS) {
7913 /* not an exclusive create, and someone else tried
7914 * creating it already, then we open it anyway. We
7915 * don't bother retrying after this, since if this next
7916 * fails, that means that the file was deleted after
7917 * we started this call.
7919 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7922 setAttr.mask = CM_ATTRMASK_LENGTH;
7923 setAttr.length.LowPart = 0;
7924 setAttr.length.HighPart = 0;
7925 code = cm_SetAttr(scp, &setAttr, userp, &req);
7930 /* we don't need this any longer */
7931 cm_ReleaseSCache(dscp);
7934 /* something went wrong creating or truncating the file */
7935 if (scp) cm_ReleaseSCache(scp);
7936 cm_ReleaseUser(userp);
7940 /* make sure we only open files */
7941 if (scp->fileType != CM_SCACHETYPE_FILE) {
7942 cm_ReleaseSCache(scp);
7943 cm_ReleaseUser(userp);
7944 return CM_ERROR_ISDIR;
7947 /* now all we have to do is open the file itself */
7948 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7949 osi_assertx(fidp, "null smb_fid_t");
7953 lock_ObtainMutex(&fidp->mx);
7954 /* always create it open for read/write */
7955 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7957 /* remember that the file was newly created */
7959 fidp->flags |= SMB_FID_CREATED;
7961 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7963 /* save a pointer to the vnode */
7965 lock_ObtainWrite(&scp->rw);
7966 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7967 lock_ReleaseWrite(&scp->rw);
7970 fidp->userp = userp;
7971 lock_ReleaseMutex(&fidp->mx);
7973 smb_SetSMBParm(outp, 0, fidp->fid);
7974 smb_SetSMBDataLength(outp, 0);
7976 cm_Open(scp, 0, userp);
7978 smb_ReleaseFID(fidp);
7979 cm_ReleaseUser(userp);
7980 /* leave scp held since we put it in fidp->scp */
7985 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7988 osi_hyper_t new_offset;
7999 fd = smb_GetSMBParm(inp, 0);
8000 whence = smb_GetSMBParm(inp, 1);
8001 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8003 /* try to find the file descriptor */
8004 fd = smb_ChainFID(fd, inp);
8005 fidp = smb_FindFID(vcp, fd, 0);
8007 return CM_ERROR_BADFD;
8009 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8010 smb_CloseFID(vcp, fidp, NULL, 0);
8011 smb_ReleaseFID(fidp);
8012 return CM_ERROR_NOSUCHFILE;
8015 lock_ObtainMutex(&fidp->mx);
8016 if (fidp->flags & SMB_FID_IOCTL) {
8017 lock_ReleaseMutex(&fidp->mx);
8018 smb_ReleaseFID(fidp);
8019 return CM_ERROR_BADFD;
8021 lock_ReleaseMutex(&fidp->mx);
8023 userp = smb_GetUserFromVCP(vcp, inp);
8025 lock_ObtainMutex(&fidp->mx);
8028 lock_ReleaseMutex(&fidp->mx);
8029 lock_ObtainWrite(&scp->rw);
8030 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8031 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8033 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8035 /* offset from current offset */
8036 new_offset = LargeIntegerAdd(fidp->offset,
8037 ConvertLongToLargeInteger(offset));
8039 else if (whence == 2) {
8040 /* offset from current EOF */
8041 new_offset = LargeIntegerAdd(scp->length,
8042 ConvertLongToLargeInteger(offset));
8044 new_offset = ConvertLongToLargeInteger(offset);
8047 fidp->offset = new_offset;
8048 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8049 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8050 smb_SetSMBDataLength(outp, 0);
8052 lock_ReleaseWrite(&scp->rw);
8053 smb_ReleaseFID(fidp);
8054 cm_ReleaseSCache(scp);
8055 cm_ReleaseUser(userp);
8059 /* dispatch all of the requests received in a packet. Due to chaining, this may
8060 * be more than one request.
8062 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8063 NCB *ncbp, raw_write_cont_t *rwcp)
8067 unsigned long code = 0;
8068 unsigned char *outWctp;
8069 int nparms; /* # of bytes of parameters */
8071 int nbytes; /* bytes of data, excluding count */
8074 unsigned short errCode;
8075 unsigned long NTStatus;
8077 unsigned char errClass;
8078 unsigned int oldGen;
8079 DWORD oldTime, newTime;
8081 /* get easy pointer to the data */
8082 smbp = (smb_t *) inp->data;
8084 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8085 /* setup the basic parms for the initial request in the packet */
8086 inp->inCom = smbp->com;
8087 inp->wctp = &smbp->wct;
8089 inp->ncb_length = ncbp->ncb_length;
8094 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8095 /* log it and discard it */
8096 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8097 __FILE__, __LINE__, ncbp->ncb_length);
8098 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8102 /* We are an ongoing op */
8103 thrd_Increment(&ongoingOps);
8105 /* set up response packet for receiving output */
8106 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8107 smb_FormatResponsePacket(vcp, inp, outp);
8108 outWctp = outp->wctp;
8110 /* Remember session generation number and time */
8111 oldGen = sessionGen;
8112 oldTime = GetTickCount();
8114 while (inp->inCom != 0xff) {
8115 dp = &smb_dispatchTable[inp->inCom];
8117 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8118 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8119 code = outp->resumeCode;
8123 /* process each request in the packet; inCom, wctp and inCount
8124 * are already set up.
8126 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8129 /* now do the dispatch */
8130 /* start by formatting the response record a little, as a default */
8131 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8133 outWctp[1] = 0xff; /* no operation */
8134 outWctp[2] = 0; /* padding */
8139 /* not a chained request, this is a more reasonable default */
8140 outWctp[0] = 0; /* wct of zero */
8141 outWctp[1] = 0; /* and bcc (word) of zero */
8145 /* once set, stays set. Doesn't matter, since we never chain
8146 * "no response" calls.
8148 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8152 /* we have a recognized operation */
8153 char * opName = myCrt_Dispatch(inp->inCom);
8155 if (inp->inCom == 0x1d)
8157 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8159 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8160 opName,vcp,vcp->lana,vcp->lsn);
8161 code = (*(dp->procp)) (vcp, inp, outp);
8162 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8163 code,vcp,vcp->lana,vcp->lsn);
8165 if ( code == CM_ERROR_BADSMB ||
8166 code == CM_ERROR_BADOP )
8168 #endif /* LOG_PACKET */
8171 newTime = GetTickCount();
8172 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8174 /* ReceiveV3Tran2A handles its own logging */
8175 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8178 clientchar_t *treepath = NULL; /* do not free */
8179 clientchar_t *pathname = NULL;
8180 cm_fid_t afid = {0,0,0,0,0};
8182 uidp = smb_FindUID(vcp, smbp->uid, 0);
8183 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8184 fidp = smb_FindFID(vcp, inp->fid, 0);
8186 if (fidp && fidp->NTopen_pathp)
8187 pathname = fidp->NTopen_pathp;
8188 else if (inp->stringsp->wdata)
8189 pathname = inp->stringsp->wdata;
8191 if (fidp && fidp->scp)
8192 afid = fidp->scp->fid;
8194 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8195 opName, newTime - oldTime,
8196 uidp ? uidp->unp->name : NULL,
8199 afid.cell, afid.volume, afid.vnode, afid.unique);
8202 smb_ReleaseUID(uidp);
8204 smb_ReleaseFID(fidp);
8207 if (oldGen != sessionGen) {
8208 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8209 newTime - oldTime, ncbp->ncb_length);
8210 osi_Log3(smb_logp, "Request %s straddled session startup, "
8211 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8214 FreeSMBStrings(inp);
8216 /* bad opcode, fail the request, after displaying it */
8217 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8220 #endif /* LOG_PACKET */
8223 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8224 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8225 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8226 if (code == IDCANCEL)
8229 code = CM_ERROR_BADOP;
8232 /* catastrophic failure: log as much as possible */
8233 if (code == CM_ERROR_BADSMB) {
8234 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8238 #endif /* LOG_PACKET */
8239 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8242 code = CM_ERROR_INVAL;
8245 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8246 thrd_Decrement(&ongoingOps);
8251 /* now, if we failed, turn the current response into an empty
8252 * one, and fill in the response packet's error code.
8255 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8256 smb_MapNTError(code, &NTStatus);
8257 outWctp = outp->wctp;
8258 smbp = (smb_t *) &outp->data;
8259 if (code != CM_ERROR_PARTIALWRITE
8260 && code != CM_ERROR_BUFFERTOOSMALL
8261 && code != CM_ERROR_GSSCONTINUE) {
8262 /* nuke wct and bcc. For a partial
8263 * write or an in-process authentication handshake,
8264 * assume they're OK.
8270 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8271 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8272 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8273 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8274 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8278 smb_MapCoreError(code, vcp, &errCode, &errClass);
8279 outWctp = outp->wctp;
8280 smbp = (smb_t *) &outp->data;
8281 if (code != CM_ERROR_PARTIALWRITE) {
8282 /* nuke wct and bcc. For a partial
8283 * write, assume they're OK.
8289 smbp->errLow = (unsigned char) (errCode & 0xff);
8290 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8291 smbp->rcls = errClass;
8294 } /* error occurred */
8296 /* if we're here, we've finished one request. Look to see if
8297 * this is a chained opcode. If it is, setup things to process
8298 * the chained request, and setup the output buffer to hold the
8299 * chained response. Start by finding the next input record.
8301 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8302 break; /* not a chained req */
8303 tp = inp->wctp; /* points to start of last request */
8304 /* in a chained request, the first two
8305 * parm fields are required, and are
8306 * AndXCommand/AndXReserved and
8308 if (tp[0] < 2) break;
8309 if (tp[1] == 0xff) break; /* no more chained opcodes */
8311 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8314 /* and now append the next output request to the end of this
8315 * last request. Begin by finding out where the last response
8316 * ends, since that's where we'll put our new response.
8318 outWctp = outp->wctp; /* ptr to out parameters */
8319 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8320 nparms = outWctp[0] << 1;
8321 tp = outWctp + nparms + 1; /* now points to bcc field */
8322 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8323 tp += 2 /* for the count itself */ + nbytes;
8324 /* tp now points to the new output record; go back and patch the
8325 * second parameter (off2) to point to the new record.
8327 temp = (unsigned int)(tp - outp->data);
8328 outWctp[3] = (unsigned char) (temp & 0xff);
8329 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8330 outWctp[2] = 0; /* padding */
8331 outWctp[1] = inp->inCom; /* next opcode */
8333 /* finally, setup for the next iteration */
8336 } /* while loop over all requests in the packet */
8338 /* now send the output packet, and return */
8340 smb_SendPacket(vcp, outp);
8341 thrd_Decrement(&ongoingOps);
8346 /* Wait for Netbios() calls to return, and make the results available to server
8347 * threads. Note that server threads can't wait on the NCBevents array
8348 * themselves, because NCB events are manual-reset, and the servers would race
8349 * each other to reset them.
8351 void smb_ClientWaiter(void *parmp)
8356 while (smbShutdownFlag == 0) {
8357 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8359 if (code == WAIT_OBJECT_0)
8362 /* error checking */
8363 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8365 int abandonIdx = code - WAIT_ABANDONED_0;
8366 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8369 if (code == WAIT_IO_COMPLETION)
8371 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8375 if (code == WAIT_TIMEOUT)
8377 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8380 if (code == WAIT_FAILED)
8382 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8385 idx = code - WAIT_OBJECT_0;
8387 /* check idx range! */
8388 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8390 /* this is fatal - log as much as possible */
8391 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8392 osi_assertx(0, "invalid index");
8395 thrd_ResetEvent(NCBevents[idx]);
8396 thrd_SetEvent(NCBreturns[0][idx]);
8401 * Try to have one NCBRECV request waiting for every live session. Not more
8402 * than one, because if there is more than one, it's hard to handle Write Raw.
8404 void smb_ServerWaiter(void *parmp)
8407 int idx_session, idx_NCB;
8410 while (smbShutdownFlag == 0) {
8412 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8414 if (code == WAIT_OBJECT_0)
8417 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8419 int abandonIdx = code - WAIT_ABANDONED_0;
8420 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8423 if (code == WAIT_IO_COMPLETION)
8425 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8429 if (code == WAIT_TIMEOUT)
8431 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8434 if (code == WAIT_FAILED)
8436 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8439 idx_session = code - WAIT_OBJECT_0;
8441 /* check idx range! */
8442 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8444 /* this is fatal - log as much as possible */
8445 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8446 osi_assertx(0, "invalid index");
8451 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8453 if (code == WAIT_OBJECT_0) {
8454 if (smbShutdownFlag == 1)
8460 /* error checking */
8461 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8463 int abandonIdx = code - WAIT_ABANDONED_0;
8464 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8467 if (code == WAIT_IO_COMPLETION)
8469 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8473 if (code == WAIT_TIMEOUT)
8475 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8478 if (code == WAIT_FAILED)
8480 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8483 idx_NCB = code - WAIT_OBJECT_0;
8485 /* check idx range! */
8486 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8488 /* this is fatal - log as much as possible */
8489 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8490 osi_assertx(0, "invalid index");
8493 /* Link them together */
8494 NCBsessions[idx_NCB] = idx_session;
8497 ncbp = NCBs[idx_NCB];
8498 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8499 ncbp->ncb_command = NCBRECV | ASYNCH;
8500 ncbp->ncb_lana_num = lanas[idx_session];
8501 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8502 ncbp->ncb_event = NCBevents[idx_NCB];
8503 ncbp->ncb_length = SMB_PACKETSIZE;
8509 * The top level loop for handling SMB request messages. Each server thread
8510 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8511 * NCB and buffer for the incoming request are loaned to us.
8513 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8514 * to immediately send a request for the rest of the data. This must come
8515 * before any other traffic for that session, so we delay setting the session
8516 * event until that data has come in.
8518 void smb_Server(VOID *parmp)
8520 INT_PTR myIdx = (INT_PTR) parmp;
8524 smb_packet_t *outbufp;
8526 int idx_NCB, idx_session;
8528 smb_vc_t *vcp = NULL;
8530 extern void rx_StartClientThread(void);
8532 rx_StartClientThread();
8534 outncbp = smb_GetNCB();
8535 outbufp = smb_GetPacket();
8536 outbufp->ncbp = outncbp;
8544 smb_ResetServerPriority();
8546 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8549 /* terminate silently if shutdown flag is set */
8550 if (code == WAIT_OBJECT_0) {
8551 if (smbShutdownFlag == 1) {
8552 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8558 /* error checking */
8559 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8561 int abandonIdx = code - WAIT_ABANDONED_0;
8562 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8565 if (code == WAIT_IO_COMPLETION)
8567 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8571 if (code == WAIT_TIMEOUT)
8573 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8576 if (code == WAIT_FAILED)
8578 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8581 idx_NCB = code - WAIT_OBJECT_0;
8583 /* check idx range! */
8584 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8586 /* this is fatal - log as much as possible */
8587 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8588 osi_assertx(0, "invalid index");
8591 ncbp = NCBs[idx_NCB];
8592 idx_session = NCBsessions[idx_NCB];
8593 rc = ncbp->ncb_retcode;
8595 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8596 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8600 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8604 /* Can this happen? Or is it just my UNIX paranoia? */
8605 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8610 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8613 /* Client closed session */
8614 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8616 lock_ObtainMutex(&vcp->mx);
8617 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8618 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8620 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8621 lock_ReleaseMutex(&vcp->mx);
8622 lock_ObtainWrite(&smb_globalLock);
8623 dead_sessions[vcp->session] = TRUE;
8624 lock_ReleaseWrite(&smb_globalLock);
8626 lock_ReleaseMutex(&vcp->mx);
8628 smb_CleanupDeadVC(vcp);
8635 /* Treat as transient error */
8636 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8639 "dispatch smb recv failed, message incomplete, ncb_length %d",
8642 "SMB message incomplete, "
8643 "length %d", ncbp->ncb_length);
8646 * We used to discard the packet.
8647 * Instead, try handling it normally.
8651 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8655 /* A weird error code. Log it, sleep, and continue. */
8656 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8658 lock_ObtainMutex(&vcp->mx);
8659 if (vcp->errorCount++ > 3) {
8660 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8661 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8662 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8664 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8665 lock_ReleaseMutex(&vcp->mx);
8666 lock_ObtainWrite(&smb_globalLock);
8667 dead_sessions[vcp->session] = TRUE;
8668 lock_ReleaseWrite(&smb_globalLock);
8670 lock_ReleaseMutex(&vcp->mx);
8672 smb_CleanupDeadVC(vcp);
8678 lock_ReleaseMutex(&vcp->mx);
8682 thrd_SetEvent(SessionEvents[idx_session]);
8688 /* Success, so now dispatch on all the data in the packet */
8690 smb_concurrentCalls++;
8691 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8692 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8695 * If at this point vcp is NULL (implies that packet was invalid)
8696 * then we are in big trouble. This means either :
8697 * a) we have the wrong NCB.
8698 * b) Netbios screwed up the call.
8699 * c) The VC was already marked dead before we were able to
8701 * Obviously this implies that
8702 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8703 * lanas[idx_session] != ncbp->ncb_lana_num )
8704 * Either way, we can't do anything with this packet.
8705 * Log, sleep and resume.
8708 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8712 ncbp->ncb_lana_num);
8714 /* Also log in the trace log. */
8715 osi_Log4(smb_logp, "Server: VCP does not exist!"
8716 "LSNs[idx_session]=[%d],"
8717 "lanas[idx_session]=[%d],"
8718 "ncbp->ncb_lsn=[%d],"
8719 "ncbp->ncb_lana_num=[%d]",
8723 ncbp->ncb_lana_num);
8725 /* thrd_Sleep(1000); Don't bother sleeping */
8726 thrd_SetEvent(SessionEvents[idx_session]);
8727 smb_concurrentCalls--;
8731 smb_SetRequestStartTime();
8733 vcp->errorCount = 0;
8734 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8735 smbp = (smb_t *)bufp->data;
8742 if (smbp->com == 0x1d) {
8743 /* Special handling for Write Raw */
8744 raw_write_cont_t rwc;
8745 EVENT_HANDLE rwevent;
8746 char eventName[MAX_PATH];
8748 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8749 if (rwc.code == 0) {
8750 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8751 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8752 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8753 ncbp->ncb_command = NCBRECV | ASYNCH;
8754 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8755 ncbp->ncb_lana_num = vcp->lana;
8756 ncbp->ncb_buffer = rwc.buf;
8757 ncbp->ncb_length = 65535;
8758 ncbp->ncb_event = rwevent;
8760 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8761 thrd_CloseHandle(rwevent);
8763 thrd_SetEvent(SessionEvents[idx_session]);
8765 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8767 else if (smbp->com == 0xa0) {
8769 * Serialize the handling for NT Transact
8772 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8773 thrd_SetEvent(SessionEvents[idx_session]);
8775 thrd_SetEvent(SessionEvents[idx_session]);
8776 /* TODO: what else needs to be serialized? */
8777 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8781 __except( smb_ServerExceptionFilter() ) {
8785 smb_concurrentCalls--;
8788 thrd_SetEvent(NCBavails[idx_NCB]);
8793 smb_FreePacket(outbufp);
8795 smb_FreeNCB(outncbp);
8799 * Exception filter for the server threads. If an exception occurs in the
8800 * dispatch routines, which is where exceptions are most common, then do a
8801 * force trace and give control to upstream exception handlers. Useful for
8804 DWORD smb_ServerExceptionFilter(void) {
8805 /* While this is not the best time to do a trace, if it succeeds, then
8806 * we have a trace (assuming tracing was enabled). Otherwise, this should
8807 * throw a second exception.
8809 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8810 afsd_ForceTrace(TRUE);
8811 buf_ForceTrace(TRUE);
8812 return EXCEPTION_CONTINUE_SEARCH;
8816 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8817 * If the number of server threads is M, and the number of live sessions is
8818 * N, then the number of NCB's in use at any time either waiting for, or
8819 * holding, received messages is M + N, so that is how many NCB's get created.
8821 void InitNCBslot(int idx)
8823 struct smb_packet *bufp;
8824 EVENT_HANDLE retHandle;
8826 char eventName[MAX_PATH];
8828 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8830 NCBs[idx] = smb_GetNCB();
8831 sprintf(eventName,"NCBavails[%d]", idx);
8832 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8833 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8834 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8835 sprintf(eventName,"NCBevents[%d]", idx);
8836 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8837 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8838 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8839 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8840 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8841 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8842 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8843 for (i=0; i<smb_NumServerThreads; i++)
8844 NCBreturns[i][idx] = retHandle;
8845 bufp = smb_GetPacket();
8846 bufp->spacep = cm_GetSpace();
8850 /* listen for new connections */
8851 void smb_Listener(void *parmp)
8857 afs_uint32 session, thread;
8858 smb_vc_t *vcp = NULL;
8860 char rname[NCBNAMSZ+1];
8861 char cname[MAX_COMPUTERNAME_LENGTH+1];
8862 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8863 INT_PTR lana = (INT_PTR) parmp;
8864 char eventName[MAX_PATH];
8865 int bridgeCount = 0;
8866 int nowildCount = 0;
8868 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8869 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8870 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8871 thrd_ResetEvent(ListenerShutdown[lana]);
8873 ncbp = smb_GetNCB();
8875 /* retrieve computer name */
8876 GetComputerName(cname, &cnamelen);
8879 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8880 memset(ncbp, 0, sizeof(NCB));
8883 ncbp->ncb_command = NCBLISTEN;
8884 ncbp->ncb_rto = 0; /* No receive timeout */
8885 ncbp->ncb_sto = 0; /* No send timeout */
8887 /* pad out with spaces instead of null termination */
8888 len = (long)strlen(smb_localNamep);
8889 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8890 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8892 strcpy(ncbp->ncb_callname, "*");
8893 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8895 ncbp->ncb_lana_num = (UCHAR)lana;
8897 code = Netbios(ncbp);
8899 if (code == NRC_NAMERR) {
8900 /* An smb shutdown or Vista resume must have taken place */
8902 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8903 ncbp->ncb_lana_num);
8904 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
8906 if (lock_TryMutex(&smb_StartedLock)) {
8907 lana_list.lana[i] = LANA_INVALID;
8908 lock_ReleaseMutex(&smb_StartedLock);
8911 } else if (code == NRC_BRIDGE || code != 0) {
8912 int lanaRemaining = 0;
8914 if (code == NRC_BRIDGE) {
8915 if (++bridgeCount <= 5) {
8916 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
8919 } else if (code == NRC_NOWILD) {
8920 if (++nowildCount <= 5) {
8921 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
8923 if (bridgeCount > 0) {
8924 memset(ncbp, 0, sizeof(*ncbp));
8925 ncbp->ncb_command = NCBADDNAME;
8926 ncbp->ncb_lana_num = (UCHAR)lana;
8927 /* pad out with spaces instead of null termination */
8928 len = (long)strlen(smb_localNamep);
8929 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8930 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8931 code = Netbios(ncbp);
8937 while (!lock_TryMutex(&smb_StartedLock)) {
8938 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8944 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8945 ncbp->ncb_lana_num, ncb_error_string(code));
8946 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8947 ncbp->ncb_lana_num, ncb_error_string(code));
8949 for (i = 0; i < lana_list.length; i++) {
8950 if (lana_list.lana[i] == lana) {
8951 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8952 lana_list.lana[i] = LANA_INVALID;
8954 if (lana_list.lana[i] != LANA_INVALID)
8958 if (lanaRemaining == 0) {
8959 cm_VolStatus_Network_Stopped(cm_NetbiosName
8964 smb_ListenerState = SMB_LISTENER_STOPPED;
8965 smb_LANadapter = LANA_INVALID;
8966 lana_list.length = 0;
8968 lock_ReleaseMutex(&smb_StartedLock);
8972 else if (code != 0) {
8973 char tbuffer[AFSPATHMAX];
8975 /* terminate silently if shutdown flag is set */
8976 while (!lock_TryMutex(&smb_StartedLock)) {
8977 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8983 "NCBLISTEN lana=%d failed with code %d [%s]",
8984 ncbp->ncb_lana_num, code, ncb_error_string(code));
8986 "Client exiting due to network failure. Please restart client.\n");
8989 "Client exiting due to network failure. Please restart client.\n"
8990 "NCBLISTEN lana=%d failed with code %d [%s]",
8991 ncbp->ncb_lana_num, code, ncb_error_string(code));
8993 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8994 MB_OK|MB_SERVICE_NOTIFICATION);
8995 osi_panic(tbuffer, __FILE__, __LINE__);
8997 lock_ReleaseMutex(&smb_StartedLock);
9002 /* a successful packet received. clear bridge error count */
9006 /* check for remote conns */
9007 /* first get remote name and insert null terminator */
9008 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9009 for (i=NCBNAMSZ; i>0; i--) {
9010 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9016 /* compare with local name */
9018 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9019 flags |= SMB_VCFLAG_REMOTECONN;
9022 lock_ObtainMutex(&smb_ListenerLock);
9024 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9025 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9027 /* now ncbp->ncb_lsn is the connection ID */
9028 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9029 if (vcp->session == 0) {
9030 /* New generation */
9031 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9034 /* Log session startup */
9036 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9037 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9038 #endif /* NOTSERVICE */
9039 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9040 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9042 if (reportSessionStartups) {
9043 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9046 lock_ObtainMutex(&vcp->mx);
9047 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9048 vcp->flags |= flags;
9049 lock_ReleaseMutex(&vcp->mx);
9051 /* Allocate slot in session arrays */
9052 /* Re-use dead session if possible, otherwise add one more */
9053 /* But don't look at session[0], it is reserved */
9054 lock_ObtainWrite(&smb_globalLock);
9055 for (session = 1; session < numSessions; session++) {
9056 if (dead_sessions[session]) {
9057 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9058 dead_sessions[session] = FALSE;
9062 lock_ReleaseWrite(&smb_globalLock);
9064 /* We are re-using an existing VC because the lsn and lana
9066 session = vcp->session;
9068 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9070 /* Log session startup */
9072 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9073 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9074 #endif /* NOTSERVICE */
9075 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9076 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9078 if (reportSessionStartups) {
9079 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9083 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9084 unsigned long code = CM_ERROR_ALLBUSY;
9085 smb_packet_t * outp = smb_GetPacket();
9086 unsigned char *outWctp;
9089 smb_FormatResponsePacket(vcp, NULL, outp);
9092 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9093 unsigned long NTStatus;
9094 smb_MapNTError(code, &NTStatus);
9095 outWctp = outp->wctp;
9096 smbp = (smb_t *) &outp->data;
9100 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9101 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9102 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9103 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9104 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9106 unsigned short errCode;
9107 unsigned char errClass;
9108 smb_MapCoreError(code, vcp, &errCode, &errClass);
9109 outWctp = outp->wctp;
9110 smbp = (smb_t *) &outp->data;
9114 smbp->errLow = (unsigned char) (errCode & 0xff);
9115 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9116 smbp->rcls = errClass;
9119 smb_SendPacket(vcp, outp);
9120 smb_FreePacket(outp);
9122 lock_ObtainMutex(&vcp->mx);
9123 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9124 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9126 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9127 lock_ReleaseMutex(&vcp->mx);
9128 lock_ObtainWrite(&smb_globalLock);
9129 dead_sessions[vcp->session] = TRUE;
9130 lock_ReleaseWrite(&smb_globalLock);
9131 smb_CleanupDeadVC(vcp);
9133 lock_ReleaseMutex(&vcp->mx);
9136 /* assert that we do not exceed the maximum number of sessions or NCBs.
9137 * we should probably want to wait for a session to be freed in case
9140 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9141 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9143 lock_ObtainMutex(&vcp->mx);
9144 vcp->session = session;
9145 lock_ReleaseMutex(&vcp->mx);
9146 lock_ObtainWrite(&smb_globalLock);
9147 LSNs[session] = ncbp->ncb_lsn;
9148 lanas[session] = ncbp->ncb_lana_num;
9149 lock_ReleaseWrite(&smb_globalLock);
9151 if (session == numSessions) {
9152 /* Add new NCB for new session */
9153 char eventName[MAX_PATH];
9155 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9157 InitNCBslot(numNCBs);
9158 lock_ObtainWrite(&smb_globalLock);
9160 lock_ReleaseWrite(&smb_globalLock);
9161 thrd_SetEvent(NCBavails[0]);
9162 thrd_SetEvent(NCBevents[0]);
9163 for (thread = 0; thread < smb_NumServerThreads; thread++)
9164 thrd_SetEvent(NCBreturns[thread][0]);
9165 /* Also add new session event */
9166 sprintf(eventName, "SessionEvents[%d]", session);
9167 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9168 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9169 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9170 lock_ObtainWrite(&smb_globalLock);
9172 lock_ReleaseWrite(&smb_globalLock);
9173 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9174 thrd_SetEvent(SessionEvents[0]);
9176 thrd_SetEvent(SessionEvents[session]);
9182 lock_ReleaseMutex(&smb_ListenerLock);
9183 } /* dispatch while loop */
9187 thrd_SetEvent(ListenerShutdown[lana]);
9192 smb_LanAdapterChangeThread(void *param)
9195 * Give the IPAddrDaemon thread a chance
9196 * to block before we trigger.
9199 smb_LanAdapterChange(0);
9202 void smb_SetLanAdapterChangeDetected(void)
9207 lock_ObtainMutex(&smb_StartedLock);
9209 if (!powerStateSuspended) {
9210 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9211 NULL, 0, &lpid, "smb_LanAdapterChange");
9212 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9213 thrd_CloseHandle(phandle);
9216 smb_LanAdapterChangeDetected = 1;
9217 lock_ReleaseMutex(&smb_StartedLock);
9220 void smb_LanAdapterChange(int locked) {
9221 lana_number_t lanaNum;
9223 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9225 LANA_ENUM temp_list;
9230 afsi_log("smb_LanAdapterChange");
9233 lock_ObtainMutex(&smb_StartedLock);
9235 smb_LanAdapterChangeDetected = 0;
9237 if (!powerStateSuspended &&
9238 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9239 LANA_NETBIOS_NAME_FULL)) &&
9240 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9241 if ( isGateway != bGateway ) {
9242 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9243 smb_LANadapter, lanaNum, isGateway, bGateway);
9245 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9246 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9247 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9250 NCB *ncbp = smb_GetNCB();
9251 ncbp->ncb_command = NCBENUM;
9252 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9253 ncbp->ncb_length = sizeof(temp_list);
9254 code = Netbios(ncbp);
9256 if (temp_list.length != lana_list.length) {
9257 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9258 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9261 for (i=0; i<lana_list.length; i++) {
9262 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9263 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9264 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9276 smb_StopListeners(1);
9277 smb_RestartListeners(1);
9280 lock_ReleaseMutex(&smb_StartedLock);
9283 /* initialize Netbios */
9284 int smb_NetbiosInit(int locked)
9287 int i, lana, code, l;
9289 int delname_tried=0;
9292 lana_number_t lanaNum;
9295 lock_ObtainMutex(&smb_StartedLock);
9297 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9298 smb_ListenerState != SMB_LISTENER_STOPPED) {
9301 lock_ReleaseMutex(&smb_StartedLock);
9304 /* setup the NCB system */
9305 ncbp = smb_GetNCB();
9307 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9308 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9309 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9311 if (smb_LANadapter != LANA_INVALID)
9312 afsi_log("LAN adapter number %d", smb_LANadapter);
9314 afsi_log("LAN adapter number not determined");
9317 afsi_log("Set for gateway service");
9319 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9321 /* something went horribly wrong. We can't proceed without a netbios name */
9323 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9324 osi_panic(buf, __FILE__, __LINE__);
9327 /* remember the name */
9328 len = (int)strlen(cm_NetbiosName);
9330 free(smb_localNamep);
9331 smb_localNamep = malloc(len+1);
9332 strcpy(smb_localNamep, cm_NetbiosName);
9333 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9335 /* Also copy the value to the client character encoded string */
9336 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9338 if (smb_LANadapter == LANA_INVALID) {
9339 ncbp->ncb_command = NCBENUM;
9340 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9341 ncbp->ncb_length = sizeof(lana_list);
9342 code = Netbios(ncbp);
9344 afsi_log("Netbios NCBENUM error code %d", code);
9345 osi_panic(s, __FILE__, __LINE__);
9349 lana_list.length = 1;
9350 lana_list.lana[0] = smb_LANadapter;
9353 for (i = 0; i < lana_list.length; i++) {
9354 /* reset the adaptor: in Win32, this is required for every process, and
9355 * acts as an init call, not as a real hardware reset.
9357 ncbp->ncb_command = NCBRESET;
9358 ncbp->ncb_callname[0] = 100;
9359 ncbp->ncb_callname[2] = 100;
9360 ncbp->ncb_lana_num = lana_list.lana[i];
9361 code = Netbios(ncbp);
9363 code = ncbp->ncb_retcode;
9365 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9366 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9368 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9372 /* and declare our name so we can receive connections */
9373 memset(ncbp, 0, sizeof(*ncbp));
9374 len=lstrlen(smb_localNamep);
9375 memset(smb_sharename,' ',NCBNAMSZ);
9376 memcpy(smb_sharename,smb_localNamep,len);
9377 afsi_log("lana_list.length %d", lana_list.length);
9379 /* Keep the name so we can unregister it later */
9380 for (l = 0; l < lana_list.length; l++) {
9381 lana = lana_list.lana[l];
9383 ncbp->ncb_command = NCBADDNAME;
9384 ncbp->ncb_lana_num = lana;
9385 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9386 code = Netbios(ncbp);
9388 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9389 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9391 char name[NCBNAMSZ+1];
9393 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9394 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9398 code = ncbp->ncb_retcode;
9401 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9404 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9405 if (code == NRC_BRIDGE) { /* invalid LANA num */
9406 lana_list.lana[l] = LANA_INVALID;
9409 else if (code == NRC_DUPNAME) {
9410 afsi_log("Name already exists; try to delete it");
9411 memset(ncbp, 0, sizeof(*ncbp));
9412 ncbp->ncb_command = NCBDELNAME;
9413 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9414 ncbp->ncb_lana_num = lana;
9415 code = Netbios(ncbp);
9417 code = ncbp->ncb_retcode;
9419 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9421 if (code != 0 || delname_tried) {
9422 lana_list.lana[l] = LANA_INVALID;
9424 else if (code == 0) {
9425 if (!delname_tried) {
9433 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9434 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9438 smb_LANadapter = lana;
9439 lana_found = 1; /* at least one worked */
9443 osi_assertx(lana_list.length >= 0, "empty lana list");
9445 afsi_log("No valid LANA numbers found!");
9446 lana_list.length = 0;
9447 smb_LANadapter = LANA_INVALID;
9448 smb_ListenerState = SMB_LISTENER_STOPPED;
9449 cm_VolStatus_Network_Stopped(cm_NetbiosName
9456 /* we're done with the NCB now */
9459 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9460 if (lana_list.length > 0)
9461 osi_assert(smb_LANadapter != LANA_INVALID);
9464 lock_ReleaseMutex(&smb_StartedLock);
9466 return (lana_list.length > 0 ? 1 : 0);
9469 void smb_StartListeners(int locked)
9476 lock_ObtainMutex(&smb_StartedLock);
9478 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9480 lock_ReleaseMutex(&smb_StartedLock);
9484 afsi_log("smb_StartListeners");
9485 smb_ListenerState = SMB_LISTENER_STARTED;
9486 cm_VolStatus_Network_Started(cm_NetbiosName
9492 for (i = 0; i < lana_list.length; i++) {
9493 if (lana_list.lana[i] == LANA_INVALID)
9495 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9496 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9497 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9498 thrd_CloseHandle(phandle);
9501 lock_ReleaseMutex(&smb_StartedLock);
9504 void smb_RestartListeners(int locked)
9507 lock_ObtainMutex(&smb_StartedLock);
9509 if (powerStateSuspended)
9510 afsi_log("smb_RestartListeners called while suspended");
9512 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9513 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9514 if (smb_NetbiosInit(1))
9515 smb_StartListeners(1);
9516 } else if (smb_LanAdapterChangeDetected) {
9517 smb_LanAdapterChange(1);
9521 lock_ReleaseMutex(&smb_StartedLock);
9524 void smb_StopListener(NCB *ncbp, int lana, int wait)
9528 memset(ncbp, 0, sizeof(*ncbp));
9529 ncbp->ncb_command = NCBDELNAME;
9530 ncbp->ncb_lana_num = lana;
9531 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9532 code = Netbios(ncbp);
9534 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9535 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9537 /* and then reset the LANA; this will cause the listener threads to exit */
9538 ncbp->ncb_command = NCBRESET;
9539 ncbp->ncb_callname[0] = 100;
9540 ncbp->ncb_callname[2] = 100;
9541 ncbp->ncb_lana_num = lana;
9542 code = Netbios(ncbp);
9544 code = ncbp->ncb_retcode;
9546 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9548 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9552 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9555 void smb_StopListeners(int locked)
9561 lock_ObtainMutex(&smb_StartedLock);
9563 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9565 lock_ReleaseMutex(&smb_StartedLock);
9569 afsi_log("smb_StopListeners");
9570 smb_ListenerState = SMB_LISTENER_STOPPED;
9571 cm_VolStatus_Network_Stopped(cm_NetbiosName
9577 ncbp = smb_GetNCB();
9579 /* Unregister the SMB name */
9580 for (l = 0; l < lana_list.length; l++) {
9581 lana = lana_list.lana[l];
9583 if (lana != LANA_INVALID) {
9584 smb_StopListener(ncbp, lana, TRUE);
9586 /* mark the adapter invalid */
9587 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9591 /* force a re-evaluation of the network adapters */
9592 lana_list.length = 0;
9593 smb_LANadapter = LANA_INVALID;
9596 lock_ReleaseMutex(&smb_StartedLock);
9599 void smb_Init(osi_log_t *logp, int useV3,
9609 EVENT_HANDLE retHandle;
9610 char eventName[MAX_PATH];
9611 int startListeners = 0;
9613 smb_TlsRequestSlot = TlsAlloc();
9615 smb_MBfunc = aMBfunc;
9619 /* Initialize smb_localZero */
9620 myTime.tm_isdst = -1; /* compute whether on DST or not */
9621 myTime.tm_year = 70;
9627 smb_localZero = mktime(&myTime);
9629 #ifndef USE_NUMERIC_TIME_CONV
9630 /* Initialize kludge-GMT */
9631 smb_CalculateNowTZ();
9632 #endif /* USE_NUMERIC_TIME_CONV */
9633 #ifdef AFS_FREELANCE_CLIENT
9634 /* Make sure the root.afs volume has the correct time */
9635 cm_noteLocalMountPointChange();
9638 /* initialize the remote debugging log */
9641 /* and the global lock */
9642 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9643 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9645 /* Raw I/O data structures */
9646 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9648 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9649 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9651 /* 4 Raw I/O buffers */
9652 smb_RawBufs = calloc(65536,1);
9653 *((char **)smb_RawBufs) = NULL;
9654 for (i=0; i<3; i++) {
9655 char *rawBuf = calloc(65536,1);
9656 *((char **)rawBuf) = smb_RawBufs;
9657 smb_RawBufs = rawBuf;
9660 /* global free lists */
9661 smb_ncbFreeListp = NULL;
9662 smb_packetFreeListp = NULL;
9664 lock_ObtainMutex(&smb_StartedLock);
9665 startListeners = smb_NetbiosInit(1);
9667 /* Initialize listener and server structures */
9669 memset(dead_sessions, 0, sizeof(dead_sessions));
9670 sprintf(eventName, "SessionEvents[0]");
9671 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9672 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9673 afsi_log("Event Object Already Exists: %s", eventName);
9675 smb_NumServerThreads = nThreads;
9676 sprintf(eventName, "NCBavails[0]");
9677 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9678 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9679 afsi_log("Event Object Already Exists: %s", eventName);
9680 sprintf(eventName, "NCBevents[0]");
9681 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9682 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9683 afsi_log("Event Object Already Exists: %s", eventName);
9684 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9685 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9686 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9687 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9688 afsi_log("Event Object Already Exists: %s", eventName);
9689 for (i = 0; i < smb_NumServerThreads; i++) {
9690 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9691 NCBreturns[i][0] = retHandle;
9694 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9695 for (i = 0; i < smb_NumServerThreads; i++) {
9696 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9697 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9698 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9699 afsi_log("Event Object Already Exists: %s", eventName);
9700 InitNCBslot((int)(i+1));
9702 numNCBs = smb_NumServerThreads + 1;
9704 /* Initialize dispatch table */
9705 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9706 /* Prepare the table for unknown operations */
9707 for(i=0; i<= SMB_NOPCODES; i++) {
9708 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9710 /* Fill in the ones we do know */
9711 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9712 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9713 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9714 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9715 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9716 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9717 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9718 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9719 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9720 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9721 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9722 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9723 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9724 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9725 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9726 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9727 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9728 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9729 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9730 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9731 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9732 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9733 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9734 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9735 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9736 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9737 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9738 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9739 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9740 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9741 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9742 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9743 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9744 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9745 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9746 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9747 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9748 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9749 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9750 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9751 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9752 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9753 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9754 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9755 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9756 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9757 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9758 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9759 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9760 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9761 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9762 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9763 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9764 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9765 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9766 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9767 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9768 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9769 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9770 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9771 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9772 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9773 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9774 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9775 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9776 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9777 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9778 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9779 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9780 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9781 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9782 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9783 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9784 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9786 /* setup tran 2 dispatch table */
9787 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9788 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9789 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9790 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9791 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9792 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9793 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9794 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9795 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9796 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9797 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9798 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9799 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9800 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9801 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9802 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9803 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9804 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9806 /* setup the rap dispatch table */
9807 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9808 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9809 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9810 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9811 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9815 /* if we are doing SMB authentication we have register outselves as a logon process */
9816 if (smb_authType != SMB_AUTH_NONE) {
9817 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9818 LSA_STRING afsProcessName;
9819 LSA_OPERATIONAL_MODE dummy; /*junk*/
9821 afsProcessName.Buffer = "OpenAFSClientDaemon";
9822 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9823 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9825 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9827 if (nts == STATUS_SUCCESS) {
9828 LSA_STRING packageName;
9829 /* we are registered. Find out the security package id */
9830 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9831 packageName.Length = (USHORT)strlen(packageName.Buffer);
9832 packageName.MaximumLength = packageName.Length + 1;
9833 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9834 if (nts == STATUS_SUCCESS) {
9836 * This code forces Windows to authenticate against the Logon Cache
9837 * first instead of attempting to authenticate against the Domain
9838 * Controller. When the Windows logon cache is enabled this improves
9839 * performance by removing the network access and works around a bug
9840 * seen at sites which are using a MIT Kerberos principal to login
9841 * to machines joined to a non-root domain in a multi-domain forest.
9842 * MsV1_0SetProcessOption was added in Windows XP.
9844 PVOID pResponse = NULL;
9845 ULONG cbResponse = 0;
9846 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9848 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9849 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9850 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9851 OptionsRequest.DisableOptions = FALSE;
9853 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9856 sizeof(OptionsRequest),
9862 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9863 char message[AFSPATHMAX];
9864 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9866 OutputDebugString(message);
9869 OutputDebugString("MsV1_0SetProcessOption success");
9870 afsi_log("MsV1_0SetProcessOption success");
9872 /* END - code from Larry */
9874 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9875 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9876 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9878 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9880 /* something went wrong. We report the error and revert back to no authentication
9881 because we can't perform any auth requests without a successful lsa handle
9882 or sec package id. */
9883 afsi_log("Reverting to NO SMB AUTH");
9884 smb_authType = SMB_AUTH_NONE;
9887 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9889 /* something went wrong. We report the error and revert back to no authentication
9890 because we can't perform any auth requests without a successful lsa handle
9891 or sec package id. */
9892 afsi_log("Reverting to NO SMB AUTH");
9893 smb_authType = SMB_AUTH_NONE;
9897 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9898 * time prevents the failure of authentication when logged into Windows with an
9899 * external Kerberos principal mapped to a local account.
9901 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9902 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9903 * then the only option is NTLMSSP anyway; so just fallback.
9908 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9909 if (secBlobLength == 0) {
9910 smb_authType = SMB_AUTH_NTLM;
9911 afsi_log("Reverting to SMB AUTH NTLM");
9920 /* Now get ourselves a domain name. */
9921 /* For now we are using the local computer name as the domain name.
9922 * It is actually the domain for local logins, and we are acting as
9923 * a local SMB server.
9925 bufsize = lengthof(smb_ServerDomainName) - 1;
9926 GetComputerNameW(smb_ServerDomainName, &bufsize);
9927 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9928 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9931 /* Start listeners, waiters, servers, and daemons */
9933 smb_StartListeners(1);
9935 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9936 NULL, 0, &lpid, "smb_ClientWaiter");
9937 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9938 thrd_CloseHandle(phandle);
9940 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9941 NULL, 0, &lpid, "smb_ServerWaiter");
9942 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9943 thrd_CloseHandle(phandle);
9945 for (i=0; i<smb_NumServerThreads; i++) {
9946 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9947 (void *) i, 0, &lpid, "smb_Server");
9948 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9949 thrd_CloseHandle(phandle);
9952 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9953 NULL, 0, &lpid, "smb_Daemon");
9954 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9955 thrd_CloseHandle(phandle);
9957 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9958 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9959 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9960 thrd_CloseHandle(phandle);
9962 lock_ReleaseMutex(&smb_StartedLock);
9966 void smb_Shutdown(void)
9973 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9975 /* setup the NCB system */
9976 ncbp = smb_GetNCB();
9978 /* Block new sessions by setting shutdown flag */
9979 smbShutdownFlag = 1;
9981 /* Hang up all sessions */
9982 memset((char *)ncbp, 0, sizeof(NCB));
9983 for (i = 1; i < numSessions; i++)
9985 if (dead_sessions[i])
9988 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9989 ncbp->ncb_command = NCBHANGUP;
9990 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9991 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9992 code = Netbios(ncbp);
9993 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9994 if (code == 0) code = ncbp->ncb_retcode;
9996 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9997 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10001 /* Trigger the shutdown of all SMB threads */
10002 for (i = 0; i < smb_NumServerThreads; i++)
10003 thrd_SetEvent(NCBreturns[i][0]);
10005 thrd_SetEvent(NCBevents[0]);
10006 thrd_SetEvent(SessionEvents[0]);
10007 thrd_SetEvent(NCBavails[0]);
10009 for (i = 0;i < smb_NumServerThreads; i++) {
10010 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10011 if (code == WAIT_OBJECT_0) {
10014 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10015 thrd_SetEvent(NCBreturns[i--][0]);
10019 /* Delete Netbios name */
10020 memset((char *)ncbp, 0, sizeof(NCB));
10021 for (i = 0; i < lana_list.length; i++) {
10022 if (lana_list.lana[i] == LANA_INVALID) continue;
10023 ncbp->ncb_command = NCBDELNAME;
10024 ncbp->ncb_lana_num = lana_list.lana[i];
10025 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10026 code = Netbios(ncbp);
10028 code = ncbp->ncb_retcode;
10030 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10031 ncbp->ncb_lana_num, code);
10036 /* Release the reference counts held by the VCs */
10037 lock_ObtainWrite(&smb_rctLock);
10038 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10043 if (vcp->magic != SMB_VC_MAGIC)
10044 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10045 __FILE__, __LINE__);
10047 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10049 if (fidp->scp != NULL) {
10052 lock_ReleaseWrite(&smb_rctLock);
10053 lock_ObtainMutex(&fidp->mx);
10054 if (fidp->scp != NULL) {
10057 lock_ObtainWrite(&scp->rw);
10058 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10059 lock_ReleaseWrite(&scp->rw);
10060 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10061 cm_ReleaseSCache(scp);
10063 lock_ReleaseMutex(&fidp->mx);
10064 lock_ObtainWrite(&smb_rctLock);
10068 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10070 smb_ReleaseVCNoLock(tidp->vcp);
10072 cm_user_t *userp = tidp->userp;
10073 tidp->userp = NULL;
10074 cm_ReleaseUser(userp);
10078 lock_ReleaseWrite(&smb_rctLock);
10080 TlsFree(smb_TlsRequestSlot);
10083 /* Get the UNC \\<servername>\<sharename> prefix. */
10084 char *smb_GetSharename()
10089 /* Make sure we have been properly initialized. */
10090 if (smb_localNamep == NULL)
10093 /* Allocate space for \\<servername>\<sharename>, plus the
10096 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10097 name = malloc(len);
10098 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10104 void smb_LogPacket(smb_packet_t *packet)
10108 unsigned length, paramlen, datalen, i, j;
10110 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10112 if (!packet) return;
10114 osi_Log0(smb_logp, "*** SMB packet dump ***");
10116 smbp = (smb_t *) packet->data;
10117 vp = (BYTE *) packet->data;
10119 paramlen = smbp->wct * 2;
10120 datalen = *((WORD *) (smbp->vdata + paramlen));
10121 length = sizeof(*smbp) + paramlen + 1 + datalen;
10123 for (i=0;i < length; i+=16)
10125 memset( buf, ' ', 80 );
10128 itoa( i, buf, 16 );
10130 buf[strlen(buf)] = ' ';
10132 cp = (BYTE*) buf + 7;
10134 for (j=0;j < 16 && (i+j)<length; j++)
10136 *(cp++) = hex[vp[i+j] >> 4];
10137 *(cp++) = hex[vp[i+j] & 0xf];
10147 for (j=0;j < 16 && (i+j)<length;j++)
10149 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10160 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10163 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10165 #endif /* LOG_PACKET */
10168 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10174 smb_username_t *unp;
10175 smb_waitingLockRequest_t *wlrp;
10178 lock_ObtainRead(&smb_rctLock);
10180 sprintf(output, "begin dumping smb_username_t\r\n");
10181 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10182 for (unp = usernamesp; unp; unp=unp->nextp)
10184 cm_ucell_t *ucellp;
10186 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10187 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10188 unp->name ? unp->name : _C("NULL"),
10189 unp->machine ? unp->machine : _C("NULL"));
10190 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10192 sprintf(output, " begin dumping cm_ucell_t\r\n");
10193 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10195 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10196 sprintf(output, " %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
10197 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10198 ucellp->expirationTime, ucellp->gen,
10200 ucellp->cellp->name);
10201 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10204 sprintf(output, " done dumping cm_ucell_t\r\n");
10205 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10208 sprintf(output, "done dumping smb_username_t\r\n");
10209 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10212 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10213 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10216 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10217 smb_waitingLock_t *lockp;
10219 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10220 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10221 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10223 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10224 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10225 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10226 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10227 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10228 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10230 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10231 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10234 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10235 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10237 sprintf(output, "begin dumping smb_vc_t\r\n");
10238 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10240 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10246 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10247 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10248 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10250 sprintf(output, " begin dumping smb_user_t\r\n");
10251 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10252 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10253 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10254 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10255 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10257 sprintf(output, " done dumping smb_user_t\r\n");
10258 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10260 sprintf(output, " begin dumping smb_tid_t\r\n");
10261 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10262 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10263 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10264 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10265 tidp->pathname ? tidp->pathname : _C("NULL"));
10266 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10268 sprintf(output, " done dumping smb_tid_t\r\n");
10269 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10271 sprintf(output, " begin dumping smb_fid_t\r\n");
10272 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10274 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10276 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10277 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10278 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10279 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10280 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10283 sprintf(output, " done dumping smb_fid_t\r\n");
10284 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10287 sprintf(output, "done dumping smb_vc_t\r\n");
10288 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10290 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10291 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10293 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10299 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10300 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10301 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10303 sprintf(output, " begin dumping smb_user_t\r\n");
10304 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10305 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10306 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10307 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10308 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10310 sprintf(output, " done dumping smb_user_t\r\n");
10311 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10313 sprintf(output, " begin dumping smb_tid_t\r\n");
10314 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10315 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10316 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10317 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10318 tidp->pathname ? tidp->pathname : _C("NULL"));
10319 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10321 sprintf(output, " done dumping smb_tid_t\r\n");
10322 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10324 sprintf(output, " begin dumping smb_fid_t\r\n");
10325 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10327 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10329 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10330 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10331 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10332 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10333 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10336 sprintf(output, " done dumping smb_fid_t\r\n");
10337 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10340 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10344 lock_ReleaseRead(&smb_rctLock);
10348 long smb_IsNetworkStarted(void)
10351 lock_ObtainWrite(&smb_globalLock);
10352 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10353 lock_ReleaseWrite(&smb_globalLock);