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;
5944 cm_ReleaseSCache(tmpscp);
5949 /* do the vnode call */
5950 rock.odscp = oldDscp;
5951 rock.ndscp = newDscp;
5955 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5957 code = CM_ERROR_NOSUCHFILE;
5960 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5961 rock.newNamep = newLastNamep;
5962 rock.fsOldName[0] = '\0';
5963 rock.clOldName[0] = '\0';
5966 /* Now search the directory for the pattern, and do the appropriate rename when found */
5967 thyper.LowPart = 0; /* search dir from here */
5968 thyper.HighPart = 0;
5970 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5971 if (code == 0 && !rock.any) {
5973 thyper.HighPart = 0;
5974 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5975 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5977 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5979 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5980 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5981 rock.ndscp, rock.newNamep, rock.userp,
5983 /* if the call worked, stop doing the search now, since we
5984 * really only want to rename one file.
5987 osi_Log0(smb_logp, "cm_Rename failure");
5988 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5989 } else if (code == 0) {
5990 code = CM_ERROR_NOSUCHFILE;
5993 /* Handle Change Notification */
5995 * Being lazy, not distinguishing between files and dirs in this
5996 * filter, since we'd have to do a lookup.
5999 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6000 if (oldDscp == newDscp) {
6001 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6002 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6003 filter, oldDscp, rock.clOldName,
6004 newLastNamep, TRUE);
6006 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6007 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6008 filter, oldDscp, rock.clOldName,
6010 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6011 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6012 filter, newDscp, newLastNamep,
6019 cm_ReleaseSCache(tmpscp);
6021 cm_ReleaseUser(userp);
6023 cm_ReleaseSCache(oldDscp);
6025 cm_ReleaseSCache(newDscp);
6033 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6036 cm_space_t *spacep = NULL;
6037 cm_scache_t *oldDscp = NULL;
6038 cm_scache_t *newDscp = NULL;
6039 cm_scache_t *tmpscp= NULL;
6040 cm_scache_t *tmpscp2 = NULL;
6041 cm_scache_t *sscp = NULL;
6042 clientchar_t *oldLastNamep;
6043 clientchar_t *newLastNamep;
6046 clientchar_t *tidPathp;
6050 userp = smb_GetUserFromVCP(vcp, inp);
6052 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6054 cm_ReleaseUser(userp);
6055 return CM_ERROR_NOSUCHPATH;
6060 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6062 spacep = inp->spacep;
6063 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6065 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6066 userp, tidPathp, &req, &oldDscp);
6068 cm_ReleaseUser(userp);
6073 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6074 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6075 cm_ReleaseSCache(oldDscp);
6076 cm_ReleaseUser(userp);
6077 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6078 return CM_ERROR_PATH_NOT_COVERED;
6080 return CM_ERROR_BADSHARENAME;
6082 #endif /* DFS_SUPPORT */
6084 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6085 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6086 userp, tidPathp, &req, &newDscp);
6088 cm_ReleaseSCache(oldDscp);
6089 cm_ReleaseUser(userp);
6094 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6095 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6096 cm_ReleaseSCache(newDscp);
6097 cm_ReleaseSCache(oldDscp);
6098 cm_ReleaseUser(userp);
6099 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6100 return CM_ERROR_PATH_NOT_COVERED;
6102 return CM_ERROR_BADSHARENAME;
6104 #endif /* DFS_SUPPORT */
6106 /* Now, although we did two lookups for the two directories (because the same
6107 * directory can be referenced through different paths), we only allow hard links
6108 * within the same directory. */
6109 if (oldDscp != newDscp) {
6110 cm_ReleaseSCache(oldDscp);
6111 cm_ReleaseSCache(newDscp);
6112 cm_ReleaseUser(userp);
6113 return CM_ERROR_CROSSDEVLINK;
6116 /* handle the old name first */
6118 oldLastNamep = oldPathp;
6122 /* and handle the new name, too */
6124 newLastNamep = newPathp;
6128 /* now lookup the old name */
6129 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6130 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6132 cm_ReleaseSCache(oldDscp);
6133 cm_ReleaseSCache(newDscp);
6134 cm_ReleaseUser(userp);
6138 /* Check if the file already exists; if so return error */
6139 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6140 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6141 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6143 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6144 osi_LogSaveClientString(smb_logp, newLastNamep));
6146 /* if the existing link is to the same file, then we return success */
6148 if(sscp == tmpscp) {
6151 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6152 code = CM_ERROR_EXISTS;
6157 cm_ReleaseSCache(tmpscp);
6158 cm_ReleaseSCache(sscp);
6159 cm_ReleaseSCache(newDscp);
6160 cm_ReleaseSCache(oldDscp);
6161 cm_ReleaseUser(userp);
6165 /* now create the hardlink */
6166 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6167 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6168 osi_Log1(smb_logp," Link returns 0x%x", code);
6170 /* Handle Change Notification */
6172 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6173 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6174 smb_NotifyChange(FILE_ACTION_ADDED,
6175 filter, newDscp, newLastNamep,
6180 cm_ReleaseSCache(tmpscp);
6181 cm_ReleaseUser(userp);
6182 cm_ReleaseSCache(sscp);
6183 cm_ReleaseSCache(oldDscp);
6184 cm_ReleaseSCache(newDscp);
6188 /* SMB_COM_RENAME */
6190 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6192 clientchar_t *oldPathp;
6193 clientchar_t *newPathp;
6197 tp = smb_GetSMBData(inp, NULL);
6198 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6199 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6201 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6202 osi_LogSaveClientString(smb_logp, oldPathp),
6203 osi_LogSaveClientString(smb_logp, newPathp));
6205 if (!cm_IsValidClientString(newPathp)) {
6207 clientchar_t * hexp;
6209 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6210 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6211 osi_LogSaveClientString(smb_logp, hexp));
6215 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6217 return CM_ERROR_BADNTFILENAME;
6220 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6222 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6228 typedef struct smb_rmdirRock {
6232 normchar_t *maskp; /* pointer to the star pattern */
6235 cm_dirEntryList_t * matches;
6238 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6241 smb_rmdirRock_t *rockp;
6243 normchar_t matchName[MAX_PATH];
6245 rockp = (smb_rmdirRock_t *) vrockp;
6247 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6248 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6249 osi_LogSaveString(smb_logp, dep->name));
6253 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6254 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6256 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6258 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6259 !cm_Is8Dot3(matchName)) {
6260 cm_Gen8Dot3Name(dep, matchName, NULL);
6261 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6266 cm_DirEntryListAdd(dep->name, &rockp->matches);
6273 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6276 clientchar_t *pathp;
6280 clientchar_t *lastNamep;
6281 smb_rmdirRock_t rock;
6285 clientchar_t *tidPathp;
6289 memset(&rock, 0, sizeof(rock));
6291 tp = smb_GetSMBData(inp, NULL);
6292 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6294 spacep = inp->spacep;
6295 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6297 userp = smb_GetUserFromVCP(vcp, inp);
6299 caseFold = CM_FLAG_CASEFOLD;
6301 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6303 cm_ReleaseUser(userp);
6304 return CM_ERROR_NOSUCHPATH;
6306 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6307 userp, tidPathp, &req, &dscp);
6310 cm_ReleaseUser(userp);
6315 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6316 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6317 cm_ReleaseSCache(dscp);
6318 cm_ReleaseUser(userp);
6319 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6320 return CM_ERROR_PATH_NOT_COVERED;
6322 return CM_ERROR_BADSHARENAME;
6324 #endif /* DFS_SUPPORT */
6326 /* otherwise, scp points to the parent directory. */
6333 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6335 code = CM_ERROR_NOSUCHFILE;
6338 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6341 thyper.HighPart = 0;
6345 rock.matches = NULL;
6347 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6348 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6349 if (code == 0 && !rock.any) {
6351 thyper.HighPart = 0;
6352 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6353 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6356 if (code == 0 && rock.matches) {
6357 cm_dirEntryList_t * entry;
6359 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6360 clientchar_t clientName[MAX_PATH];
6362 /* We assume this will succeed because smb_RmdirProc()
6363 successfully converted entry->name once above. */
6364 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6366 osi_Log1(smb_logp, "Removing directory %s",
6367 osi_LogSaveString(smb_logp, entry->name));
6369 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6371 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6372 smb_NotifyChange(FILE_ACTION_REMOVED,
6373 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6374 dscp, clientName, NULL, TRUE);
6380 cm_DirEntryListFree(&rock.matches);
6383 cm_ReleaseUser(userp);
6386 cm_ReleaseSCache(dscp);
6388 if (code == 0 && !rock.any)
6389 code = CM_ERROR_NOSUCHFILE;
6398 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6408 fid = smb_GetSMBParm(inp, 0);
6410 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6412 fid = smb_ChainFID(fid, inp);
6413 fidp = smb_FindFID(vcp, fid, 0);
6415 return CM_ERROR_BADFD;
6417 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6418 smb_CloseFID(vcp, fidp, NULL, 0);
6419 smb_ReleaseFID(fidp);
6420 return CM_ERROR_NOSUCHFILE;
6423 lock_ObtainMutex(&fidp->mx);
6424 if (fidp->flags & SMB_FID_IOCTL) {
6425 lock_ReleaseMutex(&fidp->mx);
6426 smb_ReleaseFID(fidp);
6427 return CM_ERROR_BADFD;
6429 lock_ReleaseMutex(&fidp->mx);
6431 userp = smb_GetUserFromVCP(vcp, inp);
6433 lock_ObtainMutex(&fidp->mx);
6434 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6435 cm_scache_t * scp = fidp->scp;
6437 lock_ReleaseMutex(&fidp->mx);
6438 code = cm_FSync(scp, userp, &req);
6439 cm_ReleaseSCache(scp);
6442 lock_ReleaseMutex(&fidp->mx);
6445 smb_ReleaseFID(fidp);
6447 cm_ReleaseUser(userp);
6452 struct smb_FullNameRock {
6455 clientchar_t *fullName;
6456 fschar_t *originalName;
6459 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6462 normchar_t matchName[MAX_PATH];
6463 struct smb_FullNameRock *vrockp;
6465 vrockp = (struct smb_FullNameRock *)rockp;
6467 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6468 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6469 osi_LogSaveString(smb_logp, dep->name));
6473 if (!cm_Is8Dot3(matchName)) {
6474 clientchar_t shortName[13];
6476 cm_Gen8Dot3Name(dep, shortName, NULL);
6478 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6479 vrockp->fullName = cm_ClientStrDup(matchName);
6480 vrockp->originalName = cm_FsStrDup(dep->name);
6481 return CM_ERROR_STOPNOW;
6484 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6485 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6486 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6487 vrockp->fullName = cm_ClientStrDup(matchName);
6488 vrockp->originalName = cm_FsStrDup(dep->name);
6489 return CM_ERROR_STOPNOW;
6494 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6495 clientchar_t **newPathp, fschar_t ** originalPathp,
6496 cm_user_t *userp, cm_req_t *reqp)
6498 struct smb_FullNameRock rock;
6501 memset(&rock, 0, sizeof(rock));
6505 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6506 if (code == CM_ERROR_STOPNOW) {
6507 *newPathp = rock.fullName;
6508 *originalPathp = rock.originalName;
6510 *newPathp = cm_ClientStrDup(pathp);
6511 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6515 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6516 afs_uint32 dosTime) {
6519 cm_scache_t *dscp = NULL;
6520 clientchar_t *pathp = NULL;
6521 cm_scache_t * scp = NULL;
6522 cm_scache_t *delscp = NULL;
6523 int nullcreator = 0;
6525 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6526 fidp, fidp->fid, scp, vcp);
6529 lock_ObtainMutex(&fidp->mx);
6530 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6531 lock_ReleaseMutex(&fidp->mx);
6532 osi_Log0(smb_logp, " No user specified. Not closing fid");
6533 return CM_ERROR_BADFD;
6536 userp = fidp->userp; /* no hold required since fidp is held
6537 throughout the function */
6538 lock_ReleaseMutex(&fidp->mx);
6543 lock_ObtainWrite(&smb_rctLock);
6544 if (fidp->deleteOk) {
6545 osi_Log0(smb_logp, " Fid already closed.");
6546 lock_ReleaseWrite(&smb_rctLock);
6547 return CM_ERROR_BADFD;
6550 lock_ReleaseWrite(&smb_rctLock);
6552 lock_ObtainMutex(&fidp->mx);
6553 if (fidp->NTopen_dscp) {
6554 dscp = fidp->NTopen_dscp;
6555 cm_HoldSCache(dscp);
6558 if (fidp->NTopen_pathp) {
6559 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6567 /* Don't jump the gun on an async raw write */
6568 while (fidp->raw_writers) {
6569 lock_ReleaseMutex(&fidp->mx);
6570 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6571 lock_ObtainMutex(&fidp->mx);
6574 /* watch for ioctl closes, and read-only opens */
6576 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6577 == SMB_FID_OPENWRITE) {
6578 if (dosTime != 0 && dosTime != -1) {
6579 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6580 /* This fixes defect 10958 */
6581 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6582 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6584 if (smb_AsyncStore != 2) {
6585 lock_ReleaseMutex(&fidp->mx);
6586 code = cm_FSync(scp, userp, &req);
6587 lock_ObtainMutex(&fidp->mx);
6593 /* unlock any pending locks */
6594 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6595 scp->fileType == CM_SCACHETYPE_FILE) {
6599 lock_ReleaseMutex(&fidp->mx);
6601 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6603 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6604 lock_ObtainWrite(&scp->rw);
6606 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6607 CM_SCACHESYNC_NEEDCALLBACK
6608 | CM_SCACHESYNC_GETSTATUS
6609 | CM_SCACHESYNC_LOCK);
6613 "smb CoreClose SyncOp failure code 0x%x", tcode);
6614 goto post_syncopdone;
6617 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6619 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6623 lock_ReleaseWrite(&scp->rw);
6624 lock_ObtainMutex(&fidp->mx);
6627 if (fidp->flags & SMB_FID_DELONCLOSE) {
6628 clientchar_t *fullPathp = NULL;
6629 fschar_t *originalNamep = NULL;
6631 lock_ReleaseMutex(&fidp->mx);
6633 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6638 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6639 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6640 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6642 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6643 smb_NotifyChange(FILE_ACTION_REMOVED,
6644 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6645 dscp, fullPathp, NULL, TRUE);
6648 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6650 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6651 smb_NotifyChange(FILE_ACTION_REMOVED,
6652 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6653 dscp, fullPathp, NULL, TRUE);
6660 free(originalNamep);
6662 lock_ObtainMutex(&fidp->mx);
6663 fidp->flags &= ~SMB_FID_DELONCLOSE;
6666 /* if this was a newly created file, then clear the creator
6667 * in the stat cache entry. */
6668 if (fidp->flags & SMB_FID_CREATED) {
6670 fidp->flags &= ~SMB_FID_CREATED;
6673 if (fidp->flags & SMB_FID_NTOPEN) {
6674 cm_ReleaseSCache(fidp->NTopen_dscp);
6675 fidp->NTopen_dscp = NULL;
6676 free(fidp->NTopen_pathp);
6677 fidp->NTopen_pathp = NULL;
6678 fidp->flags &= ~SMB_FID_NTOPEN;
6680 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6681 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6684 if (fidp->NTopen_wholepathp) {
6685 free(fidp->NTopen_wholepathp);
6686 fidp->NTopen_wholepathp = NULL;
6690 cm_ReleaseSCache(fidp->scp);
6693 lock_ReleaseMutex(&fidp->mx);
6696 cm_ReleaseSCache(dscp);
6699 cm_ReleaseSCache(delscp);
6703 lock_ObtainWrite(&scp->rw);
6704 if (nullcreator && scp->creator == userp)
6705 scp->creator = NULL;
6706 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6707 lock_ReleaseWrite(&scp->rw);
6708 cm_ReleaseSCache(scp);
6718 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6726 fid = smb_GetSMBParm(inp, 0);
6727 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6729 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6731 fid = smb_ChainFID(fid, inp);
6732 fidp = smb_FindFID(vcp, fid, 0);
6734 return CM_ERROR_BADFD;
6737 userp = smb_GetUserFromVCP(vcp, inp);
6739 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6741 smb_ReleaseFID(fidp);
6742 cm_ReleaseUser(userp);
6747 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6749 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6750 cm_user_t *userp, long *readp)
6756 osi_hyper_t fileLength;
6758 osi_hyper_t lastByte;
6759 osi_hyper_t bufferOffset;
6763 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6766 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6767 fidp->fid, offsetp->LowPart, count);
6771 lock_ObtainMutex(&fidp->mx);
6772 /* make sure we have a readable FD */
6773 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6774 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6775 fidp->fid, fidp->flags);
6776 lock_ReleaseMutex(&fidp->mx);
6777 code = CM_ERROR_BADFDOP;
6788 lock_ObtainWrite(&scp->rw);
6790 if (offset.HighPart == 0) {
6791 chunk = offset.LowPart >> cm_logChunkSize;
6792 if (chunk != fidp->curr_chunk) {
6793 fidp->prev_chunk = fidp->curr_chunk;
6794 fidp->curr_chunk = chunk;
6796 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6799 lock_ReleaseMutex(&fidp->mx);
6801 /* start by looking up the file's end */
6802 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6803 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6807 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6809 /* now we have the entry locked, look up the length */
6810 fileLength = scp->length;
6812 /* adjust count down so that it won't go past EOF */
6813 thyper.LowPart = count;
6814 thyper.HighPart = 0;
6815 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6817 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6818 /* we'd read past EOF, so just stop at fileLength bytes.
6819 * Start by computing how many bytes remain in the file.
6821 thyper = LargeIntegerSubtract(fileLength, offset);
6823 /* if we are past EOF, read 0 bytes */
6824 if (LargeIntegerLessThanZero(thyper))
6827 count = thyper.LowPart;
6832 /* now, copy the data one buffer at a time,
6833 * until we've filled the request packet
6836 /* if we've copied all the data requested, we're done */
6837 if (count <= 0) break;
6839 /* otherwise, load up a buffer of data */
6840 thyper.HighPart = offset.HighPart;
6841 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6842 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6845 buf_Release(bufferp);
6848 lock_ReleaseWrite(&scp->rw);
6850 code = buf_Get(scp, &thyper, &bufferp);
6852 lock_ObtainWrite(&scp->rw);
6853 if (code) goto done;
6854 bufferOffset = thyper;
6856 /* now get the data in the cache */
6858 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6859 CM_SCACHESYNC_NEEDCALLBACK |
6860 CM_SCACHESYNC_READ);
6864 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6866 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6868 /* otherwise, load the buffer and try again */
6869 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6873 buf_Release(bufferp);
6877 } /* if (wrong buffer) ... */
6879 /* now we have the right buffer loaded. Copy out the
6880 * data from here to the user's buffer.
6882 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6884 /* and figure out how many bytes we want from this buffer */
6885 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6886 if (nbytes > count) nbytes = count; /* don't go past EOF */
6888 /* now copy the data */
6889 memcpy(op, bufferp->datap + bufIndex, nbytes);
6891 /* adjust counters, pointers, etc. */
6894 thyper.LowPart = nbytes;
6895 thyper.HighPart = 0;
6896 offset = LargeIntegerAdd(thyper, offset);
6900 lock_ReleaseWrite(&scp->rw);
6902 buf_Release(bufferp);
6904 if (code == 0 && sequential)
6905 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6907 cm_ReleaseSCache(scp);
6910 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6911 fidp->fid, code, *readp);
6916 * smb_WriteData -- common code for Write and Raw Write
6918 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6919 cm_user_t *userp, long *writtenp)
6921 osi_hyper_t offset = *offsetp;
6924 cm_scache_t *scp = NULL;
6925 osi_hyper_t fileLength; /* file's length at start of write */
6926 osi_hyper_t minLength; /* don't read past this */
6927 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6928 cm_buf_t *bufferp = NULL;
6929 osi_hyper_t thyper; /* hyper tmp variable */
6930 osi_hyper_t bufferOffset;
6931 afs_uint32 bufIndex; /* index in buffer where our data is */
6932 int doWriteBack = 0;
6933 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6937 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6938 fidp->fid, offsetp->LowPart, count);
6942 lock_ObtainMutex(&fidp->mx);
6943 /* make sure we have a writable FD */
6944 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6945 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6946 fidp->fid, fidp->flags);
6947 lock_ReleaseMutex(&fidp->mx);
6948 code = CM_ERROR_BADFDOP;
6956 lock_ReleaseMutex(&fidp->mx);
6958 lock_ObtainWrite(&scp->rw);
6959 /* start by looking up the file's end */
6960 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6961 CM_SCACHESYNC_NEEDCALLBACK
6962 | CM_SCACHESYNC_SETSTATUS
6963 | CM_SCACHESYNC_GETSTATUS);
6967 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6969 /* now we have the entry locked, look up the length */
6970 fileLength = scp->length;
6971 minLength = fileLength;
6972 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6973 minLength = scp->serverLength;
6975 /* adjust file length if we extend past EOF */
6976 thyper.LowPart = count;
6977 thyper.HighPart = 0;
6978 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6979 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6980 /* we'd write past EOF, so extend the file */
6981 scp->mask |= CM_SCACHEMASK_LENGTH;
6982 scp->length = thyper;
6983 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6985 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6987 /* now, if the new position (thyper) and the old (offset) are in
6988 * different storeback windows, remember to store back the previous
6989 * storeback window when we're done with the write.
6991 * the purpose of this logic is to slow down the CIFS client
6992 * in order to avoid the client disconnecting during the CLOSE
6993 * operation if there are too many dirty buffers left to write
6994 * than can be accomplished during 45 seconds. This used to be
6995 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6996 * so that we can read larger amounts of data at a time.
6998 if (smb_AsyncStore == 1 &&
6999 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7000 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7001 /* they're different */
7003 writeBackOffset.HighPart = offset.HighPart;
7004 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7009 /* now, copy the data one buffer at a time, until we've filled the
7012 /* if we've copied all the data requested, we're done */
7016 /* handle over quota or out of space */
7017 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7018 *writtenp = written;
7019 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7023 /* otherwise, load up a buffer of data */
7024 thyper.HighPart = offset.HighPart;
7025 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7026 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7029 lock_ReleaseMutex(&bufferp->mx);
7030 buf_Release(bufferp);
7033 lock_ReleaseWrite(&scp->rw);
7035 code = buf_Get(scp, &thyper, &bufferp);
7037 lock_ObtainMutex(&bufferp->mx);
7038 lock_ObtainWrite(&scp->rw);
7039 if (code) goto done;
7041 bufferOffset = thyper;
7043 /* now get the data in the cache */
7045 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7046 CM_SCACHESYNC_NEEDCALLBACK
7047 | CM_SCACHESYNC_WRITE
7048 | CM_SCACHESYNC_BUFLOCKED);
7052 cm_SyncOpDone(scp, bufferp,
7053 CM_SCACHESYNC_NEEDCALLBACK
7054 | CM_SCACHESYNC_WRITE
7055 | CM_SCACHESYNC_BUFLOCKED);
7057 /* If we're overwriting the entire buffer, or
7058 * if we're writing at or past EOF, mark the
7059 * buffer as current so we don't call
7060 * cm_GetBuffer. This skips the fetch from the
7061 * server in those cases where we're going to
7062 * obliterate all the data in the buffer anyway,
7063 * or in those cases where there is no useful
7064 * data at the server to start with.
7066 * Use minLength instead of scp->length, since
7067 * the latter has already been updated by this
7070 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7071 || LargeIntegerEqualTo(offset, bufferp->offset)
7072 && (count >= cm_data.buf_blockSize
7073 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7074 ConvertLongToLargeInteger(count)),
7076 if (count < cm_data.buf_blockSize
7077 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7078 memset(bufferp->datap, 0,
7079 cm_data.buf_blockSize);
7080 bufferp->dataVersion = scp->dataVersion;
7083 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7085 /* otherwise, load the buffer and try again */
7086 lock_ReleaseMutex(&bufferp->mx);
7087 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7089 lock_ReleaseWrite(&scp->rw);
7090 lock_ObtainMutex(&bufferp->mx);
7091 lock_ObtainWrite(&scp->rw);
7095 lock_ReleaseMutex(&bufferp->mx);
7096 buf_Release(bufferp);
7100 } /* if (wrong buffer) ... */
7102 /* now we have the right buffer loaded. Copy out the
7103 * data from here to the user's buffer.
7105 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7107 /* and figure out how many bytes we want from this buffer */
7108 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7110 nbytes = count; /* don't go past end of request */
7112 /* now copy the data */
7113 memcpy(bufferp->datap + bufIndex, op, nbytes);
7114 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7116 /* adjust counters, pointers, etc. */
7120 thyper.LowPart = nbytes;
7121 thyper.HighPart = 0;
7122 offset = LargeIntegerAdd(thyper, offset);
7126 lock_ReleaseWrite(&scp->rw);
7129 lock_ReleaseMutex(&bufferp->mx);
7130 buf_Release(bufferp);
7133 lock_ObtainMutex(&fidp->mx);
7134 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7135 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7137 lock_ReleaseMutex(&fidp->mx);
7138 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7139 fidp->NTopen_dscp, fidp->NTopen_pathp,
7142 lock_ReleaseMutex(&fidp->mx);
7146 if (smb_AsyncStore > 0) {
7150 lock_ObtainWrite(&scp->rw);
7151 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7153 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7154 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7156 lock_ReleaseWrite(&scp->rw);
7157 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7158 writeBackOffset.HighPart,
7159 smb_AsyncStoreSize, 0, userp);
7160 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7163 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7167 cm_ReleaseSCache(scp);
7170 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7171 fidp->fid, code, *writtenp);
7176 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7179 unsigned short count;
7181 unsigned short hint;
7182 long written = 0, total_written = 0;
7185 smb_t* smbp = (smb_t*) inp;
7188 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7190 int inDataBlockCount;
7192 fd = smb_GetSMBParm(inp, 0);
7193 count = smb_GetSMBParm(inp, 1);
7194 offset.HighPart = 0; /* too bad */
7195 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7196 hint = smb_GetSMBParm(inp, 4);
7198 op = smb_GetSMBData(inp, NULL);
7199 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7201 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7202 fd, offset.LowPart, count);
7204 fd = smb_ChainFID(fd, inp);
7205 fidp = smb_FindFID(vcp, fd, 0);
7207 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7208 return CM_ERROR_BADFD;
7211 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7212 smb_CloseFID(vcp, fidp, NULL, 0);
7213 smb_ReleaseFID(fidp);
7214 return CM_ERROR_NOSUCHFILE;
7217 lock_ObtainMutex(&fidp->mx);
7218 if (fidp->flags & SMB_FID_IOCTL) {
7219 lock_ReleaseMutex(&fidp->mx);
7220 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7221 smb_ReleaseFID(fidp);
7222 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7225 lock_ReleaseMutex(&fidp->mx);
7226 userp = smb_GetUserFromVCP(vcp, inp);
7230 LARGE_INTEGER LOffset;
7231 LARGE_INTEGER LLength;
7234 key = cm_GenerateKey(vcp->vcID, pid, fd);
7236 LOffset.HighPart = offset.HighPart;
7237 LOffset.LowPart = offset.LowPart;
7238 LLength.HighPart = 0;
7239 LLength.LowPart = count;
7241 lock_ObtainWrite(&fidp->scp->rw);
7242 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7243 lock_ReleaseWrite(&fidp->scp->rw);
7246 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7251 /* special case: 0 bytes transferred means truncate to this position */
7255 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7259 truncAttr.mask = CM_ATTRMASK_LENGTH;
7260 truncAttr.length.LowPart = offset.LowPart;
7261 truncAttr.length.HighPart = 0;
7262 lock_ObtainMutex(&fidp->mx);
7263 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7264 fidp->flags |= SMB_FID_LENGTHSETDONE;
7265 lock_ReleaseMutex(&fidp->mx);
7266 smb_SetSMBParm(outp, 0, 0 /* count */);
7267 smb_SetSMBDataLength(outp, 0);
7272 * Work around bug in NT client
7274 * When copying a file, the NT client should first copy the data,
7275 * then copy the last write time. But sometimes the NT client does
7276 * these in the wrong order, so the data copies would inadvertently
7277 * cause the last write time to be overwritten. We try to detect this,
7278 * and don't set client mod time if we think that would go against the
7281 lock_ObtainMutex(&fidp->mx);
7282 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7283 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7284 fidp->scp->clientModTime = time(NULL);
7286 lock_ReleaseMutex(&fidp->mx);
7289 while ( code == 0 && count > 0 ) {
7290 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7291 if (code == 0 && written == 0)
7292 code = CM_ERROR_PARTIALWRITE;
7294 offset = LargeIntegerAdd(offset,
7295 ConvertLongToLargeInteger(written));
7296 count -= (unsigned short)written;
7297 total_written += written;
7301 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7302 total_written, code);
7304 /* set the packet data length to 3 bytes for the data block header,
7305 * plus the size of the data.
7307 smb_SetSMBParm(outp, 0, total_written);
7308 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7309 smb_SetSMBParm(outp, 3, hint);
7310 smb_SetSMBDataLength(outp, 0);
7313 smb_ReleaseFID(fidp);
7314 cm_ReleaseUser(userp);
7319 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7320 NCB *ncbp, raw_write_cont_t *rwcp)
7329 fd = smb_GetSMBParm(inp, 0);
7330 fidp = smb_FindFID(vcp, fd, 0);
7332 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7333 smb_CloseFID(vcp, fidp, NULL, 0);
7334 smb_ReleaseFID(fidp);
7338 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7339 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7341 userp = smb_GetUserFromVCP(vcp, inp);
7344 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7346 if (rwcp->writeMode & 0x1) { /* synchronous */
7349 smb_FormatResponsePacket(vcp, inp, outp);
7350 op = (smb_t *) outp;
7351 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7352 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7353 smb_SetSMBDataLength(outp, 0);
7354 smb_SendPacket(vcp, outp);
7355 smb_FreePacket(outp);
7357 else { /* asynchronous */
7358 lock_ObtainMutex(&fidp->mx);
7359 fidp->raw_writers--;
7360 if (fidp->raw_writers == 0)
7361 thrd_SetEvent(fidp->raw_write_event);
7362 lock_ReleaseMutex(&fidp->mx);
7365 /* Give back raw buffer */
7366 lock_ObtainMutex(&smb_RawBufLock);
7367 *((char **)rawBuf) = smb_RawBufs;
7368 smb_RawBufs = rawBuf;
7369 lock_ReleaseMutex(&smb_RawBufLock);
7371 smb_ReleaseFID(fidp);
7372 cm_ReleaseUser(userp);
7375 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7380 /* SMB_COM_WRITE_RAW */
7381 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7384 long count, written = 0, total_written = 0;
7388 smb_t *smbp = (smb_t*) inp;
7392 unsigned short writeMode;
7394 fd = smb_GetSMBParm(inp, 0);
7395 totalCount = smb_GetSMBParm(inp, 1);
7396 count = smb_GetSMBParm(inp, 10);
7397 writeMode = smb_GetSMBParm(inp, 7);
7399 op = (char *) inp->data;
7400 op += smb_GetSMBParm(inp, 11);
7402 offset.HighPart = 0;
7403 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7405 if (*inp->wctp == 14) {
7406 /* we received a 64-bit file offset */
7407 #ifdef AFS_LARGEFILES
7408 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7410 if (LargeIntegerLessThanZero(offset)) {
7412 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7413 offset.HighPart, offset.LowPart);
7414 return CM_ERROR_BADSMB;
7417 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7419 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7420 return CM_ERROR_BADSMB;
7423 offset.HighPart = 0;
7426 offset.HighPart = 0; /* 32-bit file offset */
7430 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7431 fd, offset.HighPart, offset.LowPart, count);
7433 " WriteRaw WriteMode 0x%x",
7436 fd = smb_ChainFID(fd, inp);
7437 fidp = smb_FindFID(vcp, fd, 0);
7439 return CM_ERROR_BADFD;
7442 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7443 smb_CloseFID(vcp, fidp, NULL, 0);
7444 smb_ReleaseFID(fidp);
7445 return CM_ERROR_NOSUCHFILE;
7451 LARGE_INTEGER LOffset;
7452 LARGE_INTEGER LLength;
7455 key = cm_GenerateKey(vcp->vcID, pid, fd);
7457 LOffset.HighPart = offset.HighPart;
7458 LOffset.LowPart = offset.LowPart;
7459 LLength.HighPart = 0;
7460 LLength.LowPart = count;
7462 lock_ObtainWrite(&fidp->scp->rw);
7463 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7464 lock_ReleaseWrite(&fidp->scp->rw);
7467 smb_ReleaseFID(fidp);
7472 userp = smb_GetUserFromVCP(vcp, inp);
7475 * Work around bug in NT client
7477 * When copying a file, the NT client should first copy the data,
7478 * then copy the last write time. But sometimes the NT client does
7479 * these in the wrong order, so the data copies would inadvertently
7480 * cause the last write time to be overwritten. We try to detect this,
7481 * and don't set client mod time if we think that would go against the
7484 lock_ObtainMutex(&fidp->mx);
7485 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7486 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7487 fidp->scp->clientModTime = time(NULL);
7489 lock_ReleaseMutex(&fidp->mx);
7492 while ( code == 0 && count > 0 ) {
7493 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7494 if (code == 0 && written == 0)
7495 code = CM_ERROR_PARTIALWRITE;
7497 offset = LargeIntegerAdd(offset,
7498 ConvertLongToLargeInteger(written));
7501 total_written += written;
7505 /* Get a raw buffer */
7508 lock_ObtainMutex(&smb_RawBufLock);
7510 /* Get a raw buf, from head of list */
7511 rawBuf = smb_RawBufs;
7512 smb_RawBufs = *(char **)smb_RawBufs;
7515 code = CM_ERROR_USESTD;
7517 lock_ReleaseMutex(&smb_RawBufLock);
7520 /* Don't allow a premature Close */
7521 if (code == 0 && (writeMode & 1) == 0) {
7522 lock_ObtainMutex(&fidp->mx);
7523 fidp->raw_writers++;
7524 thrd_ResetEvent(fidp->raw_write_event);
7525 lock_ReleaseMutex(&fidp->mx);
7528 smb_ReleaseFID(fidp);
7529 cm_ReleaseUser(userp);
7532 smb_SetSMBParm(outp, 0, total_written);
7533 smb_SetSMBDataLength(outp, 0);
7534 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7539 offset = LargeIntegerAdd(offset,
7540 ConvertLongToLargeInteger(count));
7544 rwcp->offset.HighPart = offset.HighPart;
7545 rwcp->offset.LowPart = offset.LowPart;
7546 rwcp->count = totalCount - count;
7547 rwcp->writeMode = writeMode;
7548 rwcp->alreadyWritten = total_written;
7550 /* set the packet data length to 3 bytes for the data block header,
7551 * plus the size of the data.
7553 smb_SetSMBParm(outp, 0, 0xffff);
7554 smb_SetSMBDataLength(outp, 0);
7560 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7563 long count, finalCount;
7567 smb_t *smbp = (smb_t*) inp;
7572 fd = smb_GetSMBParm(inp, 0);
7573 count = smb_GetSMBParm(inp, 1);
7574 offset.HighPart = 0; /* too bad */
7575 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7577 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7578 fd, offset.LowPart, count);
7580 fd = smb_ChainFID(fd, inp);
7581 fidp = smb_FindFID(vcp, fd, 0);
7583 return CM_ERROR_BADFD;
7585 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7586 smb_CloseFID(vcp, fidp, NULL, 0);
7587 smb_ReleaseFID(fidp);
7588 return CM_ERROR_NOSUCHFILE;
7591 lock_ObtainMutex(&fidp->mx);
7592 if (fidp->flags & SMB_FID_IOCTL) {
7593 lock_ReleaseMutex(&fidp->mx);
7594 code = smb_IoctlRead(fidp, vcp, inp, outp);
7595 smb_ReleaseFID(fidp);
7598 lock_ReleaseMutex(&fidp->mx);
7601 LARGE_INTEGER LOffset, LLength;
7605 key = cm_GenerateKey(vcp->vcID, pid, fd);
7607 LOffset.HighPart = 0;
7608 LOffset.LowPart = offset.LowPart;
7609 LLength.HighPart = 0;
7610 LLength.LowPart = count;
7612 lock_ObtainWrite(&fidp->scp->rw);
7613 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7614 lock_ReleaseWrite(&fidp->scp->rw);
7617 smb_ReleaseFID(fidp);
7621 userp = smb_GetUserFromVCP(vcp, inp);
7623 /* remember this for final results */
7624 smb_SetSMBParm(outp, 0, count);
7625 smb_SetSMBParm(outp, 1, 0);
7626 smb_SetSMBParm(outp, 2, 0);
7627 smb_SetSMBParm(outp, 3, 0);
7628 smb_SetSMBParm(outp, 4, 0);
7630 /* set the packet data length to 3 bytes for the data block header,
7631 * plus the size of the data.
7633 smb_SetSMBDataLength(outp, count+3);
7635 /* get op ptr after putting in the parms, since otherwise we don't
7636 * know where the data really is.
7638 op = smb_GetSMBData(outp, NULL);
7640 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7641 *op++ = 1; /* data block marker */
7642 *op++ = (unsigned char) (count & 0xff);
7643 *op++ = (unsigned char) ((count >> 8) & 0xff);
7645 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7647 /* fix some things up */
7648 smb_SetSMBParm(outp, 0, finalCount);
7649 smb_SetSMBDataLength(outp, finalCount+3);
7651 smb_ReleaseFID(fidp);
7653 cm_ReleaseUser(userp);
7657 /* SMB_COM_CREATE_DIRECTORY */
7658 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7660 clientchar_t *pathp;
7665 cm_scache_t *dscp; /* dir we're dealing with */
7666 cm_scache_t *scp; /* file we're creating */
7668 int initialModeBits;
7669 clientchar_t *lastNamep;
7671 clientchar_t *tidPathp;
7678 /* compute initial mode bits based on read-only flag in attributes */
7679 initialModeBits = 0777;
7681 tp = smb_GetSMBData(inp, NULL);
7682 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7684 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7685 return CM_ERROR_EXISTS;
7687 spacep = inp->spacep;
7688 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7690 userp = smb_GetUserFromVCP(vcp, inp);
7692 caseFold = CM_FLAG_CASEFOLD;
7694 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7696 cm_ReleaseUser(userp);
7697 return CM_ERROR_NOSUCHPATH;
7700 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7701 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7702 userp, tidPathp, &req, &dscp);
7705 cm_ReleaseUser(userp);
7710 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7711 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7712 cm_ReleaseSCache(dscp);
7713 cm_ReleaseUser(userp);
7714 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7715 return CM_ERROR_PATH_NOT_COVERED;
7717 return CM_ERROR_BADSHARENAME;
7719 #endif /* DFS_SUPPORT */
7721 /* otherwise, scp points to the parent directory. Do a lookup, and
7722 * fail if we find it. Otherwise, we do the create.
7728 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7729 if (scp) cm_ReleaseSCache(scp);
7730 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7731 if (code == 0) code = CM_ERROR_EXISTS;
7732 cm_ReleaseSCache(dscp);
7733 cm_ReleaseUser(userp);
7737 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7738 setAttr.clientModTime = time(NULL);
7739 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7740 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7741 smb_NotifyChange(FILE_ACTION_ADDED,
7742 FILE_NOTIFY_CHANGE_DIR_NAME,
7743 dscp, lastNamep, NULL, TRUE);
7745 /* we don't need this any longer */
7746 cm_ReleaseSCache(dscp);
7749 /* something went wrong creating or truncating the file */
7750 cm_ReleaseUser(userp);
7754 /* otherwise we succeeded */
7755 smb_SetSMBDataLength(outp, 0);
7756 cm_ReleaseUser(userp);
7761 BOOL smb_IsLegalFilename(clientchar_t *filename)
7764 * Find the longest substring of filename that does not contain
7765 * any of the chars in illegalChars. If that substring is less
7766 * than the length of the whole string, then one or more of the
7767 * illegal chars is in filename.
7769 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7775 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7776 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7778 clientchar_t *pathp;
7784 cm_scache_t *dscp; /* dir we're dealing with */
7785 cm_scache_t *scp; /* file we're creating */
7787 int initialModeBits;
7790 clientchar_t *lastNamep;
7793 clientchar_t *tidPathp;
7795 int created = 0; /* the file was new */
7800 excl = (inp->inCom == 0x03)? 0 : 1;
7802 attributes = smb_GetSMBParm(inp, 0);
7803 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7805 /* compute initial mode bits based on read-only flag in attributes */
7806 initialModeBits = 0666;
7807 if (attributes & SMB_ATTR_READONLY)
7808 initialModeBits &= ~0222;
7810 tp = smb_GetSMBData(inp, NULL);
7811 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7813 if (!cm_IsValidClientString(pathp)) {
7815 clientchar_t * hexp;
7817 hexp = cm_GetRawCharsAlloc(pathp, -1);
7818 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7819 osi_LogSaveClientString(smb_logp, hexp));
7823 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7825 return CM_ERROR_BADNTFILENAME;
7828 spacep = inp->spacep;
7829 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7831 userp = smb_GetUserFromVCP(vcp, inp);
7833 caseFold = CM_FLAG_CASEFOLD;
7835 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7837 cm_ReleaseUser(userp);
7838 return CM_ERROR_NOSUCHPATH;
7840 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7841 userp, tidPathp, &req, &dscp);
7844 cm_ReleaseUser(userp);
7849 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7850 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7851 cm_ReleaseSCache(dscp);
7852 cm_ReleaseUser(userp);
7853 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7854 return CM_ERROR_PATH_NOT_COVERED;
7856 return CM_ERROR_BADSHARENAME;
7858 #endif /* DFS_SUPPORT */
7860 /* otherwise, scp points to the parent directory. Do a lookup, and
7861 * truncate the file if we find it, otherwise we create the file.
7868 if (!smb_IsLegalFilename(lastNamep))
7869 return CM_ERROR_BADNTFILENAME;
7871 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7872 #ifdef DEBUG_VERBOSE
7875 hexp = osi_HexifyString( lastNamep );
7876 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7881 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7882 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7883 cm_ReleaseSCache(dscp);
7884 cm_ReleaseUser(userp);
7888 /* if we get here, if code is 0, the file exists and is represented by
7889 * scp. Otherwise, we have to create it.
7893 /* oops, file shouldn't be there */
7894 cm_ReleaseSCache(dscp);
7895 cm_ReleaseSCache(scp);
7896 cm_ReleaseUser(userp);
7897 return CM_ERROR_EXISTS;
7900 setAttr.mask = CM_ATTRMASK_LENGTH;
7901 setAttr.length.LowPart = 0;
7902 setAttr.length.HighPart = 0;
7903 code = cm_SetAttr(scp, &setAttr, userp, &req);
7906 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7907 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7908 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7912 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7913 smb_NotifyChange(FILE_ACTION_ADDED,
7914 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7915 dscp, lastNamep, NULL, TRUE);
7916 } else if (!excl && code == CM_ERROR_EXISTS) {
7917 /* not an exclusive create, and someone else tried
7918 * creating it already, then we open it anyway. We
7919 * don't bother retrying after this, since if this next
7920 * fails, that means that the file was deleted after
7921 * we started this call.
7923 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7926 setAttr.mask = CM_ATTRMASK_LENGTH;
7927 setAttr.length.LowPart = 0;
7928 setAttr.length.HighPart = 0;
7929 code = cm_SetAttr(scp, &setAttr, userp, &req);
7934 /* we don't need this any longer */
7935 cm_ReleaseSCache(dscp);
7938 /* something went wrong creating or truncating the file */
7939 if (scp) cm_ReleaseSCache(scp);
7940 cm_ReleaseUser(userp);
7944 /* make sure we only open files */
7945 if (scp->fileType != CM_SCACHETYPE_FILE) {
7946 cm_ReleaseSCache(scp);
7947 cm_ReleaseUser(userp);
7948 return CM_ERROR_ISDIR;
7951 /* now all we have to do is open the file itself */
7952 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7953 osi_assertx(fidp, "null smb_fid_t");
7957 lock_ObtainMutex(&fidp->mx);
7958 /* always create it open for read/write */
7959 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7961 /* remember that the file was newly created */
7963 fidp->flags |= SMB_FID_CREATED;
7965 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7967 /* save a pointer to the vnode */
7969 lock_ObtainWrite(&scp->rw);
7970 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7971 lock_ReleaseWrite(&scp->rw);
7974 fidp->userp = userp;
7975 lock_ReleaseMutex(&fidp->mx);
7977 smb_SetSMBParm(outp, 0, fidp->fid);
7978 smb_SetSMBDataLength(outp, 0);
7980 cm_Open(scp, 0, userp);
7982 smb_ReleaseFID(fidp);
7983 cm_ReleaseUser(userp);
7984 /* leave scp held since we put it in fidp->scp */
7989 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7992 osi_hyper_t new_offset;
8003 fd = smb_GetSMBParm(inp, 0);
8004 whence = smb_GetSMBParm(inp, 1);
8005 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8007 /* try to find the file descriptor */
8008 fd = smb_ChainFID(fd, inp);
8009 fidp = smb_FindFID(vcp, fd, 0);
8011 return CM_ERROR_BADFD;
8013 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8014 smb_CloseFID(vcp, fidp, NULL, 0);
8015 smb_ReleaseFID(fidp);
8016 return CM_ERROR_NOSUCHFILE;
8019 lock_ObtainMutex(&fidp->mx);
8020 if (fidp->flags & SMB_FID_IOCTL) {
8021 lock_ReleaseMutex(&fidp->mx);
8022 smb_ReleaseFID(fidp);
8023 return CM_ERROR_BADFD;
8025 lock_ReleaseMutex(&fidp->mx);
8027 userp = smb_GetUserFromVCP(vcp, inp);
8029 lock_ObtainMutex(&fidp->mx);
8032 lock_ReleaseMutex(&fidp->mx);
8033 lock_ObtainWrite(&scp->rw);
8034 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8035 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8037 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8039 /* offset from current offset */
8040 new_offset = LargeIntegerAdd(fidp->offset,
8041 ConvertLongToLargeInteger(offset));
8043 else if (whence == 2) {
8044 /* offset from current EOF */
8045 new_offset = LargeIntegerAdd(scp->length,
8046 ConvertLongToLargeInteger(offset));
8048 new_offset = ConvertLongToLargeInteger(offset);
8051 fidp->offset = new_offset;
8052 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8053 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8054 smb_SetSMBDataLength(outp, 0);
8056 lock_ReleaseWrite(&scp->rw);
8057 smb_ReleaseFID(fidp);
8058 cm_ReleaseSCache(scp);
8059 cm_ReleaseUser(userp);
8063 /* dispatch all of the requests received in a packet. Due to chaining, this may
8064 * be more than one request.
8066 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8067 NCB *ncbp, raw_write_cont_t *rwcp)
8071 unsigned long code = 0;
8072 unsigned char *outWctp;
8073 int nparms; /* # of bytes of parameters */
8075 int nbytes; /* bytes of data, excluding count */
8078 unsigned short errCode;
8079 unsigned long NTStatus;
8081 unsigned char errClass;
8082 unsigned int oldGen;
8083 DWORD oldTime, newTime;
8085 /* get easy pointer to the data */
8086 smbp = (smb_t *) inp->data;
8088 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8089 /* setup the basic parms for the initial request in the packet */
8090 inp->inCom = smbp->com;
8091 inp->wctp = &smbp->wct;
8093 inp->ncb_length = ncbp->ncb_length;
8098 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8099 /* log it and discard it */
8100 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8101 __FILE__, __LINE__, ncbp->ncb_length);
8102 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8106 /* We are an ongoing op */
8107 thrd_Increment(&ongoingOps);
8109 /* set up response packet for receiving output */
8110 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8111 smb_FormatResponsePacket(vcp, inp, outp);
8112 outWctp = outp->wctp;
8114 /* Remember session generation number and time */
8115 oldGen = sessionGen;
8116 oldTime = GetTickCount();
8118 while (inp->inCom != 0xff) {
8119 dp = &smb_dispatchTable[inp->inCom];
8121 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8122 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8123 code = outp->resumeCode;
8127 /* process each request in the packet; inCom, wctp and inCount
8128 * are already set up.
8130 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8133 /* now do the dispatch */
8134 /* start by formatting the response record a little, as a default */
8135 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8137 outWctp[1] = 0xff; /* no operation */
8138 outWctp[2] = 0; /* padding */
8143 /* not a chained request, this is a more reasonable default */
8144 outWctp[0] = 0; /* wct of zero */
8145 outWctp[1] = 0; /* and bcc (word) of zero */
8149 /* once set, stays set. Doesn't matter, since we never chain
8150 * "no response" calls.
8152 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8156 /* we have a recognized operation */
8157 char * opName = myCrt_Dispatch(inp->inCom);
8159 if (inp->inCom == 0x1d)
8161 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8163 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8164 opName,vcp,vcp->lana,vcp->lsn);
8165 code = (*(dp->procp)) (vcp, inp, outp);
8166 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8167 code,vcp,vcp->lana,vcp->lsn);
8169 if ( code == CM_ERROR_BADSMB ||
8170 code == CM_ERROR_BADOP )
8172 #endif /* LOG_PACKET */
8175 newTime = GetTickCount();
8176 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8178 /* ReceiveV3Tran2A handles its own logging */
8179 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8182 clientchar_t *treepath = NULL; /* do not free */
8183 clientchar_t *pathname = NULL;
8184 cm_fid_t afid = {0,0,0,0,0};
8186 uidp = smb_FindUID(vcp, smbp->uid, 0);
8187 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8188 fidp = smb_FindFID(vcp, inp->fid, 0);
8190 if (fidp && fidp->NTopen_pathp)
8191 pathname = fidp->NTopen_pathp;
8192 else if (inp->stringsp->wdata)
8193 pathname = inp->stringsp->wdata;
8195 if (fidp && fidp->scp)
8196 afid = fidp->scp->fid;
8198 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8199 opName, newTime - oldTime,
8200 uidp ? uidp->unp->name : NULL,
8203 afid.cell, afid.volume, afid.vnode, afid.unique);
8206 smb_ReleaseUID(uidp);
8208 smb_ReleaseFID(fidp);
8211 if (oldGen != sessionGen) {
8212 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8213 newTime - oldTime, ncbp->ncb_length);
8214 osi_Log3(smb_logp, "Request %s straddled session startup, "
8215 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8218 FreeSMBStrings(inp);
8220 /* bad opcode, fail the request, after displaying it */
8221 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8224 #endif /* LOG_PACKET */
8227 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8228 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8229 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8230 if (code == IDCANCEL)
8233 code = CM_ERROR_BADOP;
8236 /* catastrophic failure: log as much as possible */
8237 if (code == CM_ERROR_BADSMB) {
8238 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8242 #endif /* LOG_PACKET */
8243 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8246 code = CM_ERROR_INVAL;
8249 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8250 thrd_Decrement(&ongoingOps);
8255 /* now, if we failed, turn the current response into an empty
8256 * one, and fill in the response packet's error code.
8259 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8260 smb_MapNTError(code, &NTStatus);
8261 outWctp = outp->wctp;
8262 smbp = (smb_t *) &outp->data;
8263 if (code != CM_ERROR_PARTIALWRITE
8264 && code != CM_ERROR_BUFFERTOOSMALL
8265 && code != CM_ERROR_GSSCONTINUE) {
8266 /* nuke wct and bcc. For a partial
8267 * write or an in-process authentication handshake,
8268 * assume they're OK.
8274 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8275 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8276 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8277 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8278 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8282 smb_MapCoreError(code, vcp, &errCode, &errClass);
8283 outWctp = outp->wctp;
8284 smbp = (smb_t *) &outp->data;
8285 if (code != CM_ERROR_PARTIALWRITE) {
8286 /* nuke wct and bcc. For a partial
8287 * write, assume they're OK.
8293 smbp->errLow = (unsigned char) (errCode & 0xff);
8294 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8295 smbp->rcls = errClass;
8298 } /* error occurred */
8300 /* if we're here, we've finished one request. Look to see if
8301 * this is a chained opcode. If it is, setup things to process
8302 * the chained request, and setup the output buffer to hold the
8303 * chained response. Start by finding the next input record.
8305 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8306 break; /* not a chained req */
8307 tp = inp->wctp; /* points to start of last request */
8308 /* in a chained request, the first two
8309 * parm fields are required, and are
8310 * AndXCommand/AndXReserved and
8312 if (tp[0] < 2) break;
8313 if (tp[1] == 0xff) break; /* no more chained opcodes */
8315 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8318 /* and now append the next output request to the end of this
8319 * last request. Begin by finding out where the last response
8320 * ends, since that's where we'll put our new response.
8322 outWctp = outp->wctp; /* ptr to out parameters */
8323 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8324 nparms = outWctp[0] << 1;
8325 tp = outWctp + nparms + 1; /* now points to bcc field */
8326 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8327 tp += 2 /* for the count itself */ + nbytes;
8328 /* tp now points to the new output record; go back and patch the
8329 * second parameter (off2) to point to the new record.
8331 temp = (unsigned int)(tp - outp->data);
8332 outWctp[3] = (unsigned char) (temp & 0xff);
8333 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8334 outWctp[2] = 0; /* padding */
8335 outWctp[1] = inp->inCom; /* next opcode */
8337 /* finally, setup for the next iteration */
8340 } /* while loop over all requests in the packet */
8342 /* now send the output packet, and return */
8344 smb_SendPacket(vcp, outp);
8345 thrd_Decrement(&ongoingOps);
8350 /* Wait for Netbios() calls to return, and make the results available to server
8351 * threads. Note that server threads can't wait on the NCBevents array
8352 * themselves, because NCB events are manual-reset, and the servers would race
8353 * each other to reset them.
8355 void smb_ClientWaiter(void *parmp)
8360 while (smbShutdownFlag == 0) {
8361 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8363 if (code == WAIT_OBJECT_0)
8366 /* error checking */
8367 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8369 int abandonIdx = code - WAIT_ABANDONED_0;
8370 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8373 if (code == WAIT_IO_COMPLETION)
8375 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8379 if (code == WAIT_TIMEOUT)
8381 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8384 if (code == WAIT_FAILED)
8386 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8389 idx = code - WAIT_OBJECT_0;
8391 /* check idx range! */
8392 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8394 /* this is fatal - log as much as possible */
8395 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8396 osi_assertx(0, "invalid index");
8399 thrd_ResetEvent(NCBevents[idx]);
8400 thrd_SetEvent(NCBreturns[0][idx]);
8405 * Try to have one NCBRECV request waiting for every live session. Not more
8406 * than one, because if there is more than one, it's hard to handle Write Raw.
8408 void smb_ServerWaiter(void *parmp)
8411 int idx_session, idx_NCB;
8414 while (smbShutdownFlag == 0) {
8416 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8418 if (code == WAIT_OBJECT_0)
8421 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8423 int abandonIdx = code - WAIT_ABANDONED_0;
8424 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8427 if (code == WAIT_IO_COMPLETION)
8429 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8433 if (code == WAIT_TIMEOUT)
8435 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8438 if (code == WAIT_FAILED)
8440 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8443 idx_session = code - WAIT_OBJECT_0;
8445 /* check idx range! */
8446 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8448 /* this is fatal - log as much as possible */
8449 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8450 osi_assertx(0, "invalid index");
8455 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8457 if (code == WAIT_OBJECT_0) {
8458 if (smbShutdownFlag == 1)
8464 /* error checking */
8465 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8467 int abandonIdx = code - WAIT_ABANDONED_0;
8468 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8471 if (code == WAIT_IO_COMPLETION)
8473 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8477 if (code == WAIT_TIMEOUT)
8479 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8482 if (code == WAIT_FAILED)
8484 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8487 idx_NCB = code - WAIT_OBJECT_0;
8489 /* check idx range! */
8490 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8492 /* this is fatal - log as much as possible */
8493 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8494 osi_assertx(0, "invalid index");
8497 /* Link them together */
8498 NCBsessions[idx_NCB] = idx_session;
8501 ncbp = NCBs[idx_NCB];
8502 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8503 ncbp->ncb_command = NCBRECV | ASYNCH;
8504 ncbp->ncb_lana_num = lanas[idx_session];
8505 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8506 ncbp->ncb_event = NCBevents[idx_NCB];
8507 ncbp->ncb_length = SMB_PACKETSIZE;
8513 * The top level loop for handling SMB request messages. Each server thread
8514 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8515 * NCB and buffer for the incoming request are loaned to us.
8517 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8518 * to immediately send a request for the rest of the data. This must come
8519 * before any other traffic for that session, so we delay setting the session
8520 * event until that data has come in.
8522 void smb_Server(VOID *parmp)
8524 INT_PTR myIdx = (INT_PTR) parmp;
8528 smb_packet_t *outbufp;
8530 int idx_NCB, idx_session;
8532 smb_vc_t *vcp = NULL;
8534 extern void rx_StartClientThread(void);
8536 rx_StartClientThread();
8538 outncbp = smb_GetNCB();
8539 outbufp = smb_GetPacket();
8540 outbufp->ncbp = outncbp;
8548 smb_ResetServerPriority();
8550 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8553 /* terminate silently if shutdown flag is set */
8554 if (code == WAIT_OBJECT_0) {
8555 if (smbShutdownFlag == 1) {
8556 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8562 /* error checking */
8563 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8565 int abandonIdx = code - WAIT_ABANDONED_0;
8566 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8569 if (code == WAIT_IO_COMPLETION)
8571 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8575 if (code == WAIT_TIMEOUT)
8577 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8580 if (code == WAIT_FAILED)
8582 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8585 idx_NCB = code - WAIT_OBJECT_0;
8587 /* check idx range! */
8588 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8590 /* this is fatal - log as much as possible */
8591 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8592 osi_assertx(0, "invalid index");
8595 ncbp = NCBs[idx_NCB];
8596 idx_session = NCBsessions[idx_NCB];
8597 rc = ncbp->ncb_retcode;
8599 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8600 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8604 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8608 /* Can this happen? Or is it just my UNIX paranoia? */
8609 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8614 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8617 /* Client closed session */
8618 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8620 lock_ObtainMutex(&vcp->mx);
8621 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8622 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8624 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8625 lock_ReleaseMutex(&vcp->mx);
8626 lock_ObtainWrite(&smb_globalLock);
8627 dead_sessions[vcp->session] = TRUE;
8628 lock_ReleaseWrite(&smb_globalLock);
8630 lock_ReleaseMutex(&vcp->mx);
8632 smb_CleanupDeadVC(vcp);
8639 /* Treat as transient error */
8640 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8643 "dispatch smb recv failed, message incomplete, ncb_length %d",
8646 "SMB message incomplete, "
8647 "length %d", ncbp->ncb_length);
8650 * We used to discard the packet.
8651 * Instead, try handling it normally.
8655 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8659 /* A weird error code. Log it, sleep, and continue. */
8660 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8662 lock_ObtainMutex(&vcp->mx);
8663 if (vcp->errorCount++ > 3) {
8664 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8665 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8666 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8668 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8669 lock_ReleaseMutex(&vcp->mx);
8670 lock_ObtainWrite(&smb_globalLock);
8671 dead_sessions[vcp->session] = TRUE;
8672 lock_ReleaseWrite(&smb_globalLock);
8674 lock_ReleaseMutex(&vcp->mx);
8676 smb_CleanupDeadVC(vcp);
8682 lock_ReleaseMutex(&vcp->mx);
8686 thrd_SetEvent(SessionEvents[idx_session]);
8692 /* Success, so now dispatch on all the data in the packet */
8694 smb_concurrentCalls++;
8695 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8696 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8699 * If at this point vcp is NULL (implies that packet was invalid)
8700 * then we are in big trouble. This means either :
8701 * a) we have the wrong NCB.
8702 * b) Netbios screwed up the call.
8703 * c) The VC was already marked dead before we were able to
8705 * Obviously this implies that
8706 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8707 * lanas[idx_session] != ncbp->ncb_lana_num )
8708 * Either way, we can't do anything with this packet.
8709 * Log, sleep and resume.
8712 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8716 ncbp->ncb_lana_num);
8718 /* Also log in the trace log. */
8719 osi_Log4(smb_logp, "Server: VCP does not exist!"
8720 "LSNs[idx_session]=[%d],"
8721 "lanas[idx_session]=[%d],"
8722 "ncbp->ncb_lsn=[%d],"
8723 "ncbp->ncb_lana_num=[%d]",
8727 ncbp->ncb_lana_num);
8729 /* thrd_Sleep(1000); Don't bother sleeping */
8730 thrd_SetEvent(SessionEvents[idx_session]);
8731 smb_concurrentCalls--;
8735 smb_SetRequestStartTime();
8737 vcp->errorCount = 0;
8738 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8739 smbp = (smb_t *)bufp->data;
8746 if (smbp->com == 0x1d) {
8747 /* Special handling for Write Raw */
8748 raw_write_cont_t rwc;
8749 EVENT_HANDLE rwevent;
8750 char eventName[MAX_PATH];
8752 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8753 if (rwc.code == 0) {
8754 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8755 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8756 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8757 ncbp->ncb_command = NCBRECV | ASYNCH;
8758 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8759 ncbp->ncb_lana_num = vcp->lana;
8760 ncbp->ncb_buffer = rwc.buf;
8761 ncbp->ncb_length = 65535;
8762 ncbp->ncb_event = rwevent;
8764 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8765 thrd_CloseHandle(rwevent);
8767 thrd_SetEvent(SessionEvents[idx_session]);
8769 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8771 else if (smbp->com == 0xa0) {
8773 * Serialize the handling for NT Transact
8776 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8777 thrd_SetEvent(SessionEvents[idx_session]);
8779 thrd_SetEvent(SessionEvents[idx_session]);
8780 /* TODO: what else needs to be serialized? */
8781 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8785 __except( smb_ServerExceptionFilter() ) {
8789 smb_concurrentCalls--;
8792 thrd_SetEvent(NCBavails[idx_NCB]);
8797 smb_FreePacket(outbufp);
8799 smb_FreeNCB(outncbp);
8803 * Exception filter for the server threads. If an exception occurs in the
8804 * dispatch routines, which is where exceptions are most common, then do a
8805 * force trace and give control to upstream exception handlers. Useful for
8808 DWORD smb_ServerExceptionFilter(void) {
8809 /* While this is not the best time to do a trace, if it succeeds, then
8810 * we have a trace (assuming tracing was enabled). Otherwise, this should
8811 * throw a second exception.
8813 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8814 afsd_ForceTrace(TRUE);
8815 buf_ForceTrace(TRUE);
8816 return EXCEPTION_CONTINUE_SEARCH;
8820 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8821 * If the number of server threads is M, and the number of live sessions is
8822 * N, then the number of NCB's in use at any time either waiting for, or
8823 * holding, received messages is M + N, so that is how many NCB's get created.
8825 void InitNCBslot(int idx)
8827 struct smb_packet *bufp;
8828 EVENT_HANDLE retHandle;
8830 char eventName[MAX_PATH];
8832 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8834 NCBs[idx] = smb_GetNCB();
8835 sprintf(eventName,"NCBavails[%d]", idx);
8836 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, 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,"NCBevents[%d]", idx);
8840 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8841 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8842 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8843 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8844 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8845 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8846 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8847 for (i=0; i<smb_NumServerThreads; i++)
8848 NCBreturns[i][idx] = retHandle;
8849 bufp = smb_GetPacket();
8850 bufp->spacep = cm_GetSpace();
8854 /* listen for new connections */
8855 void smb_Listener(void *parmp)
8861 afs_uint32 session, thread;
8862 smb_vc_t *vcp = NULL;
8864 char rname[NCBNAMSZ+1];
8865 char cname[MAX_COMPUTERNAME_LENGTH+1];
8866 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8867 INT_PTR lana = (INT_PTR) parmp;
8868 char eventName[MAX_PATH];
8869 int bridgeCount = 0;
8870 int nowildCount = 0;
8872 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8873 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8874 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8875 thrd_ResetEvent(ListenerShutdown[lana]);
8877 ncbp = smb_GetNCB();
8879 /* retrieve computer name */
8880 GetComputerName(cname, &cnamelen);
8883 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8884 memset(ncbp, 0, sizeof(NCB));
8887 ncbp->ncb_command = NCBLISTEN;
8888 ncbp->ncb_rto = 0; /* No receive timeout */
8889 ncbp->ncb_sto = 0; /* No send timeout */
8891 /* pad out with spaces instead of null termination */
8892 len = (long)strlen(smb_localNamep);
8893 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8894 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8896 strcpy(ncbp->ncb_callname, "*");
8897 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8899 ncbp->ncb_lana_num = (UCHAR)lana;
8901 code = Netbios(ncbp);
8903 if (code == NRC_NAMERR) {
8904 /* An smb shutdown or Vista resume must have taken place */
8906 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8907 ncbp->ncb_lana_num);
8908 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
8910 if (lock_TryMutex(&smb_StartedLock)) {
8911 lana_list.lana[i] = LANA_INVALID;
8912 lock_ReleaseMutex(&smb_StartedLock);
8915 } else if (code == NRC_BRIDGE || code != 0) {
8916 int lanaRemaining = 0;
8918 if (code == NRC_BRIDGE) {
8919 if (++bridgeCount <= 5) {
8920 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
8923 } else if (code == NRC_NOWILD) {
8924 if (++nowildCount <= 5) {
8925 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
8927 if (bridgeCount > 0) {
8928 memset(ncbp, 0, sizeof(*ncbp));
8929 ncbp->ncb_command = NCBADDNAME;
8930 ncbp->ncb_lana_num = (UCHAR)lana;
8931 /* pad out with spaces instead of null termination */
8932 len = (long)strlen(smb_localNamep);
8933 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8934 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8935 code = Netbios(ncbp);
8941 while (!lock_TryMutex(&smb_StartedLock)) {
8942 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8948 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8949 ncbp->ncb_lana_num, ncb_error_string(code));
8950 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8951 ncbp->ncb_lana_num, ncb_error_string(code));
8953 for (i = 0; i < lana_list.length; i++) {
8954 if (lana_list.lana[i] == lana) {
8955 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8956 lana_list.lana[i] = LANA_INVALID;
8958 if (lana_list.lana[i] != LANA_INVALID)
8962 if (lanaRemaining == 0) {
8963 cm_VolStatus_Network_Stopped(cm_NetbiosName
8968 smb_ListenerState = SMB_LISTENER_STOPPED;
8969 smb_LANadapter = LANA_INVALID;
8970 lana_list.length = 0;
8972 lock_ReleaseMutex(&smb_StartedLock);
8976 else if (code != 0) {
8977 char tbuffer[AFSPATHMAX];
8979 /* terminate silently if shutdown flag is set */
8980 while (!lock_TryMutex(&smb_StartedLock)) {
8981 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8987 "NCBLISTEN lana=%d failed with code %d [%s]",
8988 ncbp->ncb_lana_num, code, ncb_error_string(code));
8990 "Client exiting due to network failure. Please restart client.\n");
8993 "Client exiting due to network failure. Please restart client.\n"
8994 "NCBLISTEN lana=%d failed with code %d [%s]",
8995 ncbp->ncb_lana_num, code, ncb_error_string(code));
8997 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8998 MB_OK|MB_SERVICE_NOTIFICATION);
8999 osi_panic(tbuffer, __FILE__, __LINE__);
9001 lock_ReleaseMutex(&smb_StartedLock);
9006 /* a successful packet received. clear bridge error count */
9010 /* check for remote conns */
9011 /* first get remote name and insert null terminator */
9012 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9013 for (i=NCBNAMSZ; i>0; i--) {
9014 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9020 /* compare with local name */
9022 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9023 flags |= SMB_VCFLAG_REMOTECONN;
9026 lock_ObtainMutex(&smb_ListenerLock);
9028 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9029 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9031 /* now ncbp->ncb_lsn is the connection ID */
9032 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9033 if (vcp->session == 0) {
9034 /* New generation */
9035 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9038 /* Log session startup */
9040 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9041 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9042 #endif /* NOTSERVICE */
9043 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9044 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9046 if (reportSessionStartups) {
9047 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9050 lock_ObtainMutex(&vcp->mx);
9051 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9052 vcp->flags |= flags;
9053 lock_ReleaseMutex(&vcp->mx);
9055 /* Allocate slot in session arrays */
9056 /* Re-use dead session if possible, otherwise add one more */
9057 /* But don't look at session[0], it is reserved */
9058 lock_ObtainWrite(&smb_globalLock);
9059 for (session = 1; session < numSessions; session++) {
9060 if (dead_sessions[session]) {
9061 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9062 dead_sessions[session] = FALSE;
9066 lock_ReleaseWrite(&smb_globalLock);
9068 /* We are re-using an existing VC because the lsn and lana
9070 session = vcp->session;
9072 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9074 /* Log session startup */
9076 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9077 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9078 #endif /* NOTSERVICE */
9079 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9080 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9082 if (reportSessionStartups) {
9083 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9087 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9088 unsigned long code = CM_ERROR_ALLBUSY;
9089 smb_packet_t * outp = smb_GetPacket();
9090 unsigned char *outWctp;
9093 smb_FormatResponsePacket(vcp, NULL, outp);
9096 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9097 unsigned long NTStatus;
9098 smb_MapNTError(code, &NTStatus);
9099 outWctp = outp->wctp;
9100 smbp = (smb_t *) &outp->data;
9104 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9105 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9106 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9107 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9108 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9110 unsigned short errCode;
9111 unsigned char errClass;
9112 smb_MapCoreError(code, vcp, &errCode, &errClass);
9113 outWctp = outp->wctp;
9114 smbp = (smb_t *) &outp->data;
9118 smbp->errLow = (unsigned char) (errCode & 0xff);
9119 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9120 smbp->rcls = errClass;
9123 smb_SendPacket(vcp, outp);
9124 smb_FreePacket(outp);
9126 lock_ObtainMutex(&vcp->mx);
9127 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9128 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9130 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9131 lock_ReleaseMutex(&vcp->mx);
9132 lock_ObtainWrite(&smb_globalLock);
9133 dead_sessions[vcp->session] = TRUE;
9134 lock_ReleaseWrite(&smb_globalLock);
9135 smb_CleanupDeadVC(vcp);
9137 lock_ReleaseMutex(&vcp->mx);
9140 /* assert that we do not exceed the maximum number of sessions or NCBs.
9141 * we should probably want to wait for a session to be freed in case
9144 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9145 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9147 lock_ObtainMutex(&vcp->mx);
9148 vcp->session = session;
9149 lock_ReleaseMutex(&vcp->mx);
9150 lock_ObtainWrite(&smb_globalLock);
9151 LSNs[session] = ncbp->ncb_lsn;
9152 lanas[session] = ncbp->ncb_lana_num;
9153 lock_ReleaseWrite(&smb_globalLock);
9155 if (session == numSessions) {
9156 /* Add new NCB for new session */
9157 char eventName[MAX_PATH];
9159 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9161 InitNCBslot(numNCBs);
9162 lock_ObtainWrite(&smb_globalLock);
9164 lock_ReleaseWrite(&smb_globalLock);
9165 thrd_SetEvent(NCBavails[0]);
9166 thrd_SetEvent(NCBevents[0]);
9167 for (thread = 0; thread < smb_NumServerThreads; thread++)
9168 thrd_SetEvent(NCBreturns[thread][0]);
9169 /* Also add new session event */
9170 sprintf(eventName, "SessionEvents[%d]", session);
9171 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9172 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9173 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9174 lock_ObtainWrite(&smb_globalLock);
9176 lock_ReleaseWrite(&smb_globalLock);
9177 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9178 thrd_SetEvent(SessionEvents[0]);
9180 thrd_SetEvent(SessionEvents[session]);
9186 lock_ReleaseMutex(&smb_ListenerLock);
9187 } /* dispatch while loop */
9191 thrd_SetEvent(ListenerShutdown[lana]);
9196 smb_LanAdapterChangeThread(void *param)
9199 * Give the IPAddrDaemon thread a chance
9200 * to block before we trigger.
9203 smb_LanAdapterChange(0);
9206 void smb_SetLanAdapterChangeDetected(void)
9211 lock_ObtainMutex(&smb_StartedLock);
9213 if (!powerStateSuspended) {
9214 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9215 NULL, 0, &lpid, "smb_LanAdapterChange");
9216 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9217 thrd_CloseHandle(phandle);
9220 smb_LanAdapterChangeDetected = 1;
9221 lock_ReleaseMutex(&smb_StartedLock);
9224 void smb_LanAdapterChange(int locked) {
9225 lana_number_t lanaNum;
9227 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9229 LANA_ENUM temp_list;
9234 afsi_log("smb_LanAdapterChange");
9237 lock_ObtainMutex(&smb_StartedLock);
9239 smb_LanAdapterChangeDetected = 0;
9241 if (!powerStateSuspended &&
9242 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9243 LANA_NETBIOS_NAME_FULL)) &&
9244 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9245 if ( isGateway != bGateway ) {
9246 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9247 smb_LANadapter, lanaNum, isGateway, bGateway);
9249 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9250 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9251 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9254 NCB *ncbp = smb_GetNCB();
9255 ncbp->ncb_command = NCBENUM;
9256 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9257 ncbp->ncb_length = sizeof(temp_list);
9258 code = Netbios(ncbp);
9260 if (temp_list.length != lana_list.length) {
9261 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9262 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9265 for (i=0; i<lana_list.length; i++) {
9266 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9267 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9268 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9280 smb_StopListeners(1);
9281 smb_RestartListeners(1);
9284 lock_ReleaseMutex(&smb_StartedLock);
9287 /* initialize Netbios */
9288 int smb_NetbiosInit(int locked)
9291 int i, lana, code, l;
9293 int delname_tried=0;
9296 lana_number_t lanaNum;
9299 lock_ObtainMutex(&smb_StartedLock);
9301 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9302 smb_ListenerState != SMB_LISTENER_STOPPED) {
9305 lock_ReleaseMutex(&smb_StartedLock);
9308 /* setup the NCB system */
9309 ncbp = smb_GetNCB();
9311 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9312 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9313 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9315 if (smb_LANadapter != LANA_INVALID)
9316 afsi_log("LAN adapter number %d", smb_LANadapter);
9318 afsi_log("LAN adapter number not determined");
9321 afsi_log("Set for gateway service");
9323 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9325 /* something went horribly wrong. We can't proceed without a netbios name */
9327 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9328 osi_panic(buf, __FILE__, __LINE__);
9331 /* remember the name */
9332 len = (int)strlen(cm_NetbiosName);
9334 free(smb_localNamep);
9335 smb_localNamep = malloc(len+1);
9336 strcpy(smb_localNamep, cm_NetbiosName);
9337 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9339 /* Also copy the value to the client character encoded string */
9340 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9342 if (smb_LANadapter == LANA_INVALID) {
9343 ncbp->ncb_command = NCBENUM;
9344 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9345 ncbp->ncb_length = sizeof(lana_list);
9346 code = Netbios(ncbp);
9348 afsi_log("Netbios NCBENUM error code %d", code);
9349 osi_panic(s, __FILE__, __LINE__);
9353 lana_list.length = 1;
9354 lana_list.lana[0] = smb_LANadapter;
9357 for (i = 0; i < lana_list.length; i++) {
9358 /* reset the adaptor: in Win32, this is required for every process, and
9359 * acts as an init call, not as a real hardware reset.
9361 ncbp->ncb_command = NCBRESET;
9362 ncbp->ncb_callname[0] = 100;
9363 ncbp->ncb_callname[2] = 100;
9364 ncbp->ncb_lana_num = lana_list.lana[i];
9365 code = Netbios(ncbp);
9367 code = ncbp->ncb_retcode;
9369 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9370 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9372 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9376 /* and declare our name so we can receive connections */
9377 memset(ncbp, 0, sizeof(*ncbp));
9378 len=lstrlen(smb_localNamep);
9379 memset(smb_sharename,' ',NCBNAMSZ);
9380 memcpy(smb_sharename,smb_localNamep,len);
9381 afsi_log("lana_list.length %d", lana_list.length);
9383 /* Keep the name so we can unregister it later */
9384 for (l = 0; l < lana_list.length; l++) {
9385 lana = lana_list.lana[l];
9387 ncbp->ncb_command = NCBADDNAME;
9388 ncbp->ncb_lana_num = lana;
9389 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9390 code = Netbios(ncbp);
9392 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9393 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9395 char name[NCBNAMSZ+1];
9397 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9398 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9402 code = ncbp->ncb_retcode;
9405 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9408 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9409 if (code == NRC_BRIDGE) { /* invalid LANA num */
9410 lana_list.lana[l] = LANA_INVALID;
9413 else if (code == NRC_DUPNAME) {
9414 afsi_log("Name already exists; try to delete it");
9415 memset(ncbp, 0, sizeof(*ncbp));
9416 ncbp->ncb_command = NCBDELNAME;
9417 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9418 ncbp->ncb_lana_num = lana;
9419 code = Netbios(ncbp);
9421 code = ncbp->ncb_retcode;
9423 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9425 if (code != 0 || delname_tried) {
9426 lana_list.lana[l] = LANA_INVALID;
9428 else if (code == 0) {
9429 if (!delname_tried) {
9437 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9438 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9442 smb_LANadapter = lana;
9443 lana_found = 1; /* at least one worked */
9447 osi_assertx(lana_list.length >= 0, "empty lana list");
9449 afsi_log("No valid LANA numbers found!");
9450 lana_list.length = 0;
9451 smb_LANadapter = LANA_INVALID;
9452 smb_ListenerState = SMB_LISTENER_STOPPED;
9453 cm_VolStatus_Network_Stopped(cm_NetbiosName
9460 /* we're done with the NCB now */
9463 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9464 if (lana_list.length > 0)
9465 osi_assert(smb_LANadapter != LANA_INVALID);
9468 lock_ReleaseMutex(&smb_StartedLock);
9470 return (lana_list.length > 0 ? 1 : 0);
9473 void smb_StartListeners(int locked)
9480 lock_ObtainMutex(&smb_StartedLock);
9482 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9484 lock_ReleaseMutex(&smb_StartedLock);
9488 afsi_log("smb_StartListeners");
9489 smb_ListenerState = SMB_LISTENER_STARTED;
9490 cm_VolStatus_Network_Started(cm_NetbiosName
9496 for (i = 0; i < lana_list.length; i++) {
9497 if (lana_list.lana[i] == LANA_INVALID)
9499 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9500 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9501 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9502 thrd_CloseHandle(phandle);
9505 lock_ReleaseMutex(&smb_StartedLock);
9508 void smb_RestartListeners(int locked)
9511 lock_ObtainMutex(&smb_StartedLock);
9513 if (powerStateSuspended)
9514 afsi_log("smb_RestartListeners called while suspended");
9516 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9517 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9518 if (smb_NetbiosInit(1))
9519 smb_StartListeners(1);
9520 } else if (smb_LanAdapterChangeDetected) {
9521 smb_LanAdapterChange(1);
9525 lock_ReleaseMutex(&smb_StartedLock);
9528 void smb_StopListener(NCB *ncbp, int lana, int wait)
9532 memset(ncbp, 0, sizeof(*ncbp));
9533 ncbp->ncb_command = NCBDELNAME;
9534 ncbp->ncb_lana_num = lana;
9535 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9536 code = Netbios(ncbp);
9538 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9539 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9541 /* and then reset the LANA; this will cause the listener threads to exit */
9542 ncbp->ncb_command = NCBRESET;
9543 ncbp->ncb_callname[0] = 100;
9544 ncbp->ncb_callname[2] = 100;
9545 ncbp->ncb_lana_num = lana;
9546 code = Netbios(ncbp);
9548 code = ncbp->ncb_retcode;
9550 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9552 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9556 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9559 void smb_StopListeners(int locked)
9565 lock_ObtainMutex(&smb_StartedLock);
9567 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9569 lock_ReleaseMutex(&smb_StartedLock);
9573 afsi_log("smb_StopListeners");
9574 smb_ListenerState = SMB_LISTENER_STOPPED;
9575 cm_VolStatus_Network_Stopped(cm_NetbiosName
9581 ncbp = smb_GetNCB();
9583 /* Unregister the SMB name */
9584 for (l = 0; l < lana_list.length; l++) {
9585 lana = lana_list.lana[l];
9587 if (lana != LANA_INVALID) {
9588 smb_StopListener(ncbp, lana, TRUE);
9590 /* mark the adapter invalid */
9591 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9595 /* force a re-evaluation of the network adapters */
9596 lana_list.length = 0;
9597 smb_LANadapter = LANA_INVALID;
9600 lock_ReleaseMutex(&smb_StartedLock);
9603 void smb_Init(osi_log_t *logp, int useV3,
9613 EVENT_HANDLE retHandle;
9614 char eventName[MAX_PATH];
9615 int startListeners = 0;
9617 smb_TlsRequestSlot = TlsAlloc();
9619 smb_MBfunc = aMBfunc;
9623 /* Initialize smb_localZero */
9624 myTime.tm_isdst = -1; /* compute whether on DST or not */
9625 myTime.tm_year = 70;
9631 smb_localZero = mktime(&myTime);
9633 #ifndef USE_NUMERIC_TIME_CONV
9634 /* Initialize kludge-GMT */
9635 smb_CalculateNowTZ();
9636 #endif /* USE_NUMERIC_TIME_CONV */
9637 #ifdef AFS_FREELANCE_CLIENT
9638 /* Make sure the root.afs volume has the correct time */
9639 cm_noteLocalMountPointChange();
9642 /* initialize the remote debugging log */
9645 /* and the global lock */
9646 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9647 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9649 /* Raw I/O data structures */
9650 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9652 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9653 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9655 /* 4 Raw I/O buffers */
9656 smb_RawBufs = calloc(65536,1);
9657 *((char **)smb_RawBufs) = NULL;
9658 for (i=0; i<3; i++) {
9659 char *rawBuf = calloc(65536,1);
9660 *((char **)rawBuf) = smb_RawBufs;
9661 smb_RawBufs = rawBuf;
9664 /* global free lists */
9665 smb_ncbFreeListp = NULL;
9666 smb_packetFreeListp = NULL;
9668 lock_ObtainMutex(&smb_StartedLock);
9669 startListeners = smb_NetbiosInit(1);
9671 /* Initialize listener and server structures */
9673 memset(dead_sessions, 0, sizeof(dead_sessions));
9674 sprintf(eventName, "SessionEvents[0]");
9675 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9676 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9677 afsi_log("Event Object Already Exists: %s", eventName);
9679 smb_NumServerThreads = nThreads;
9680 sprintf(eventName, "NCBavails[0]");
9681 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9682 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9683 afsi_log("Event Object Already Exists: %s", eventName);
9684 sprintf(eventName, "NCBevents[0]");
9685 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9686 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9687 afsi_log("Event Object Already Exists: %s", eventName);
9688 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9689 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9690 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9691 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9692 afsi_log("Event Object Already Exists: %s", eventName);
9693 for (i = 0; i < smb_NumServerThreads; i++) {
9694 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9695 NCBreturns[i][0] = retHandle;
9698 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9699 for (i = 0; i < smb_NumServerThreads; i++) {
9700 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9701 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9702 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9703 afsi_log("Event Object Already Exists: %s", eventName);
9704 InitNCBslot((int)(i+1));
9706 numNCBs = smb_NumServerThreads + 1;
9708 /* Initialize dispatch table */
9709 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9710 /* Prepare the table for unknown operations */
9711 for(i=0; i<= SMB_NOPCODES; i++) {
9712 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9714 /* Fill in the ones we do know */
9715 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9716 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9717 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9718 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9719 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9720 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9721 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9722 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9723 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9724 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9725 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9726 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9727 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9728 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9729 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9730 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9731 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9732 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9733 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9734 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9735 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9736 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9737 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9738 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9739 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9740 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9741 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9742 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9743 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9744 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9745 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9746 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9747 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9748 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9749 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9750 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9751 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9752 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9753 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9754 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9755 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9756 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9757 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9758 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9759 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9760 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9761 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9762 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9763 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9764 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9765 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9766 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9767 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9768 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9769 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9770 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9771 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9772 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9773 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9774 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9775 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9776 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9777 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9778 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9779 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9780 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9781 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9782 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9783 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9784 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9785 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9786 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9787 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9788 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9790 /* setup tran 2 dispatch table */
9791 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9792 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9793 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9794 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9795 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9796 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9797 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9798 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9799 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9800 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9801 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9802 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9803 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9804 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9805 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9806 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9807 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9808 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9810 /* setup the rap dispatch table */
9811 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9812 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9813 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9814 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9815 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9819 /* if we are doing SMB authentication we have register outselves as a logon process */
9820 if (smb_authType != SMB_AUTH_NONE) {
9821 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9822 LSA_STRING afsProcessName;
9823 LSA_OPERATIONAL_MODE dummy; /*junk*/
9825 afsProcessName.Buffer = "OpenAFSClientDaemon";
9826 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9827 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9829 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9831 if (nts == STATUS_SUCCESS) {
9832 LSA_STRING packageName;
9833 /* we are registered. Find out the security package id */
9834 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9835 packageName.Length = (USHORT)strlen(packageName.Buffer);
9836 packageName.MaximumLength = packageName.Length + 1;
9837 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9838 if (nts == STATUS_SUCCESS) {
9840 * This code forces Windows to authenticate against the Logon Cache
9841 * first instead of attempting to authenticate against the Domain
9842 * Controller. When the Windows logon cache is enabled this improves
9843 * performance by removing the network access and works around a bug
9844 * seen at sites which are using a MIT Kerberos principal to login
9845 * to machines joined to a non-root domain in a multi-domain forest.
9846 * MsV1_0SetProcessOption was added in Windows XP.
9848 PVOID pResponse = NULL;
9849 ULONG cbResponse = 0;
9850 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9852 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9853 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9854 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9855 OptionsRequest.DisableOptions = FALSE;
9857 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9860 sizeof(OptionsRequest),
9866 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9867 char message[AFSPATHMAX];
9868 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9870 OutputDebugString(message);
9873 OutputDebugString("MsV1_0SetProcessOption success");
9874 afsi_log("MsV1_0SetProcessOption success");
9876 /* END - code from Larry */
9878 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9879 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9880 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9882 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9884 /* something went wrong. We report the error and revert back to no authentication
9885 because we can't perform any auth requests without a successful lsa handle
9886 or sec package id. */
9887 afsi_log("Reverting to NO SMB AUTH");
9888 smb_authType = SMB_AUTH_NONE;
9891 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9893 /* something went wrong. We report the error and revert back to no authentication
9894 because we can't perform any auth requests without a successful lsa handle
9895 or sec package id. */
9896 afsi_log("Reverting to NO SMB AUTH");
9897 smb_authType = SMB_AUTH_NONE;
9901 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9902 * time prevents the failure of authentication when logged into Windows with an
9903 * external Kerberos principal mapped to a local account.
9905 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9906 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9907 * then the only option is NTLMSSP anyway; so just fallback.
9912 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9913 if (secBlobLength == 0) {
9914 smb_authType = SMB_AUTH_NTLM;
9915 afsi_log("Reverting to SMB AUTH NTLM");
9924 /* Now get ourselves a domain name. */
9925 /* For now we are using the local computer name as the domain name.
9926 * It is actually the domain for local logins, and we are acting as
9927 * a local SMB server.
9929 bufsize = lengthof(smb_ServerDomainName) - 1;
9930 GetComputerNameW(smb_ServerDomainName, &bufsize);
9931 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9932 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9935 /* Start listeners, waiters, servers, and daemons */
9937 smb_StartListeners(1);
9939 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9940 NULL, 0, &lpid, "smb_ClientWaiter");
9941 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9942 thrd_CloseHandle(phandle);
9944 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9945 NULL, 0, &lpid, "smb_ServerWaiter");
9946 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9947 thrd_CloseHandle(phandle);
9949 for (i=0; i<smb_NumServerThreads; i++) {
9950 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9951 (void *) i, 0, &lpid, "smb_Server");
9952 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9953 thrd_CloseHandle(phandle);
9956 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9957 NULL, 0, &lpid, "smb_Daemon");
9958 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9959 thrd_CloseHandle(phandle);
9961 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9962 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9963 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9964 thrd_CloseHandle(phandle);
9966 lock_ReleaseMutex(&smb_StartedLock);
9970 void smb_Shutdown(void)
9977 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9979 /* setup the NCB system */
9980 ncbp = smb_GetNCB();
9982 /* Block new sessions by setting shutdown flag */
9983 smbShutdownFlag = 1;
9985 /* Hang up all sessions */
9986 memset((char *)ncbp, 0, sizeof(NCB));
9987 for (i = 1; i < numSessions; i++)
9989 if (dead_sessions[i])
9992 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9993 ncbp->ncb_command = NCBHANGUP;
9994 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9995 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9996 code = Netbios(ncbp);
9997 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9998 if (code == 0) code = ncbp->ncb_retcode;
10000 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10001 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10005 /* Trigger the shutdown of all SMB threads */
10006 for (i = 0; i < smb_NumServerThreads; i++)
10007 thrd_SetEvent(NCBreturns[i][0]);
10009 thrd_SetEvent(NCBevents[0]);
10010 thrd_SetEvent(SessionEvents[0]);
10011 thrd_SetEvent(NCBavails[0]);
10013 for (i = 0;i < smb_NumServerThreads; i++) {
10014 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10015 if (code == WAIT_OBJECT_0) {
10018 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10019 thrd_SetEvent(NCBreturns[i--][0]);
10023 /* Delete Netbios name */
10024 memset((char *)ncbp, 0, sizeof(NCB));
10025 for (i = 0; i < lana_list.length; i++) {
10026 if (lana_list.lana[i] == LANA_INVALID) continue;
10027 ncbp->ncb_command = NCBDELNAME;
10028 ncbp->ncb_lana_num = lana_list.lana[i];
10029 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10030 code = Netbios(ncbp);
10032 code = ncbp->ncb_retcode;
10034 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10035 ncbp->ncb_lana_num, code);
10040 /* Release the reference counts held by the VCs */
10041 lock_ObtainWrite(&smb_rctLock);
10042 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10047 if (vcp->magic != SMB_VC_MAGIC)
10048 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10049 __FILE__, __LINE__);
10051 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10053 if (fidp->scp != NULL) {
10056 lock_ReleaseWrite(&smb_rctLock);
10057 lock_ObtainMutex(&fidp->mx);
10058 if (fidp->scp != NULL) {
10061 lock_ObtainWrite(&scp->rw);
10062 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10063 lock_ReleaseWrite(&scp->rw);
10064 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10065 cm_ReleaseSCache(scp);
10067 lock_ReleaseMutex(&fidp->mx);
10068 lock_ObtainWrite(&smb_rctLock);
10072 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10074 smb_ReleaseVCNoLock(tidp->vcp);
10076 cm_user_t *userp = tidp->userp;
10077 tidp->userp = NULL;
10078 cm_ReleaseUser(userp);
10082 lock_ReleaseWrite(&smb_rctLock);
10084 TlsFree(smb_TlsRequestSlot);
10087 /* Get the UNC \\<servername>\<sharename> prefix. */
10088 char *smb_GetSharename()
10093 /* Make sure we have been properly initialized. */
10094 if (smb_localNamep == NULL)
10097 /* Allocate space for \\<servername>\<sharename>, plus the
10100 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10101 name = malloc(len);
10102 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10108 void smb_LogPacket(smb_packet_t *packet)
10112 unsigned length, paramlen, datalen, i, j;
10114 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10116 if (!packet) return;
10118 osi_Log0(smb_logp, "*** SMB packet dump ***");
10120 smbp = (smb_t *) packet->data;
10121 vp = (BYTE *) packet->data;
10123 paramlen = smbp->wct * 2;
10124 datalen = *((WORD *) (smbp->vdata + paramlen));
10125 length = sizeof(*smbp) + paramlen + 1 + datalen;
10127 for (i=0;i < length; i+=16)
10129 memset( buf, ' ', 80 );
10132 itoa( i, buf, 16 );
10134 buf[strlen(buf)] = ' ';
10136 cp = (BYTE*) buf + 7;
10138 for (j=0;j < 16 && (i+j)<length; j++)
10140 *(cp++) = hex[vp[i+j] >> 4];
10141 *(cp++) = hex[vp[i+j] & 0xf];
10151 for (j=0;j < 16 && (i+j)<length;j++)
10153 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10164 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10167 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10169 #endif /* LOG_PACKET */
10172 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10178 smb_username_t *unp;
10179 smb_waitingLockRequest_t *wlrp;
10182 lock_ObtainRead(&smb_rctLock);
10184 sprintf(output, "begin dumping smb_username_t\r\n");
10185 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10186 for (unp = usernamesp; unp; unp=unp->nextp)
10188 cm_ucell_t *ucellp;
10190 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10191 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10192 unp->name ? unp->name : _C("NULL"),
10193 unp->machine ? unp->machine : _C("NULL"));
10194 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10196 sprintf(output, " begin dumping cm_ucell_t\r\n");
10197 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10199 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10200 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",
10201 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10202 ucellp->expirationTime, ucellp->gen,
10204 ucellp->cellp->name);
10205 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10208 sprintf(output, " done dumping cm_ucell_t\r\n");
10209 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10212 sprintf(output, "done dumping smb_username_t\r\n");
10213 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10216 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10217 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10220 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10221 smb_waitingLock_t *lockp;
10223 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10224 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10225 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10227 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10228 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10229 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10230 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10231 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10232 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10234 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10235 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10238 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10239 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10241 sprintf(output, "begin dumping smb_vc_t\r\n");
10242 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10244 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10250 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10251 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10252 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10254 sprintf(output, " begin dumping smb_user_t\r\n");
10255 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10256 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10257 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10258 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10259 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10261 sprintf(output, " done dumping smb_user_t\r\n");
10262 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10264 sprintf(output, " begin dumping smb_tid_t\r\n");
10265 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10266 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10267 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",
10268 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10269 tidp->pathname ? tidp->pathname : _C("NULL"));
10270 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10272 sprintf(output, " done dumping smb_tid_t\r\n");
10273 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10275 sprintf(output, " begin dumping smb_fid_t\r\n");
10276 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10278 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10280 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",
10281 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10282 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10283 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10284 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10287 sprintf(output, " done dumping smb_fid_t\r\n");
10288 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10291 sprintf(output, "done dumping smb_vc_t\r\n");
10292 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10294 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10295 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10297 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10303 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10304 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10305 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10307 sprintf(output, " begin dumping smb_user_t\r\n");
10308 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10309 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10310 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10311 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10312 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10314 sprintf(output, " done dumping smb_user_t\r\n");
10315 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10317 sprintf(output, " begin dumping smb_tid_t\r\n");
10318 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10319 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10320 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",
10321 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10322 tidp->pathname ? tidp->pathname : _C("NULL"));
10323 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10325 sprintf(output, " done dumping smb_tid_t\r\n");
10326 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10328 sprintf(output, " begin dumping smb_fid_t\r\n");
10329 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10331 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10333 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",
10334 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10335 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10336 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10337 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10340 sprintf(output, " done dumping smb_fid_t\r\n");
10341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10344 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10348 lock_ReleaseRead(&smb_rctLock);
10352 long smb_IsNetworkStarted(void)
10355 lock_ObtainWrite(&smb_globalLock);
10356 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10357 lock_ReleaseWrite(&smb_globalLock);