2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
240 case 0x03: s = "NRC_ILLCMD illegal command"; break;
241 case 0x05: s = "NRC_CMDTMO command timed out"; break;
242 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
243 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
244 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
245 case 0x09: s = "NRC_NORES no resource available"; break;
246 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
247 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
248 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
249 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
250 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
251 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
252 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
253 case 0x13: s = "NRC_ILLNN illegal name number"; break;
254 case 0x14: s = "NRC_NOCALL no callname"; break;
255 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
256 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
257 case 0x17: s = "NRC_NAMERR name deleted"; break;
258 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
259 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
260 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
261 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
263 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
264 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
265 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
266 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
267 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
268 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
269 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
270 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
271 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
272 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
273 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
274 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
275 case 0x40: s = "NRC_SYSTEM system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 #ifdef DEBUG_SMB_REFCOUNT
823 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
825 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
830 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
831 lock_ObtainWrite(&smb_rctLock);
832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
833 if (vcp->magic != SMB_VC_MAGIC)
834 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
837 if (lsn == vcp->lsn && lana == vcp->lana &&
838 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
839 smb_HoldVCNoLock(vcp);
843 if (!vcp && (flags & SMB_FLAG_CREATE)) {
844 vcp = malloc(sizeof(*vcp));
845 memset(vcp, 0, sizeof(*vcp));
846 vcp->vcID = ++numVCs;
847 vcp->magic = SMB_VC_MAGIC;
848 vcp->refCount = 2; /* smb_allVCsp and caller */
851 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
852 vcp->nextp = smb_allVCsp;
854 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
859 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
860 /* We must obtain a challenge for extended auth
861 * in case the client negotiates smb v3
863 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
864 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
865 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
866 ULONG lsaRespSize = 0;
868 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
870 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
877 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
878 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
879 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
880 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
881 nts, ntsEx, lsaRespSize);
883 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
885 if (ntsEx == STATUS_SUCCESS) {
886 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
889 * This will cause the subsequent authentication to fail but
890 * that is better than us dereferencing a NULL pointer and
893 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 LsaFreeReturnBuffer(lsaResp);
899 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
901 if (numVCs >= CM_SESSION_RESERVED) {
903 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
906 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
913 lock_ReleaseWrite(&smb_globalLock);
917 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 static int smb_IsStarMask(clientchar_t *maskp)
936 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
942 #ifdef DEBUG_SMB_REFCOUNT
943 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
944 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
946 void smb_ReleaseVCInternal(smb_vc_t *vcp)
952 lock_AssertWrite(&smb_rctLock);
955 if (vcp->refCount == 0) {
956 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
957 #ifdef DEBUG_SMB_REFCOUNT
958 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
959 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
961 /* remove VCP from smb_deadVCsp */
962 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
968 lock_FinalizeMutex(&vcp->mx);
969 memset(vcp,0,sizeof(smb_vc_t));
972 #ifdef DEBUG_SMB_REFCOUNT
973 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
975 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
979 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
980 avcp?"":"not ",vcp, vcp->refCount);
982 /* This is a wrong. However, I suspect that there is an undercount
983 * and I don't want to release 1.4.1 in a state that will allow
984 * smb_vc_t objects to be deallocated while still in the
985 * smb_allVCsp list. The list is supposed to keep a reference
986 * to the smb_vc_t. Put it back.
990 #ifdef DEBUG_SMB_REFCOUNT
991 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
992 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
996 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
997 /* The reference count is non-zero but the VC is dead.
998 * This implies that some FIDs, TIDs, etc on the VC have yet to
999 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1000 * add a reference that will be dropped by
1001 * smb_CleanupDeadVC() and try to cleanup the VC again.
1002 * Eventually the refCount will drop to zero when all of the
1003 * active threads working with the VC end their task.
1005 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1006 vcp->refCount++; /* put the refCount back */
1007 lock_ReleaseWrite(&smb_rctLock);
1008 smb_CleanupDeadVC(vcp);
1009 #ifdef DEBUG_SMB_REFCOUNT
1010 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1011 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1013 lock_ObtainWrite(&smb_rctLock);
1016 #ifdef DEBUG_SMB_REFCOUNT
1017 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1018 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1023 #ifdef DEBUG_SMB_REFCOUNT
1024 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1026 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1029 lock_AssertWrite(&smb_rctLock);
1030 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1031 smb_ReleaseVCInternal(vcp);
1034 #ifdef DEBUG_SMB_REFCOUNT
1035 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1037 void smb_ReleaseVC(smb_vc_t *vcp)
1040 lock_ObtainWrite(&smb_rctLock);
1041 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1042 smb_ReleaseVCInternal(vcp);
1043 lock_ReleaseWrite(&smb_rctLock);
1046 #ifdef DEBUG_SMB_REFCOUNT
1047 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1049 void smb_HoldVCNoLock(smb_vc_t *vcp)
1052 lock_AssertWrite(&smb_rctLock);
1054 #ifdef DEBUG_SMB_REFCOUNT
1055 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1056 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1058 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1062 #ifdef DEBUG_SMB_REFCOUNT
1063 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1065 void smb_HoldVC(smb_vc_t *vcp)
1068 lock_ObtainWrite(&smb_rctLock);
1070 #ifdef DEBUG_SMB_REFCOUNT
1071 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1072 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1074 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1076 lock_ReleaseWrite(&smb_rctLock);
1079 void smb_CleanupDeadVC(smb_vc_t *vcp)
1081 smb_fid_t *fidpIter;
1082 smb_fid_t *fidpNext;
1084 smb_tid_t *tidpIter;
1085 smb_tid_t *tidpNext;
1087 smb_user_t *uidpIter;
1088 smb_user_t *uidpNext;
1090 afs_uint32 refCount = 0;
1092 lock_ObtainMutex(&vcp->mx);
1093 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1094 lock_ReleaseMutex(&vcp->mx);
1095 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1098 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1099 lock_ReleaseMutex(&vcp->mx);
1100 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1102 lock_ObtainWrite(&smb_rctLock);
1103 /* remove VCP from smb_allVCsp */
1104 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1105 if ((*vcpp)->magic != SMB_VC_MAGIC)
1106 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1107 __FILE__, __LINE__);
1110 vcp->nextp = smb_deadVCsp;
1112 /* Hold onto the reference until we are done with this function */
1117 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1118 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1120 if (fidpIter->deleteOk)
1123 fid = fidpIter->fid;
1124 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1126 smb_HoldFIDNoLock(fidpIter);
1127 lock_ReleaseWrite(&smb_rctLock);
1129 smb_CloseFID(vcp, fidpIter, NULL, 0);
1130 smb_ReleaseFID(fidpIter);
1132 lock_ObtainWrite(&smb_rctLock);
1133 fidpNext = vcp->fidsp;
1136 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1137 tidpNext = tidpIter->nextp;
1138 if (tidpIter->deleteOk)
1140 tidpIter->deleteOk = 1;
1142 tid = tidpIter->tid;
1143 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1145 smb_HoldTIDNoLock(tidpIter);
1146 smb_ReleaseTID(tidpIter, TRUE);
1147 tidpNext = vcp->tidsp;
1150 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1151 uidpNext = uidpIter->nextp;
1152 if (uidpIter->deleteOk)
1154 uidpIter->deleteOk = 1;
1156 /* do not add an additional reference count for the smb_user_t
1157 * as the smb_vc_t already is holding a reference */
1158 lock_ReleaseWrite(&smb_rctLock);
1160 smb_ReleaseUID(uidpIter);
1162 lock_ObtainWrite(&smb_rctLock);
1163 uidpNext = vcp->usersp;
1166 /* The vcp is now on the deadVCsp list. We intentionally drop the
1167 * reference so that the refcount can reach 0 and we can delete it
1169 * If the refCount == 1 going into the ReleaseVCNoLock call
1170 * the object will be freed and it won't be safe to clear
1173 refCount = vcp->refCount;
1174 smb_ReleaseVCNoLock(vcp);
1176 lock_ObtainMutex(&vcp->mx);
1177 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1178 lock_ReleaseMutex(&vcp->mx);
1181 lock_ReleaseWrite(&smb_rctLock);
1182 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1185 #ifdef DEBUG_SMB_REFCOUNT
1186 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1188 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1193 lock_ObtainWrite(&smb_rctLock);
1195 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1196 if (tidp->refCount == 0 && tidp->deleteOk) {
1198 smb_ReleaseTID(tidp, TRUE);
1202 if (tid == tidp->tid) {
1207 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1208 tidp = malloc(sizeof(*tidp));
1209 memset(tidp, 0, sizeof(*tidp));
1210 tidp->nextp = vcp->tidsp;
1213 smb_HoldVCNoLock(vcp);
1215 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1218 #ifdef DEBUG_SMB_REFCOUNT
1220 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1221 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1224 lock_ReleaseWrite(&smb_rctLock);
1228 #ifdef DEBUG_SMB_REFCOUNT
1229 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1231 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1234 lock_AssertWrite(&smb_rctLock);
1236 #ifdef DEBUG_SMB_REFCOUNT
1237 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1238 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1242 #ifdef DEBUG_SMB_REFCOUNT
1243 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1245 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1250 cm_user_t *userp = NULL;
1251 smb_vc_t *vcp = NULL;
1254 lock_ObtainWrite(&smb_rctLock);
1256 lock_AssertWrite(&smb_rctLock);
1258 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1259 #ifdef DEBUG_SMB_REFCOUNT
1260 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1261 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1263 if (tidp->refCount == 0) {
1264 if (tidp->deleteOk) {
1265 ltpp = &tidp->vcp->tidsp;
1266 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1270 osi_assertx(tp != NULL, "null smb_tid_t");
1272 lock_FinalizeMutex(&tidp->mx);
1273 userp = tidp->userp; /* remember to drop ref later */
1281 lock_ReleaseWrite(&smb_rctLock);
1283 cm_ReleaseUser(userp);
1285 smb_ReleaseVCNoLock(vcp);
1288 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1290 smb_user_t *uidp = NULL;
1292 lock_ObtainWrite(&smb_rctLock);
1293 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1294 if (uid == uidp->userID) {
1296 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1298 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1302 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1303 uidp = malloc(sizeof(*uidp));
1304 memset(uidp, 0, sizeof(*uidp));
1305 uidp->nextp = vcp->usersp;
1306 uidp->refCount = 2; /* one for the vcp and one for the caller */
1308 smb_HoldVCNoLock(vcp);
1310 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1312 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1314 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1316 lock_ReleaseWrite(&smb_rctLock);
1320 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1323 smb_username_t *unp= NULL;
1325 lock_ObtainWrite(&smb_rctLock);
1326 for(unp = usernamesp; unp; unp = unp->nextp) {
1327 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1328 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1333 if (!unp && (flags & SMB_FLAG_CREATE)) {
1334 unp = malloc(sizeof(*unp));
1335 memset(unp, 0, sizeof(*unp));
1337 unp->nextp = usernamesp;
1338 unp->name = cm_ClientStrDup(usern);
1339 unp->machine = cm_ClientStrDup(machine);
1341 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1342 if (flags & SMB_FLAG_AFSLOGON)
1343 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1346 lock_ReleaseWrite(&smb_rctLock);
1350 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1352 smb_user_t *uidp= NULL;
1354 lock_ObtainWrite(&smb_rctLock);
1355 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1358 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1360 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1361 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1366 lock_ReleaseWrite(&smb_rctLock);
1370 void smb_ReleaseUsername(smb_username_t *unp)
1373 smb_username_t **lupp;
1374 cm_user_t *userp = NULL;
1375 time_t now = osi_Time();
1377 lock_ObtainWrite(&smb_rctLock);
1378 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1379 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1380 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1382 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1386 osi_assertx(up != NULL, "null smb_username_t");
1388 up->nextp = NULL; /* do not remove this */
1389 lock_FinalizeMutex(&unp->mx);
1395 lock_ReleaseWrite(&smb_rctLock);
1397 cm_ReleaseUser(userp);
1400 void smb_HoldUIDNoLock(smb_user_t *uidp)
1402 lock_AssertWrite(&smb_rctLock);
1406 void smb_ReleaseUID(smb_user_t *uidp)
1410 smb_username_t *unp = NULL;
1412 lock_ObtainWrite(&smb_rctLock);
1413 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1414 if (uidp->refCount == 0) {
1415 lupp = &uidp->vcp->usersp;
1416 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1420 osi_assertx(up != NULL, "null smb_user_t");
1422 lock_FinalizeMutex(&uidp->mx);
1424 smb_ReleaseVCNoLock(uidp->vcp);
1428 lock_ReleaseWrite(&smb_rctLock);
1432 cm_ReleaseUserVCRef(unp->userp);
1433 smb_ReleaseUsername(unp);
1437 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1439 cm_user_t *up = NULL;
1444 lock_ObtainMutex(&uidp->mx);
1446 up = uidp->unp->userp;
1449 lock_ReleaseMutex(&uidp->mx);
1455 /* retrieve a held reference to a user structure corresponding to an incoming
1457 * corresponding release function is cm_ReleaseUser.
1459 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1462 cm_user_t *up = NULL;
1465 smbp = (smb_t *) inp;
1466 uidp = smb_FindUID(vcp, smbp->uid, 0);
1470 up = smb_GetUserFromUID(uidp);
1472 smb_ReleaseUID(uidp);
1477 * Return a pointer to a pathname extracted from a TID structure. The
1478 * TID structure is not held; assume it won't go away.
1480 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1485 tidp = smb_FindTID(vcp, tid, 0);
1489 if (tidp->flags & SMB_TIDFLAG_IPC) {
1490 code = CM_ERROR_TIDIPC;
1491 /* tidp->pathname would be NULL, but that's fine */
1493 *treepath = tidp->pathname;
1494 smb_ReleaseTID(tidp, FALSE);
1499 /* check to see if we have a chained fid, that is, a fid that comes from an
1500 * OpenAndX message that ran earlier in this packet. In this case, the fid
1501 * field in a read, for example, request, isn't set, since the value is
1502 * supposed to be inherited from the openAndX call.
1504 int smb_ChainFID(int fid, smb_packet_t *inp)
1506 if (inp->fid == 0 || inp->inCount == 0)
1512 /* are we a priv'd user? What does this mean on NT? */
1513 int smb_SUser(cm_user_t *userp)
1518 /* find a file ID. If we pass in 0 we select an unused File ID.
1519 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1520 * smb_fid_t data structure if desired File ID cannot be found.
1522 #ifdef DEBUG_SMB_REFCOUNT
1523 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1525 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1531 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1534 lock_ObtainWrite(&smb_rctLock);
1535 /* figure out if we need to allocate a new file ID */
1538 fid = vcp->fidCounter;
1542 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1543 if (fidp->refCount == 0 && fidp->deleteOk) {
1545 lock_ReleaseWrite(&smb_rctLock);
1546 smb_ReleaseFID(fidp);
1547 lock_ObtainWrite(&smb_rctLock);
1550 if (fid == fidp->fid) {
1553 if (fid == 0xFFFF) {
1555 "New FID number wraps on vcp 0x%x", vcp);
1565 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1566 char eventName[MAX_PATH];
1568 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1569 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1570 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1571 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1572 thrd_CloseHandle(event);
1574 if (fid == 0xFFFF) {
1575 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1581 fidp = malloc(sizeof(*fidp));
1582 memset(fidp, 0, sizeof(*fidp));
1583 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1586 smb_HoldVCNoLock(vcp);
1587 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1589 fidp->curr_chunk = fidp->prev_chunk = -2;
1590 fidp->raw_write_event = event;
1592 vcp->fidCounter = fid+1;
1593 if (vcp->fidCounter == 0xFFFF) {
1594 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1596 vcp->fidCounter = 1;
1601 #ifdef DEBUG_SMB_REFCOUNT
1603 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1604 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1607 lock_ReleaseWrite(&smb_rctLock);
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1614 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1617 smb_fid_t *fidp = NULL;
1623 lock_ObtainWrite(&smb_rctLock);
1624 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1625 if (scp == fidp->scp) {
1626 lock_ObtainMutex(&fidp->mx);
1627 if (scp == fidp->scp) {
1629 lock_ReleaseMutex(&fidp->mx);
1632 lock_ReleaseMutex(&fidp->mx);
1635 #ifdef DEBUG_SMB_REFCOUNT
1637 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1638 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1641 lock_ReleaseWrite(&smb_rctLock);
1645 #ifdef DEBUG_SMB_REFCOUNT
1646 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1648 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1651 lock_AssertWrite(&smb_rctLock);
1653 #ifdef DEBUG_SMB_REFCOUNT
1654 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1655 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1661 /* the sm_fid_t->mx and smb_rctLock must not be held */
1662 #ifdef DEBUG_SMB_REFCOUNT
1663 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1665 void smb_ReleaseFID(smb_fid_t *fidp)
1668 cm_scache_t *scp = NULL;
1669 cm_user_t *userp = NULL;
1670 smb_vc_t *vcp = NULL;
1671 smb_ioctl_t *ioctlp;
1673 lock_ObtainMutex(&fidp->mx);
1674 lock_ObtainWrite(&smb_rctLock);
1675 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1676 #ifdef DEBUG_SMB_REFCOUNT
1677 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1678 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1680 if (fidp->refCount == 0) {
1681 if (fidp->deleteOk) {
1684 scp = fidp->scp; /* release after lock is released */
1686 lock_ObtainWrite(&scp->rw);
1687 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1688 lock_ReleaseWrite(&scp->rw);
1689 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1692 userp = fidp->userp;
1696 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1697 thrd_CloseHandle(fidp->raw_write_event);
1699 /* and see if there is ioctl stuff to free */
1700 ioctlp = fidp->ioctlp;
1703 cm_FreeSpace(ioctlp->prefix);
1704 if (ioctlp->ioctl.inAllocp)
1705 free(ioctlp->ioctl.inAllocp);
1706 if (ioctlp->ioctl.outAllocp)
1707 free(ioctlp->ioctl.outAllocp);
1710 lock_ReleaseMutex(&fidp->mx);
1711 lock_FinalizeMutex(&fidp->mx);
1716 smb_ReleaseVCNoLock(vcp);
1720 lock_ReleaseMutex(&fidp->mx);
1722 lock_ReleaseWrite(&smb_rctLock);
1724 /* now release the scache structure */
1726 cm_ReleaseSCache(scp);
1729 cm_ReleaseUser(userp);
1733 * Case-insensitive search for one string in another;
1734 * used to find variable names in submount pathnames.
1736 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1738 clientchar_t *cursor;
1740 for (cursor = str1; *cursor; cursor++)
1741 if (cm_ClientStrCmpI(cursor, str2) == 0)
1748 * Substitute a variable value for its name in a submount pathname. Variable
1749 * name has been identified by smb_stristr() and is in substr. Variable name
1750 * length (plus one) is in substr_size. Variable value is in newstr.
1752 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1753 unsigned int substr_size, clientchar_t *newstr)
1755 clientchar_t temp[1024];
1757 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1758 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1759 cm_ClientStrCat(str1, cchstr1, temp);
1762 clientchar_t VNUserName[] = _C("%USERNAME%");
1763 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1764 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1765 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1767 typedef struct smb_findShare_rock {
1768 clientchar_t * shareName;
1769 clientchar_t * match;
1771 } smb_findShare_rock_t;
1773 #define SMB_FINDSHARE_EXACT_MATCH 1
1774 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1776 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1780 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1781 normchar_t normName[MAX_PATH];
1783 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1784 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1785 osi_LogSaveString(smb_logp, dep->name));
1789 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1790 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1791 matchType = SMB_FINDSHARE_EXACT_MATCH;
1793 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1796 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1797 vrock->matchType = matchType;
1799 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1800 return CM_ERROR_STOPNOW;
1806 /* find a shareName in the table of submounts */
1807 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1808 clientchar_t *shareName,
1809 clientchar_t **pathNamep)
1813 clientchar_t pathName[1024];
1816 clientchar_t *p, *q;
1817 fschar_t *cellname = NULL;
1820 DWORD allSubmount = 1;
1822 /* if allSubmounts == 0, only return the //mountRoot/all share
1823 * if in fact it has been been created in the subMounts table.
1824 * This is to allow sites that want to restrict access to the
1827 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1828 0, KEY_QUERY_VALUE, &parmKey);
1829 if (code == ERROR_SUCCESS) {
1830 cblen = sizeof(allSubmount);
1831 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1832 (BYTE *) &allSubmount, &cblen);
1833 if (code != ERROR_SUCCESS) {
1836 RegCloseKey (parmKey);
1839 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1844 /* In case, the all share is disabled we need to still be able
1845 * to handle ioctl requests
1847 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1848 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1852 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1853 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1854 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1855 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1856 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1862 /* Check for volume references
1864 * They look like <cell>{%,#}<volume>
1866 if (cm_ClientStrChr(shareName, '%') != NULL ||
1867 cm_ClientStrChr(shareName, '#') != NULL) {
1868 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1869 /* make room for '/@vol:' + mountchar + NULL terminator*/
1871 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1872 osi_LogSaveClientString(smb_logp, shareName));
1874 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1875 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1876 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1878 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1880 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1881 cm_ClientStrLwr(*pathNamep);
1882 osi_Log1(smb_logp, " returning pathname [%S]",
1883 osi_LogSaveClientString(smb_logp, *pathNamep));
1891 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1892 0, KEY_QUERY_VALUE, &parmKey);
1893 if (code == ERROR_SUCCESS) {
1894 cblen = sizeof(pathName);
1895 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1896 (BYTE *) pathName, &cblen);
1897 if (code != ERROR_SUCCESS)
1899 RegCloseKey (parmKey);
1903 cchlen = cblen / sizeof(clientchar_t);
1904 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1905 /* We can accept either unix or PC style AFS pathnames. Convert
1906 * Unix-style to PC style here for internal use.
1909 cchlen = lengthof(pathName);
1911 /* within this code block, we maintain, cchlen = writeable
1912 buffer length of p */
1914 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1915 p += cm_mountRootCLen; /* skip mount path */
1916 cchlen -= (DWORD)(p - pathName);
1921 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1927 clientchar_t temp[1024];
1929 if (var = smb_stristr(p, VNUserName)) {
1930 if (uidp && uidp->unp)
1931 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1933 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1935 else if (var = smb_stristr(p, VNLCUserName))
1937 if (uidp && uidp->unp)
1938 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1940 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1941 cm_ClientStrLwr(temp);
1942 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1944 else if (var = smb_stristr(p, VNComputerName))
1946 sizeTemp = lengthof(temp);
1947 GetComputerNameW(temp, &sizeTemp);
1948 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1950 else if (var = smb_stristr(p, VNLCComputerName))
1952 sizeTemp = lengthof(temp);
1953 GetComputerName((LPTSTR)temp, &sizeTemp);
1954 cm_ClientStrLwr(temp);
1955 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1960 *pathNamep = cm_ClientStrDup(p);
1965 /* First lookup shareName in root.afs */
1967 smb_findShare_rock_t vrock;
1969 fschar_t ftemp[1024];
1970 clientchar_t * p = shareName;
1973 /* attempt to locate a partial match in root.afs. This is because
1974 when using the ANSI RAP calls, the share name is limited to 13 chars
1975 and hence is truncated. Of course we prefer exact matches. */
1977 thyper.HighPart = 0;
1980 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1981 if (vrock.shareName == NULL)
1984 vrock.matchType = 0;
1986 cm_HoldSCache(cm_data.rootSCachep);
1987 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1988 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1989 cm_ReleaseSCache(cm_data.rootSCachep);
1991 free(vrock.shareName);
1992 vrock.shareName = NULL;
1994 if (vrock.matchType) {
1995 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1996 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2001 /* if we get here, there was no match for the share in root.afs */
2002 /* so try to create \\<netbiosName>\<cellname> */
2007 /* Get the full name for this cell */
2008 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2009 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2010 #ifdef AFS_AFSDB_ENV
2011 if (code && cm_dnsEnabled) {
2013 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2019 /* construct the path */
2021 clientchar_t temp[1024];
2023 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2024 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2025 rw ? _C("/.%S/") : _C("/%S/"), temp);
2026 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2036 /* Client-side offline caching policy types */
2037 #define CSC_POLICY_MANUAL 0
2038 #define CSC_POLICY_DOCUMENTS 1
2039 #define CSC_POLICY_PROGRAMS 2
2040 #define CSC_POLICY_DISABLE 3
2042 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2045 clientchar_t policy[1024];
2048 int retval = CSC_POLICY_MANUAL;
2050 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2051 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2054 REG_OPTION_NON_VOLATILE,
2060 len = sizeof(policy);
2061 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2063 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2065 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2067 retval = CSC_POLICY_DOCUMENTS;
2069 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2071 retval = CSC_POLICY_PROGRAMS;
2073 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2075 retval = CSC_POLICY_DISABLE;
2078 RegCloseKey(hkCSCPolicy);
2082 /* find a dir search structure by cookie value, and return it held.
2083 * Must be called with smb_globalLock held.
2085 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2087 smb_dirSearch_t *dsp;
2089 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2090 if (dsp->cookie == cookie) {
2091 if (dsp != smb_firstDirSearchp) {
2092 /* move to head of LRU queue, too, if we're not already there */
2093 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2094 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2095 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2096 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2097 if (!smb_lastDirSearchp)
2098 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2106 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2107 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2108 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2114 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2116 lock_ObtainMutex(&dsp->mx);
2117 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2118 dsp->cookie, dsp, dsp->scp);
2119 dsp->flags |= SMB_DIRSEARCH_DELETE;
2120 if (dsp->scp != NULL) {
2121 lock_ObtainWrite(&dsp->scp->rw);
2122 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2123 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2124 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2125 dsp->scp->bulkStatProgress = hzero;
2127 lock_ReleaseWrite(&dsp->scp->rw);
2129 lock_ReleaseMutex(&dsp->mx);
2132 /* Must be called with the smb_globalLock held */
2133 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2135 cm_scache_t *scp = NULL;
2137 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2138 if (dsp->refCount == 0) {
2139 lock_ObtainMutex(&dsp->mx);
2140 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2141 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2142 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2143 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2144 lock_ReleaseMutex(&dsp->mx);
2145 lock_FinalizeMutex(&dsp->mx);
2147 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2148 dsp->cookie, dsp, scp);
2151 lock_ReleaseMutex(&dsp->mx);
2154 /* do this now to avoid spurious locking hierarchy creation */
2156 cm_ReleaseSCache(scp);
2159 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2161 lock_ObtainWrite(&smb_globalLock);
2162 smb_ReleaseDirSearchNoLock(dsp);
2163 lock_ReleaseWrite(&smb_globalLock);
2166 /* find a dir search structure by cookie value, and return it held */
2167 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2169 smb_dirSearch_t *dsp;
2171 lock_ObtainWrite(&smb_globalLock);
2172 dsp = smb_FindDirSearchNoLock(cookie);
2173 lock_ReleaseWrite(&smb_globalLock);
2177 /* GC some dir search entries, in the address space expected by the specific protocol.
2178 * Must be called with smb_globalLock held; release the lock temporarily.
2180 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2181 void smb_GCDirSearches(int isV3)
2183 smb_dirSearch_t *prevp;
2184 smb_dirSearch_t *dsp;
2185 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2189 victimCount = 0; /* how many have we got so far */
2190 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2191 /* we'll move tp from queue, so
2194 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2195 /* if no one is using this guy, and we're either in the new protocol,
2196 * or we're in the old one and this is a small enough ID to be useful
2197 * to the old protocol, GC this guy.
2199 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2200 /* hold and delete */
2201 lock_ObtainMutex(&dsp->mx);
2202 dsp->flags |= SMB_DIRSEARCH_DELETE;
2203 lock_ReleaseMutex(&dsp->mx);
2204 victimsp[victimCount++] = dsp;
2208 /* don't do more than this */
2209 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2213 /* now release them */
2214 for (i = 0; i < victimCount; i++) {
2215 smb_ReleaseDirSearchNoLock(victimsp[i]);
2219 /* function for allocating a dir search entry. We need these to remember enough context
2220 * since we don't get passed the path from call to call during a directory search.
2222 * Returns a held dir search structure, and bumps the reference count on the vnode,
2223 * since it saves a pointer to the vnode.
2225 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2227 smb_dirSearch_t *dsp;
2233 lock_ObtainWrite(&smb_globalLock);
2236 /* what's the biggest ID allowed in this version of the protocol */
2237 /* TODO: do we really want a non v3 dir search request to wrap
2238 smb_dirSearchCounter? */
2239 maxAllowed = isV3 ? 65535 : 255;
2240 if (smb_dirSearchCounter > maxAllowed)
2241 smb_dirSearchCounter = 1;
2243 start = smb_dirSearchCounter;
2246 /* twice so we have enough tries to find guys we GC after one pass;
2247 * 10 extra is just in case I mis-counted.
2249 if (++counter > 2*maxAllowed+10)
2250 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2252 if (smb_dirSearchCounter > maxAllowed) {
2253 smb_dirSearchCounter = 1;
2255 if (smb_dirSearchCounter == start) {
2257 smb_GCDirSearches(isV3);
2260 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2262 /* don't need to watch for refcount zero and deleted, since
2263 * we haven't dropped the global lock.
2266 ++smb_dirSearchCounter;
2270 dsp = malloc(sizeof(*dsp));
2271 memset(dsp, 0, sizeof(*dsp));
2272 dsp->cookie = smb_dirSearchCounter;
2273 ++smb_dirSearchCounter;
2275 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2276 dsp->lastTime = osi_Time();
2277 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2278 if (!smb_lastDirSearchp)
2279 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2281 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2285 lock_ReleaseWrite(&smb_globalLock);
2289 static smb_packet_t *smb_GetPacket(void)
2293 lock_ObtainWrite(&smb_globalLock);
2294 tbp = smb_packetFreeListp;
2296 smb_packetFreeListp = tbp->nextp;
2297 lock_ReleaseWrite(&smb_globalLock);
2299 tbp = calloc(sizeof(*tbp),1);
2300 tbp->magic = SMB_PACKETMAGIC;
2303 tbp->resumeCode = 0;
2309 tbp->ncb_length = 0;
2312 tbp->stringsp = NULL;
2314 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2319 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2322 tbp = smb_GetPacket();
2323 memcpy(tbp, pkt, sizeof(smb_packet_t));
2324 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2325 tbp->stringsp = NULL;
2327 smb_HoldVC(tbp->vcp);
2331 static NCB *smb_GetNCB(void)
2336 lock_ObtainWrite(&smb_globalLock);
2337 tbp = smb_ncbFreeListp;
2339 smb_ncbFreeListp = tbp->nextp;
2340 lock_ReleaseWrite(&smb_globalLock);
2342 tbp = calloc(sizeof(*tbp),1);
2343 tbp->magic = SMB_NCBMAGIC;
2346 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2348 memset(&tbp->ncb, 0, sizeof(NCB));
2353 static void FreeSMBStrings(smb_packet_t * pkt)
2358 for (s = pkt->stringsp; s; s = ns) {
2362 pkt->stringsp = NULL;
2365 void smb_FreePacket(smb_packet_t *tbp)
2367 smb_vc_t * vcp = NULL;
2368 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2370 lock_ObtainWrite(&smb_globalLock);
2371 tbp->nextp = smb_packetFreeListp;
2372 smb_packetFreeListp = tbp;
2373 tbp->magic = SMB_PACKETMAGIC;
2377 tbp->resumeCode = 0;
2383 tbp->ncb_length = 0;
2385 FreeSMBStrings(tbp);
2386 lock_ReleaseWrite(&smb_globalLock);
2392 static void smb_FreeNCB(NCB *bufferp)
2396 tbp = (smb_ncb_t *) bufferp;
2397 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2399 lock_ObtainWrite(&smb_globalLock);
2400 tbp->nextp = smb_ncbFreeListp;
2401 smb_ncbFreeListp = tbp;
2402 lock_ReleaseWrite(&smb_globalLock);
2405 /* get a ptr to the data part of a packet, and its count */
2406 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2410 unsigned char *afterParmsp;
2412 parmBytes = *smbp->wctp << 1;
2413 afterParmsp = smbp->wctp + parmBytes + 1;
2415 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2416 if (nbytesp) *nbytesp = dataBytes;
2418 /* don't forget to skip the data byte count, since it follows
2419 * the parameters; that's where the "2" comes from below.
2421 return (unsigned char *) (afterParmsp + 2);
2424 /* must set all the returned parameters before playing around with the
2425 * data region, since the data region is located past the end of the
2426 * variable number of parameters.
2428 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2430 unsigned char *afterParmsp;
2432 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2434 *afterParmsp++ = dsize & 0xff;
2435 *afterParmsp = (dsize>>8) & 0xff;
2438 /* return the parm'th parameter in the smbp packet */
2439 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2442 unsigned char *parmDatap;
2444 parmCount = *smbp->wctp;
2446 if (parm >= parmCount) {
2449 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2450 parm, parmCount, smbp->ncb_length);
2451 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2452 parm, parmCount, smbp->ncb_length);
2453 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2454 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2455 osi_panic(s, __FILE__, __LINE__);
2457 parmDatap = smbp->wctp + (2*parm) + 1;
2459 return parmDatap[0] + (parmDatap[1] << 8);
2462 /* return the parm'th parameter in the smbp packet */
2463 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2466 unsigned char *parmDatap;
2468 parmCount = *smbp->wctp;
2470 if (parm >= parmCount) {
2473 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2474 parm, parmCount, smbp->ncb_length);
2475 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2476 parm, parmCount, smbp->ncb_length);
2477 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2478 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2479 osi_panic(s, __FILE__, __LINE__);
2481 parmDatap = smbp->wctp + (2*parm) + 1;
2483 return parmDatap[0];
2486 /* return the parm'th parameter in the smbp packet */
2487 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2490 unsigned char *parmDatap;
2492 parmCount = *smbp->wctp;
2494 if (parm + 1 >= parmCount) {
2497 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2498 parm, parmCount, smbp->ncb_length);
2499 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2500 parm, parmCount, smbp->ncb_length);
2501 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2502 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2503 osi_panic(s, __FILE__, __LINE__);
2505 parmDatap = smbp->wctp + (2*parm) + 1;
2507 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2510 /* return the parm'th parameter in the smbp packet */
2511 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2514 unsigned char *parmDatap;
2516 parmCount = *smbp->wctp;
2518 if (parm * 2 + offset >= parmCount * 2) {
2521 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2522 parm, offset, parmCount, smbp->ncb_length);
2523 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2524 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2525 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2526 parm, offset, parmCount, smbp->ncb_length);
2527 osi_panic(s, __FILE__, __LINE__);
2529 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2531 return parmDatap[0] + (parmDatap[1] << 8);
2534 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2536 unsigned char *parmDatap;
2538 /* make sure we have enough slots */
2539 if (*smbp->wctp <= slot)
2540 *smbp->wctp = slot+1;
2542 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2543 *parmDatap++ = parmValue & 0xff;
2544 *parmDatap = (parmValue>>8) & 0xff;
2547 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2549 unsigned char *parmDatap;
2551 /* make sure we have enough slots */
2552 if (*smbp->wctp <= slot)
2553 *smbp->wctp = slot+2;
2555 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2556 *parmDatap++ = parmValue & 0xff;
2557 *parmDatap++ = (parmValue>>8) & 0xff;
2558 *parmDatap++ = (parmValue>>16) & 0xff;
2559 *parmDatap = (parmValue>>24) & 0xff;
2562 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2564 unsigned char *parmDatap;
2567 /* make sure we have enough slots */
2568 if (*smbp->wctp <= slot)
2569 *smbp->wctp = slot+4;
2571 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2573 *parmDatap++ = *parmValuep++;
2576 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2578 unsigned char *parmDatap;
2580 /* make sure we have enough slots */
2581 if (*smbp->wctp <= slot) {
2582 if (smbp->oddByte) {
2584 *smbp->wctp = slot+1;
2589 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2590 *parmDatap++ = parmValue & 0xff;
2595 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2596 clientchar_t *inPathp)
2598 clientchar_t *lastSlashp;
2600 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2602 *lastComponentp = lastSlashp;
2605 if (inPathp == lastSlashp)
2607 *outPathp++ = *inPathp++;
2616 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2617 char **chainpp, int flags)
2620 afs_uint32 type = *inp++;
2623 * The first byte specifies the type of the input string.
2624 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2628 /* Length Counted */
2629 case 0x1: /* Data Block */
2630 case 0x5: /* Variable Block */
2631 cb = *inp++ << 16 | *inp++;
2634 /* Null-terminated string */
2635 case 0x4: /* ASCII */
2636 case 0x3: /* Pathname */
2637 case 0x2: /* Dialect */
2638 cb = sizeof(pktp->data) - (inp - pktp->data);
2639 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2640 #ifdef DEBUG_UNICODE
2643 cb = sizeof(pktp->data);
2648 return NULL; /* invalid input */
2652 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2653 flags |= SMB_STRF_FORCEASCII;
2656 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2659 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2660 char ** chainpp, int flags)
2665 if (!WANTS_UNICODE(pktp))
2666 flags |= SMB_STRF_FORCEASCII;
2669 cb = sizeof(pktp->data) - (inp - pktp->data);
2670 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2671 #ifdef DEBUG_UNICODE
2674 cb = sizeof(pktp->data);
2676 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2677 flags | SMB_STRF_SRCNULTERM);
2680 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2681 size_t cb, char ** chainpp, int flags)
2684 if (!WANTS_UNICODE(pktp))
2685 flags |= SMB_STRF_FORCEASCII;
2688 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2691 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2692 size_t cch, char ** chainpp, int flags)
2697 if (!WANTS_UNICODE(pktp))
2698 flags |= SMB_STRF_FORCEASCII;
2700 cb = cch * sizeof(wchar_t);
2703 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2707 smb_ParseStringBuf(const unsigned char * bufbase,
2708 cm_space_t ** stringspp,
2709 unsigned char *inp, size_t *pcb_max,
2710 char **chainpp, int flags)
2713 if (!(flags & SMB_STRF_FORCEASCII)) {
2715 cm_space_t * spacep;
2718 if (bufbase && ((inp - bufbase) % 2) != 0) {
2719 inp++; /* unicode strings are always word aligned */
2723 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2725 cch_src = *pcb_max / sizeof(wchar_t);
2729 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2736 spacep = cm_GetSpace();
2737 spacep->nextp = *stringspp;
2738 *stringspp = spacep;
2742 *chainpp = inp + sizeof(wchar_t);
2745 *(spacep->wdata) = 0;
2746 return spacep->wdata;
2749 StringCchCopyNW(spacep->wdata,
2750 lengthof(spacep->wdata),
2751 (const clientchar_t *) inp, cch_src);
2754 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2756 return spacep->wdata;
2760 cm_space_t * spacep;
2763 /* Not using Unicode */
2765 *chainpp = inp + strlen(inp) + 1;
2768 spacep = cm_GetSpace();
2769 spacep->nextp = *stringspp;
2770 *stringspp = spacep;
2772 cchdest = lengthof(spacep->wdata);
2773 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2774 spacep->wdata, cchdest);
2776 return spacep->wdata;
2782 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2784 size_t * plen, int flags)
2790 /* we are only calculating the required size */
2797 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2799 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2800 if (!(flags & SMB_STRF_IGNORENUL))
2801 *plen += sizeof(wchar_t);
2803 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2813 cch_str = cm_ClientStrLen(str);
2814 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2817 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2825 /* if outp != NULL ... */
2827 /* Number of bytes left in the buffer.
2829 If outp lies inside the packet data buffer, we assume that the
2830 buffer is the packet data buffer. Otherwise we assume that the
2831 buffer is sizeof(packet->data).
2834 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2835 align = (int)((outp - pktp->data) % 2);
2836 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2838 align = (int)(((size_t) outp) % 2);
2839 buffersize = (int)sizeof(pktp->data);
2844 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2850 if (*str == _C('\0')) {
2852 if (buffersize < sizeof(wchar_t))
2855 *((wchar_t *) outp) = L'\0';
2856 if (plen && !(flags & SMB_STRF_IGNORENUL))
2857 *plen += sizeof(wchar_t);
2858 return outp + sizeof(wchar_t);
2861 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2863 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2864 osi_LogSaveClientString(smb_logp, str),
2870 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2872 return outp + sizeof(wchar_t) * nchars;
2880 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2883 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2885 return outp + cch_dest;
2889 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2895 tlen = inp[0] + (inp[1]<<8);
2896 inp += 2; /* skip length field */
2899 *chainpp = inp + tlen;
2908 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2912 if (*inp++ != 0x1) return NULL;
2913 tlen = inp[0] + (inp[1]<<8);
2914 inp += 2; /* skip length field */
2917 *chainpp = inp + tlen;
2920 if (lengthp) *lengthp = tlen;
2925 /* format a packet as a response */
2926 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2931 outp = (smb_t *) op;
2933 /* zero the basic structure through the smb_wct field, and zero the data
2934 * size field, assuming that wct stays zero; otherwise, you have to
2935 * explicitly set the data size field, too.
2937 inSmbp = (smb_t *) inp;
2938 memset(outp, 0, sizeof(smb_t)+2);
2944 outp->com = inSmbp->com;
2945 outp->tid = inSmbp->tid;
2946 outp->pid = inSmbp->pid;
2947 outp->uid = inSmbp->uid;
2948 outp->mid = inSmbp->mid;
2949 outp->res[0] = inSmbp->res[0];
2950 outp->res[1] = inSmbp->res[1];
2951 op->inCom = inSmbp->com;
2953 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2954 #ifdef SEND_CANONICAL_PATHNAMES
2955 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2957 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2959 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2960 outp->flg2 |= SMB_FLAGS2_UNICODE;
2963 /* copy fields in generic packet area */
2964 op->wctp = &outp->wct;
2967 /* send a (probably response) packet; vcp tells us to whom to send it.
2968 * we compute the length by looking at wct and bcc fields.
2970 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2980 ncbp = smb_GetNCB();
2984 memset((char *)ncbp, 0, sizeof(NCB));
2986 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2987 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2988 extra += tp[0] + (tp[1]<<8);
2989 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2990 extra += 3; /* wct and length fields */
2992 ncbp->ncb_length = extra; /* bytes to send */
2993 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2994 ncbp->ncb_lana_num = vcp->lana;
2995 ncbp->ncb_command = NCBSEND; /* op means send data */
2996 ncbp->ncb_buffer = (char *) inp;/* packet */
2997 code = Netbios(ncbp);
3000 const char * s = ncb_error_string(code);
3001 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3002 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3004 lock_ObtainMutex(&vcp->mx);
3005 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3006 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3008 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3009 lock_ReleaseMutex(&vcp->mx);
3010 lock_ObtainWrite(&smb_globalLock);
3011 dead_sessions[vcp->session] = TRUE;
3012 lock_ReleaseWrite(&smb_globalLock);
3013 smb_CleanupDeadVC(vcp);
3015 lock_ReleaseMutex(&vcp->mx);
3023 void smb_MapNTError(long code, unsigned long *NTStatusp)
3025 unsigned long NTStatus;
3027 /* map CM_ERROR_* errors to NT 32-bit status codes */
3028 /* NT Status codes are listed in ntstatus.h not winerror.h */
3032 else if (code == CM_ERROR_NOSUCHCELL) {
3033 NTStatus = 0xC000000FL; /* No such file */
3035 else if (code == CM_ERROR_NOSUCHVOLUME) {
3036 NTStatus = 0xC000000FL; /* No such file */
3038 else if (code == CM_ERROR_TIMEDOUT) {
3040 NTStatus = 0xC00000CFL; /* Sharing Paused */
3042 NTStatus = 0x00000102L; /* Timeout */
3045 else if (code == CM_ERROR_RETRY) {
3046 NTStatus = 0xC000022DL; /* Retry */
3048 else if (code == CM_ERROR_NOACCESS) {
3049 NTStatus = 0xC0000022L; /* Access denied */
3051 else if (code == CM_ERROR_READONLY) {
3052 NTStatus = 0xC00000A2L; /* Write protected */
3054 else if (code == CM_ERROR_NOSUCHFILE ||
3055 code == CM_ERROR_BPLUS_NOMATCH) {
3056 NTStatus = 0xC000000FL; /* No such file */
3058 else if (code == CM_ERROR_NOSUCHPATH) {
3059 NTStatus = 0xC000003AL; /* Object path not found */
3061 else if (code == CM_ERROR_TOOBIG) {
3062 NTStatus = 0xC000007BL; /* Invalid image format */
3064 else if (code == CM_ERROR_INVAL) {
3065 NTStatus = 0xC000000DL; /* Invalid parameter */
3067 else if (code == CM_ERROR_BADFD) {
3068 NTStatus = 0xC0000008L; /* Invalid handle */
3070 else if (code == CM_ERROR_BADFDOP) {
3071 NTStatus = 0xC0000022L; /* Access denied */
3073 else if (code == CM_ERROR_EXISTS) {
3074 NTStatus = 0xC0000035L; /* Object name collision */
3076 else if (code == CM_ERROR_NOTEMPTY) {
3077 NTStatus = 0xC0000101L; /* Directory not empty */
3079 else if (code == CM_ERROR_CROSSDEVLINK) {
3080 NTStatus = 0xC00000D4L; /* Not same device */
3082 else if (code == CM_ERROR_NOTDIR) {
3083 NTStatus = 0xC0000103L; /* Not a directory */
3085 else if (code == CM_ERROR_ISDIR) {
3086 NTStatus = 0xC00000BAL; /* File is a directory */
3088 else if (code == CM_ERROR_BADOP) {
3090 /* I have no idea where this comes from */
3091 NTStatus = 0xC09820FFL; /* SMB no support */
3093 NTStatus = 0xC00000BBL; /* Not supported */
3094 #endif /* COMMENT */
3096 else if (code == CM_ERROR_BADSHARENAME) {
3097 NTStatus = 0xC00000CCL; /* Bad network name */
3099 else if (code == CM_ERROR_NOIPC) {
3101 NTStatus = 0xC0000022L; /* Access Denied */
3103 NTStatus = 0xC000013DL; /* Remote Resources */
3106 else if (code == CM_ERROR_CLOCKSKEW) {
3107 NTStatus = 0xC0000133L; /* Time difference at DC */
3109 else if (code == CM_ERROR_BADTID) {
3110 NTStatus = 0xC0982005L; /* SMB bad TID */
3112 else if (code == CM_ERROR_USESTD) {
3113 NTStatus = 0xC09820FBL; /* SMB use standard */
3115 else if (code == CM_ERROR_QUOTA) {
3116 NTStatus = 0xC0000044L; /* Quota exceeded */
3118 else if (code == CM_ERROR_SPACE) {
3119 NTStatus = 0xC000007FL; /* Disk full */
3121 else if (code == CM_ERROR_ATSYS) {
3122 NTStatus = 0xC0000033L; /* Object name invalid */
3124 else if (code == CM_ERROR_BADNTFILENAME) {
3125 NTStatus = 0xC0000033L; /* Object name invalid */
3127 else if (code == CM_ERROR_WOULDBLOCK) {
3128 NTStatus = 0xC00000D8L; /* Can't wait */
3130 else if (code == CM_ERROR_SHARING_VIOLATION) {
3131 NTStatus = 0xC0000043L; /* Sharing violation */
3133 else if (code == CM_ERROR_LOCK_CONFLICT) {
3134 NTStatus = 0xC0000054L; /* Lock conflict */
3136 else if (code == CM_ERROR_PARTIALWRITE) {
3137 NTStatus = 0xC000007FL; /* Disk full */
3139 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3140 NTStatus = 0xC0000023L; /* Buffer too small */
3142 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3143 NTStatus = 0xC0000035L; /* Object name collision */
3145 else if (code == CM_ERROR_BADPASSWORD) {
3146 NTStatus = 0xC000006DL; /* unknown username or bad password */
3148 else if (code == CM_ERROR_BADLOGONTYPE) {
3149 NTStatus = 0xC000015BL; /* logon type not granted */
3151 else if (code == CM_ERROR_GSSCONTINUE) {
3152 NTStatus = 0xC0000016L; /* more processing required */
3154 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3156 NTStatus = 0xC0000280L; /* reparse point not resolved */
3158 NTStatus = 0xC0000022L; /* Access Denied */
3161 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3162 NTStatus = 0xC0000257L; /* Path Not Covered */
3164 else if (code == CM_ERROR_ALLBUSY) {
3165 NTStatus = 0xC000022DL; /* Retry */
3167 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3168 NTStatus = 0xC00000BEL; /* Bad Network Path */
3170 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3171 NTStatus = 0xC0000322L; /* No Kerberos key */
3173 else if (code == CM_ERROR_BAD_LEVEL) {
3174 NTStatus = 0xC0000148L; /* Invalid Level */
3176 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3177 NTStatus = 0xC000007EL; /* Range Not Locked */
3179 else if (code == CM_ERROR_NOSUCHDEVICE) {
3180 NTStatus = 0xC000000EL; /* No Such Device */
3182 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3183 NTStatus = 0xC0000055L; /* Lock Not Granted */
3184 } else if (code == ENOMEM) {
3185 NTStatus = 0xC0000017L; /* Out of Memory */
3187 NTStatus = 0xC0982001L; /* SMB non-specific error */
3190 *NTStatusp = NTStatus;
3191 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3194 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3195 unsigned char *classp)
3197 unsigned char class;
3198 unsigned short error;
3200 /* map CM_ERROR_* errors to SMB errors */
3201 if (code == CM_ERROR_NOSUCHCELL) {
3203 error = 3; /* bad path */
3205 else if (code == CM_ERROR_NOSUCHVOLUME) {
3207 error = 3; /* bad path */
3209 else if (code == CM_ERROR_TIMEDOUT) {
3211 error = 81; /* server is paused */
3213 else if (code == CM_ERROR_RETRY) {
3214 class = 2; /* shouldn't happen */
3217 else if (code == CM_ERROR_NOACCESS) {
3219 error = 4; /* bad access */
3221 else if (code == CM_ERROR_READONLY) {
3223 error = 19; /* read only */
3225 else if (code == CM_ERROR_NOSUCHFILE ||
3226 code == CM_ERROR_BPLUS_NOMATCH) {
3228 error = 2; /* ENOENT! */
3230 else if (code == CM_ERROR_NOSUCHPATH) {
3232 error = 3; /* Bad path */
3234 else if (code == CM_ERROR_TOOBIG) {
3236 error = 11; /* bad format */
3238 else if (code == CM_ERROR_INVAL) {
3239 class = 2; /* server non-specific error code */
3242 else if (code == CM_ERROR_BADFD) {
3244 error = 6; /* invalid file handle */
3246 else if (code == CM_ERROR_BADFDOP) {
3247 class = 1; /* invalid op on FD */
3250 else if (code == CM_ERROR_EXISTS) {
3252 error = 80; /* file already exists */
3254 else if (code == CM_ERROR_NOTEMPTY) {
3256 error = 5; /* delete directory not empty */
3258 else if (code == CM_ERROR_CROSSDEVLINK) {
3260 error = 17; /* EXDEV */
3262 else if (code == CM_ERROR_NOTDIR) {
3263 class = 1; /* bad path */
3266 else if (code == CM_ERROR_ISDIR) {
3267 class = 1; /* access denied; DOS doesn't have a good match */
3270 else if (code == CM_ERROR_BADOP) {
3274 else if (code == CM_ERROR_BADSHARENAME) {
3278 else if (code == CM_ERROR_NOIPC) {
3280 error = 4; /* bad access */
3282 else if (code == CM_ERROR_CLOCKSKEW) {
3283 class = 1; /* invalid function */
3286 else if (code == CM_ERROR_BADTID) {
3290 else if (code == CM_ERROR_USESTD) {
3294 else if (code == CM_ERROR_REMOTECONN) {
3298 else if (code == CM_ERROR_QUOTA) {
3299 if (vcp->flags & SMB_VCFLAG_USEV3) {
3301 error = 39; /* disk full */
3305 error = 5; /* access denied */
3308 else if (code == CM_ERROR_SPACE) {
3309 if (vcp->flags & SMB_VCFLAG_USEV3) {
3311 error = 39; /* disk full */
3315 error = 5; /* access denied */
3318 else if (code == CM_ERROR_PARTIALWRITE) {
3320 error = 39; /* disk full */
3322 else if (code == CM_ERROR_ATSYS) {
3324 error = 2; /* ENOENT */
3326 else if (code == CM_ERROR_WOULDBLOCK) {
3328 error = 33; /* lock conflict */
3330 else if (code == CM_ERROR_LOCK_CONFLICT) {
3332 error = 33; /* lock conflict */
3334 else if (code == CM_ERROR_SHARING_VIOLATION) {
3336 error = 33; /* lock conflict */
3338 else if (code == CM_ERROR_NOFILES) {
3340 error = 18; /* no files in search */
3342 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3344 error = 183; /* Samba uses this */
3346 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3347 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3349 error = 2; /* bad password */
3351 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3353 error = 3; /* bad path */
3362 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3365 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3367 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3368 return CM_ERROR_BADOP;
3372 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3374 unsigned short EchoCount, i;
3375 char *data, *outdata;
3378 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3380 for (i=1; i<=EchoCount; i++) {
3381 data = smb_GetSMBData(inp, &dataSize);
3382 smb_SetSMBParm(outp, 0, i);
3383 smb_SetSMBDataLength(outp, dataSize);
3384 outdata = smb_GetSMBData(outp, NULL);
3385 memcpy(outdata, data, dataSize);
3386 smb_SendPacket(vcp, outp);
3392 /* SMB_COM_READ_RAW */
3393 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3396 long count, minCount, finalCount;
3400 smb_t *smbp = (smb_t*) inp;
3402 cm_user_t *userp = NULL;
3405 char *rawBuf = NULL;
3410 fd = smb_GetSMBParm(inp, 0);
3411 count = smb_GetSMBParm(inp, 3);
3412 minCount = smb_GetSMBParm(inp, 4);
3413 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3415 if (*inp->wctp == 10) {
3416 /* we were sent a request with 64-bit file offsets */
3417 #ifdef AFS_LARGEFILES
3418 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3420 if (LargeIntegerLessThanZero(offset)) {
3421 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3425 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3426 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3429 offset.HighPart = 0;
3433 /* we were sent a request with 32-bit file offsets */
3434 offset.HighPart = 0;
3437 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3438 fd, offset.HighPart, offset.LowPart, count);
3440 fidp = smb_FindFID(vcp, fd, 0);
3444 lock_ObtainMutex(&fidp->mx);
3445 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3446 lock_ReleaseMutex(&fidp->mx);
3447 smb_CloseFID(vcp, fidp, NULL, 0);
3448 code = CM_ERROR_NOSUCHFILE;
3454 LARGE_INTEGER LOffset, LLength;
3457 key = cm_GenerateKey(vcp->vcID, pid, fd);
3459 LOffset.HighPart = offset.HighPart;
3460 LOffset.LowPart = offset.LowPart;
3461 LLength.HighPart = 0;
3462 LLength.LowPart = count;
3464 lock_ObtainWrite(&fidp->scp->rw);
3465 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3466 lock_ReleaseWrite(&fidp->scp->rw);
3469 lock_ReleaseMutex(&fidp->mx);
3473 lock_ObtainMutex(&smb_RawBufLock);
3475 /* Get a raw buf, from head of list */
3476 rawBuf = smb_RawBufs;
3477 smb_RawBufs = *(char **)smb_RawBufs;
3479 lock_ReleaseMutex(&smb_RawBufLock);
3481 lock_ReleaseMutex(&fidp->mx);
3485 if (fidp->flags & SMB_FID_IOCTL)
3487 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3489 /* Give back raw buffer */
3490 lock_ObtainMutex(&smb_RawBufLock);
3491 *((char **) rawBuf) = smb_RawBufs;
3493 smb_RawBufs = rawBuf;
3494 lock_ReleaseMutex(&smb_RawBufLock);
3497 lock_ReleaseMutex(&fidp->mx);
3498 smb_ReleaseFID(fidp);
3501 lock_ReleaseMutex(&fidp->mx);
3503 userp = smb_GetUserFromVCP(vcp, inp);
3505 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3511 cm_ReleaseUser(userp);
3514 smb_ReleaseFID(fidp);
3518 memset((char *)ncbp, 0, sizeof(NCB));
3520 ncbp->ncb_length = (unsigned short) finalCount;
3521 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3522 ncbp->ncb_lana_num = vcp->lana;
3523 ncbp->ncb_command = NCBSEND;
3524 ncbp->ncb_buffer = rawBuf;
3526 code = Netbios(ncbp);
3528 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3531 /* Give back raw buffer */
3532 lock_ObtainMutex(&smb_RawBufLock);
3533 *((char **) rawBuf) = smb_RawBufs;
3535 smb_RawBufs = rawBuf;
3536 lock_ReleaseMutex(&smb_RawBufLock);
3542 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3544 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3549 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3551 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3556 /* SMB_COM_NEGOTIATE */
3557 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3564 int VistaProtoIndex;
3565 int protoIndex; /* index we're using */
3570 char protocol_array[10][1024]; /* protocol signature of the client */
3571 int caps; /* capabilities */
3574 TIME_ZONE_INFORMATION tzi;
3576 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3579 namep = smb_GetSMBData(inp, &dbytes);
3582 coreProtoIndex = -1; /* not found */
3585 VistaProtoIndex = -1;
3586 while(namex < dbytes) {
3587 osi_Log1(smb_logp, "Protocol %s",
3588 osi_LogSaveString(smb_logp, namep+1));
3589 strcpy(protocol_array[tcounter], namep+1);
3591 /* namep points at the first protocol, or really, a 0x02
3592 * byte preceding the null-terminated ASCII name.
3594 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3595 coreProtoIndex = tcounter;
3597 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3598 v3ProtoIndex = tcounter;
3600 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3601 NTProtoIndex = tcounter;
3603 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3604 VistaProtoIndex = tcounter;
3607 /* compute size of protocol entry */
3608 entryLength = (int)strlen(namep+1);
3609 entryLength += 2; /* 0x02 bytes and null termination */
3611 /* advance over this protocol entry */
3612 namex += entryLength;
3613 namep += entryLength;
3614 tcounter++; /* which proto entry we're looking at */
3617 lock_ObtainMutex(&vcp->mx);
3619 if (VistaProtoIndex != -1) {
3620 protoIndex = VistaProtoIndex;
3621 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3624 if (NTProtoIndex != -1) {
3625 protoIndex = NTProtoIndex;
3626 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3628 else if (v3ProtoIndex != -1) {
3629 protoIndex = v3ProtoIndex;
3630 vcp->flags |= SMB_VCFLAG_USEV3;
3632 else if (coreProtoIndex != -1) {
3633 protoIndex = coreProtoIndex;
3634 vcp->flags |= SMB_VCFLAG_USECORE;
3636 else protoIndex = -1;
3637 lock_ReleaseMutex(&vcp->mx);
3639 if (protoIndex == -1)
3640 return CM_ERROR_INVAL;
3641 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3642 smb_SetSMBParm(outp, 0, protoIndex);
3643 if (smb_authType != SMB_AUTH_NONE) {
3644 smb_SetSMBParmByte(outp, 1,
3645 NEGOTIATE_SECURITY_USER_LEVEL |
3646 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3648 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3650 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3651 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3652 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3653 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3654 /* The session key is not a well documented field however most clients
3655 * will echo back the session key to the server. Currently we are using
3656 * the same value for all sessions. We should generate a random value
3657 * and store it into the vcp
3659 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3660 smb_SetSMBParm(outp, 8, 1);
3662 * Tried changing the capabilities to support for W2K - defect 117695
3663 * Maybe something else needs to be changed here?
3667 smb_SetSMBParmLong(outp, 9, 0x43fd);
3669 smb_SetSMBParmLong(outp, 9, 0x251);
3672 * 32-bit error codes *
3678 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3680 NTNEGOTIATE_CAPABILITY_DFS |
3682 #ifdef AFS_LARGEFILES
3683 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3685 NTNEGOTIATE_CAPABILITY_NTFIND |
3686 NTNEGOTIATE_CAPABILITY_RAWMODE |
3687 NTNEGOTIATE_CAPABILITY_NTSMB;
3689 if ( smb_authType == SMB_AUTH_EXTENDED )
3690 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3693 if ( smb_UseUnicode ) {
3694 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3698 smb_SetSMBParmLong(outp, 9, caps);
3700 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3701 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3702 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3704 GetTimeZoneInformation(&tzi);
3705 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3707 if (smb_authType == SMB_AUTH_NTLM) {
3708 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3709 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3710 /* paste in encryption key */
3711 datap = smb_GetSMBData(outp, NULL);
3712 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3713 /* and the faux domain name */
3714 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3715 datap + MSV1_0_CHALLENGE_LENGTH,
3716 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3717 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3721 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3723 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3725 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3727 datap = smb_GetSMBData(outp, NULL);
3728 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3731 datap += sizeof(smb_ServerGUID);
3732 memcpy(datap, secBlob, secBlobLength);
3736 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3737 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3740 else if (v3ProtoIndex != -1) {
3741 smb_SetSMBParm(outp, 0, protoIndex);
3743 /* NOTE: Extended authentication cannot be negotiated with v3
3744 * therefore we fail over to NTLM
3746 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3747 smb_SetSMBParm(outp, 1,
3748 NEGOTIATE_SECURITY_USER_LEVEL |
3749 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3751 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3753 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3754 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3755 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3756 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3757 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3758 smb_SetSMBParm(outp, 7, 1);
3760 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3761 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3762 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3764 GetTimeZoneInformation(&tzi);
3765 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3767 /* NOTE: Extended authentication cannot be negotiated with v3
3768 * therefore we fail over to NTLM
3770 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3771 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3772 smb_SetSMBParm(outp, 12, 0); /* resvd */
3773 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3774 datap = smb_GetSMBData(outp, NULL);
3775 /* paste in a new encryption key */
3776 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3777 /* and the faux domain name */
3778 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3779 datap + MSV1_0_CHALLENGE_LENGTH,
3780 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3782 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3783 smb_SetSMBParm(outp, 12, 0); /* resvd */
3784 smb_SetSMBDataLength(outp, 0);
3787 else if (coreProtoIndex != -1) { /* not really supported anymore */
3788 smb_SetSMBParm(outp, 0, protoIndex);
3789 smb_SetSMBDataLength(outp, 0);
3794 void smb_CheckVCs(void)
3796 smb_vc_t * vcp, *nextp;
3797 smb_packet_t * outp = smb_GetPacket();
3800 lock_ObtainWrite(&smb_rctLock);
3801 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3803 if (vcp->magic != SMB_VC_MAGIC)
3804 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3805 __FILE__, __LINE__);
3807 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3809 smb_HoldVCNoLock(vcp);
3812 * obtain a reference to 'nextp' now because we drop the
3813 * smb_rctLock later and the list contents could change
3814 * or 'vcp' could be destroyed when released.
3818 smb_HoldVCNoLock(nextp);
3820 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3821 smb_ReleaseVCNoLock(vcp);
3825 smb_FormatResponsePacket(vcp, NULL, outp);
3826 smbp = (smb_t *)outp;
3827 outp->inCom = smbp->com = 0x2b /* Echo */;
3835 smb_SetSMBParm(outp, 0, 0);
3836 smb_SetSMBDataLength(outp, 0);
3837 lock_ReleaseWrite(&smb_rctLock);
3839 smb_SendPacket(vcp, outp);
3841 lock_ObtainWrite(&smb_rctLock);
3842 smb_ReleaseVCNoLock(vcp);
3844 lock_ReleaseWrite(&smb_rctLock);
3845 smb_FreePacket(outp);
3848 void smb_Daemon(void *parmp)
3850 afs_uint32 count = 0;
3851 smb_username_t **unpp;
3854 while(smbShutdownFlag == 0) {
3858 if (smbShutdownFlag == 1)
3861 if ((count % 72) == 0) { /* every five minutes */
3863 time_t old_localZero = smb_localZero;
3865 /* Initialize smb_localZero */
3866 myTime.tm_isdst = -1; /* compute whether on DST or not */
3867 myTime.tm_year = 70;
3873 smb_localZero = mktime(&myTime);
3875 #ifndef USE_NUMERIC_TIME_CONV
3876 smb_CalculateNowTZ();
3877 #endif /* USE_NUMERIC_TIME_CONV */
3878 #ifdef AFS_FREELANCE
3879 if ( smb_localZero != old_localZero )
3880 cm_noteLocalMountPointChange();
3886 /* GC smb_username_t objects that will no longer be used */
3888 lock_ObtainWrite(&smb_rctLock);
3889 for ( unpp=&usernamesp; *unpp; ) {
3891 smb_username_t *unp;
3893 lock_ObtainMutex(&(*unpp)->mx);
3894 if ( (*unpp)->refCount > 0 ||
3895 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3896 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3898 else if (!smb_LogoffTokenTransfer ||
3899 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3901 lock_ReleaseMutex(&(*unpp)->mx);
3909 lock_FinalizeMutex(&unp->mx);
3915 cm_ReleaseUser(userp);
3917 unpp = &(*unpp)->nextp;
3920 lock_ReleaseWrite(&smb_rctLock);
3922 /* XXX GC dir search entries */
3926 void smb_WaitingLocksDaemon()
3928 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3929 smb_waitingLock_t *wl, *wlNext;
3932 smb_packet_t *inp, *outp;
3936 while (smbShutdownFlag == 0) {
3937 lock_ObtainWrite(&smb_globalLock);
3938 nwlRequest = smb_allWaitingLocks;
3939 if (nwlRequest == NULL) {
3940 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3945 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3952 lock_ObtainWrite(&smb_globalLock);
3954 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3956 wlRequest = nwlRequest;
3957 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3958 lock_ReleaseWrite(&smb_globalLock);
3962 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3963 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3966 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3967 code = CM_ERROR_LOCK_NOT_GRANTED;
3971 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3973 /* wl->state is either _DONE or _WAITING. _ERROR
3974 would no longer be on the queue. */
3975 code = cm_RetryLock( wl->lockp,
3976 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3979 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3980 } else if (code != CM_ERROR_WOULDBLOCK) {
3981 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3986 if (code == CM_ERROR_WOULDBLOCK) {
3989 if (wlRequest->msTimeout != 0xffffffff
3990 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4002 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4005 scp = wlRequest->scp;
4006 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4010 lock_ObtainWrite(&scp->rw);
4012 for (wl = wlRequest->locks; wl; wl = wlNext) {
4013 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4015 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4016 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4017 wl->LLength, wl->key, NULL, &req);
4019 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4024 lock_ReleaseWrite(&scp->rw);
4028 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4031 for (wl = wlRequest->locks; wl; wl = wlNext) {
4032 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4033 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4038 vcp = wlRequest->vcp;
4039 inp = wlRequest->inp;
4040 outp = wlRequest->outp;
4041 ncbp = smb_GetNCB();
4042 ncbp->ncb_length = inp->ncb_length;
4043 inp->spacep = cm_GetSpace();
4045 /* Remove waitingLock from list */
4046 lock_ObtainWrite(&smb_globalLock);
4047 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4049 lock_ReleaseWrite(&smb_globalLock);
4051 /* Resume packet processing */
4053 smb_SetSMBDataLength(outp, 0);
4054 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4055 outp->resumeCode = code;
4057 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4060 cm_FreeSpace(inp->spacep);
4061 smb_FreePacket(inp);
4062 smb_FreePacket(outp);
4064 cm_ReleaseSCache(wlRequest->scp);
4067 } while (nwlRequest && smbShutdownFlag == 0);
4072 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4074 osi_Log0(smb_logp, "SMB receive get disk attributes");
4076 smb_SetSMBParm(outp, 0, 32000);
4077 smb_SetSMBParm(outp, 1, 64);
4078 smb_SetSMBParm(outp, 2, 1024);
4079 smb_SetSMBParm(outp, 3, 30000);
4080 smb_SetSMBParm(outp, 4, 0);
4081 smb_SetSMBDataLength(outp, 0);
4085 /* SMB_COM_TREE_CONNECT */
4086 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4090 unsigned short newTid;
4091 clientchar_t shareName[AFSPATHMAX];
4092 clientchar_t *sharePath;
4095 clientchar_t *pathp;
4098 osi_Log0(smb_logp, "SMB receive tree connect");
4100 /* parse input parameters */
4103 tbp = smb_GetSMBData(inp, NULL);
4104 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4106 return CM_ERROR_BADSMB;
4108 tp = cm_ClientStrRChr(pathp, '\\');
4110 return CM_ERROR_BADSMB;
4111 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4113 lock_ObtainMutex(&vcp->mx);
4114 newTid = vcp->tidCounter++;
4115 lock_ReleaseMutex(&vcp->mx);
4117 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4118 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4120 return CM_ERROR_BADSMB;
4121 userp = smb_GetUserFromUID(uidp);
4122 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4123 smb_ReleaseUID(uidp);
4125 smb_ReleaseTID(tidp, FALSE);
4126 return CM_ERROR_BADSHARENAME;
4128 lock_ObtainMutex(&tidp->mx);
4129 tidp->userp = userp;
4130 tidp->pathname = sharePath;
4131 lock_ReleaseMutex(&tidp->mx);
4132 smb_ReleaseTID(tidp, FALSE);
4134 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4135 smb_SetSMBParm(rsp, 1, newTid);
4136 smb_SetSMBDataLength(rsp, 0);
4138 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4142 /* set maskp to the mask part of the incoming path.
4143 * Mask is 11 bytes long (8.3 with the dot elided).
4144 * Returns true if succeeds with a valid name, otherwise it does
4145 * its best, but returns false.
4147 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4155 /* starts off valid */
4158 /* mask starts out all blanks */
4159 memset(maskp, ' ', 11);
4162 /* find last backslash, or use whole thing if there is none */
4163 tp = cm_ClientStrRChr(pathp, '\\');
4167 tp++; /* skip slash */
4171 /* names starting with a dot are illegal */
4179 if (tc == '.' || tc == '"')
4187 /* if we get here, tp point after the dot */
4188 up = maskp+8; /* ext goes here */
4195 if (tc == '.' || tc == '"')
4198 /* copy extension if not too long */
4208 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4210 clientchar_t umask[11];
4218 /* XXX redo this, calling cm_MatchMask with a converted mask */
4220 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4224 /* otherwise, we have a valid 8.3 name; see if we have a match,
4225 * treating '?' as a wildcard in maskp (but not in the file name).
4227 tp1 = umask; /* real name, in mask format */
4228 tp2 = maskp; /* mask, in mask format */
4229 for(i=0; i<11; i++) {
4230 tc1 = *tp1++; /* clientchar_t from real name */
4231 tc2 = *tp2++; /* clientchar_t from mask */
4232 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4233 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4236 if (tc2 == '?' && tc1 != ' ')
4243 /* we got a match */
4247 clientchar_t *smb_FindMask(clientchar_t *pathp)
4251 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4254 return tp+1; /* skip the slash */
4256 return pathp; /* no slash, return the entire path */
4259 /* SMB_COM_SEARCH for a volume label
4261 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4262 dispatch function.) */
4263 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4265 clientchar_t *pathp;
4267 clientchar_t mask[12];
4268 unsigned char *statBlockp;
4269 unsigned char initStatBlock[21];
4272 osi_Log0(smb_logp, "SMB receive search volume");
4274 /* pull pathname and stat block out of request */
4275 tp = smb_GetSMBData(inp, NULL);
4276 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4277 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4279 return CM_ERROR_BADSMB;
4280 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4281 osi_assertx(statBlockp != NULL, "null statBlock");
4283 statBlockp = initStatBlock;
4287 /* for returning to caller */
4288 smb_Get8Dot3MaskFromPath(mask, pathp);
4290 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4291 tp = smb_GetSMBData(outp, NULL);
4293 *tp++ = 43; /* bytes in a dir entry */
4294 *tp++ = 0; /* high byte in counter */
4296 /* now marshall the dir entry, starting with the search status */
4297 *tp++ = statBlockp[0]; /* Reserved */
4298 memcpy(tp, mask, 11); tp += 11; /* FileName */
4300 /* now pass back server use info, with 1st byte non-zero */
4302 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4304 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4306 *tp++ = 0x8; /* attribute: volume */
4316 /* 4 byte file size */
4322 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4325 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4326 memset(tp, ' ', 13);
4329 /* set the length of the data part of the packet to 43 + 3, for the dir
4330 * entry plus the 5 and the length fields.
4332 smb_SetSMBDataLength(outp, 46);
4337 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4338 clientchar_t * tidPathp, clientchar_t * relPathp,
4339 cm_user_t *userp, cm_req_t *reqp)
4347 smb_dirListPatch_t *patchp;
4348 smb_dirListPatch_t *npatchp;
4349 clientchar_t path[AFSPATHMAX];
4351 afs_int32 mustFake = 0;
4353 code = cm_FindACLCache(dscp, userp, &rights);
4355 lock_ObtainWrite(&dscp->rw);
4356 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4357 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4358 lock_ReleaseWrite(&dscp->rw);
4359 if (code == CM_ERROR_NOACCESS) {
4367 if (!mustFake) { /* Bulk Stat */
4369 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4371 memset(bsp, 0, sizeof(cm_bulkStat_t));
4373 for (patchp = *dirPatchespp, count=0;
4375 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4376 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4380 if (lock_TryWrite(&tscp->rw)) {
4381 /* we have an entry that we can look at */
4382 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4383 /* we have a callback on it. Don't bother
4384 * fetching this stat entry, since we're happy
4385 * with the info we have.
4387 lock_ReleaseWrite(&tscp->rw);
4388 cm_ReleaseSCache(tscp);
4391 lock_ReleaseWrite(&tscp->rw);
4393 cm_ReleaseSCache(tscp);
4397 bsp->fids[i].Volume = patchp->fid.volume;
4398 bsp->fids[i].Vnode = patchp->fid.vnode;
4399 bsp->fids[i].Unique = patchp->fid.unique;
4401 if (bsp->counter == AFSCBMAX) {
4402 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4403 memset(bsp, 0, sizeof(cm_bulkStat_t));
4407 if (bsp->counter > 0)
4408 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4413 for (patchp = *dirPatchespp; patchp; patchp =
4414 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4416 dptr = patchp->dptr;
4418 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4419 relPathp ? relPathp : _C(""), patchp->dep->name);
4420 reqp->relPathp = path;
4421 reqp->tidPathp = tidPathp;
4423 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4424 reqp->relPathp = reqp->tidPathp = NULL;
4427 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4428 *dptr++ = SMB_ATTR_HIDDEN;
4431 lock_ObtainWrite(&scp->rw);
4432 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4433 lock_ReleaseWrite(&scp->rw);
4435 /* set the attribute */
4436 switch (scp->fileType) {
4437 case CM_SCACHETYPE_DIRECTORY:
4438 case CM_SCACHETYPE_MOUNTPOINT:
4439 case CM_SCACHETYPE_INVALID:
4440 attr = SMB_ATTR_DIRECTORY;
4442 case CM_SCACHETYPE_SYMLINK:
4443 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4444 attr = SMB_ATTR_DIRECTORY;
4446 attr = SMB_ATTR_NORMAL;
4449 /* if we get here we either have a normal file
4450 * or we have a file for which we have never
4451 * received status info. In this case, we can
4452 * check the even/odd value of the entry's vnode.
4453 * odd means it is to be treated as a directory
4454 * and even means it is to be treated as a file.
4456 if (mustFake && (scp->fid.vnode & 0x1))
4457 attr = SMB_ATTR_DIRECTORY;
4459 attr = SMB_ATTR_NORMAL;
4463 /* 1969-12-31 23:59:58 +00*/
4464 dosTime = 0xEBBFBF7D;
4467 shortTemp = (unsigned short) (dosTime & 0xffff);
4468 *((u_short *)dptr) = shortTemp;
4471 /* and copy out date */
4472 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4473 *((u_short *)dptr) = shortTemp;
4476 /* copy out file length */
4477 *((u_long *)dptr) = 0;
4480 lock_ConvertWToR(&scp->rw);
4481 attr = smb_Attributes(scp);
4482 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4483 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4484 attr |= SMB_ATTR_HIDDEN;
4488 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4491 shortTemp = (unsigned short) (dosTime & 0xffff);
4492 *((u_short *)dptr) = shortTemp;
4495 /* and copy out date */
4496 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4497 *((u_short *)dptr) = shortTemp;
4500 /* copy out file length */
4501 *((u_long *)dptr) = scp->length.LowPart;
4503 lock_ReleaseRead(&scp->rw);
4505 cm_ReleaseSCache(scp);
4508 /* now free the patches */
4509 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4510 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4514 /* and mark the list as empty */
4515 *dirPatchespp = NULL;
4521 /* SMB_COM_SEARCH */
4522 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4528 clientchar_t *pathp;
4529 cm_dirEntry_t *dep = 0;
4531 smb_dirListPatch_t *dirListPatchesp;
4532 smb_dirListPatch_t *curPatchp;
4536 osi_hyper_t dirLength;
4537 osi_hyper_t bufferOffset;
4538 osi_hyper_t curOffset;
4540 unsigned char *inCookiep;
4541 smb_dirSearch_t *dsp;
4545 unsigned long clientCookie;
4546 cm_pageHeader_t *pageHeaderp;
4547 cm_user_t *userp = NULL;
4549 clientchar_t mask[12];
4551 long nextEntryCookie;
4552 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4553 char resByte; /* reserved byte from the cookie */
4554 char *op; /* output data ptr */
4555 char *origOp; /* original value of op */
4556 cm_space_t *spacep; /* for pathname buffer */
4560 clientchar_t *tidPathp = 0;
4567 maxCount = smb_GetSMBParm(inp, 0);
4569 dirListPatchesp = NULL;
4571 caseFold = CM_FLAG_CASEFOLD;
4573 tp = smb_GetSMBData(inp, NULL);
4574 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4575 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4577 return CM_ERROR_BADSMB;
4579 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4581 return CM_ERROR_BADSMB;
4583 /* We can handle long names */
4584 if (vcp->flags & SMB_VCFLAG_USENT)
4585 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4587 /* make sure we got a whole search status */
4588 if (dataLength < 21) {
4589 nextCookie = 0; /* start at the beginning of the dir */
4592 attribute = smb_GetSMBParm(inp, 1);
4594 /* handle volume info in another function */
4595 if (attribute & 0x8)
4596 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4598 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4599 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4601 if (*pathp == 0) { /* null pathp, treat as root dir */
4602 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4603 return CM_ERROR_NOFILES;
4607 dsp = smb_NewDirSearch(0);
4608 dsp->attribute = attribute;
4609 smb_Get8Dot3MaskFromPath(mask, pathp);
4610 memcpy(dsp->mask, mask, 12);
4612 /* track if this is likely to match a lot of entries */
4613 if (smb_Is8Dot3StarMask(mask))
4618 /* pull the next cookie value out of the search status block */
4619 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4620 + (inCookiep[16]<<24);
4621 dsp = smb_FindDirSearch(inCookiep[12]);
4623 /* can't find dir search status; fatal error */
4624 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4625 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4626 return CM_ERROR_BADFD;
4628 attribute = dsp->attribute;
4629 resByte = inCookiep[0];
4631 /* copy out client cookie, in host byte order. Don't bother
4632 * interpreting it, since we're just passing it through, anyway.
4634 memcpy(&clientCookie, &inCookiep[17], 4);
4636 memcpy(mask, dsp->mask, 12);
4638 /* assume we're doing a star match if it has continued for more
4644 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4645 nextCookie, dsp->cookie, attribute);
4647 userp = smb_GetUserFromVCP(vcp, inp);
4649 /* try to get the vnode for the path name next */
4650 lock_ObtainMutex(&dsp->mx);
4653 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4657 spacep = inp->spacep;
4658 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4659 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4661 lock_ReleaseMutex(&dsp->mx);
4662 cm_ReleaseUser(userp);
4663 smb_DeleteDirSearch(dsp);
4664 smb_ReleaseDirSearch(dsp);
4665 return CM_ERROR_NOFILES;
4667 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4668 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4670 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4671 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4674 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4677 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4678 cm_ReleaseSCache(scp);
4679 lock_ReleaseMutex(&dsp->mx);
4680 cm_ReleaseUser(userp);
4681 smb_DeleteDirSearch(dsp);
4682 smb_ReleaseDirSearch(dsp);
4683 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4684 return CM_ERROR_PATH_NOT_COVERED;
4686 return CM_ERROR_BADSHARENAME;
4688 #endif /* DFS_SUPPORT */
4691 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4692 /* we need one hold for the entry we just stored into,
4693 * and one for our own processing. When we're done with this
4694 * function, we'll drop the one for our own processing.
4695 * We held it once from the namei call, and so we do another hold
4699 lock_ObtainWrite(&scp->rw);
4700 dsp->flags |= SMB_DIRSEARCH_BULKST;
4701 lock_ReleaseWrite(&scp->rw);
4704 lock_ReleaseMutex(&dsp->mx);
4706 cm_ReleaseUser(userp);
4707 smb_DeleteDirSearch(dsp);
4708 smb_ReleaseDirSearch(dsp);
4712 /* reserves space for parameter; we'll adjust it again later to the
4713 * real count of the # of entries we returned once we've actually
4714 * assembled the directory listing.
4716 smb_SetSMBParm(outp, 0, 0);
4718 /* get the directory size */
4719 lock_ObtainWrite(&scp->rw);
4720 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4721 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4723 lock_ReleaseWrite(&scp->rw);
4724 cm_ReleaseSCache(scp);
4725 cm_ReleaseUser(userp);
4726 smb_DeleteDirSearch(dsp);
4727 smb_ReleaseDirSearch(dsp);
4731 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4733 dirLength = scp->length;
4735 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4736 curOffset.HighPart = 0;
4737 curOffset.LowPart = nextCookie;
4738 origOp = op = smb_GetSMBData(outp, NULL);
4739 /* and write out the basic header */
4740 *op++ = 5; /* variable block */
4741 op += 2; /* skip vbl block length; we'll fill it in later */
4745 clientchar_t *actualName = NULL;
4746 int free_actualName = 0;
4747 clientchar_t shortName[13];
4748 clientchar_t *shortNameEnd;
4750 /* make sure that curOffset.LowPart doesn't point to the first
4751 * 32 bytes in the 2nd through last dir page, and that it doesn't
4752 * point at the first 13 32-byte chunks in the first dir page,
4753 * since those are dir and page headers, and don't contain useful
4756 temp = curOffset.LowPart & (2048-1);
4757 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4758 /* we're in the first page */
4759 if (temp < 13*32) temp = 13*32;
4762 /* we're in a later dir page */
4763 if (temp < 32) temp = 32;
4766 /* make sure the low order 5 bits are zero */
4769 /* now put temp bits back ito curOffset.LowPart */
4770 curOffset.LowPart &= ~(2048-1);
4771 curOffset.LowPart |= temp;
4773 /* check if we've returned all the names that will fit in the
4776 if (returnedNames >= maxCount) {
4777 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4778 returnedNames, maxCount);
4782 /* check if we've passed the dir's EOF */
4783 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4785 /* see if we can use the bufferp we have now; compute in which page
4786 * the current offset would be, and check whether that's the offset
4787 * of the buffer we have. If not, get the buffer.
4789 thyper.HighPart = curOffset.HighPart;
4790 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4791 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4794 buf_Release(bufferp);
4797 lock_ReleaseWrite(&scp->rw);
4798 code = buf_Get(scp, &thyper, &bufferp);
4799 lock_ObtainMutex(&dsp->mx);
4801 /* now, if we're doing a star match, do bulk fetching of all of
4802 * the status info for files in the dir.
4805 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4807 lock_ObtainWrite(&scp->rw);
4808 lock_ReleaseMutex(&dsp->mx);
4810 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4814 bufferOffset = thyper;
4816 /* now get the data in the cache */
4818 code = cm_SyncOp(scp, bufferp, userp, &req,
4820 CM_SCACHESYNC_NEEDCALLBACK |
4821 CM_SCACHESYNC_READ);
4823 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4827 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4829 if (cm_HaveBuffer(scp, bufferp, 0)) {
4830 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4834 /* otherwise, load the buffer and try again */
4835 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4837 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4838 scp, bufferp, code);
4843 buf_Release(bufferp);
4847 } /* if (wrong buffer) ... */
4849 /* now we have the buffer containing the entry we're interested in; copy
4850 * it out if it represents a non-deleted entry.
4852 entryInDir = curOffset.LowPart & (2048-1);
4853 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4855 /* page header will help tell us which entries are free. Page header
4856 * can change more often than once per buffer, since AFS 3 dir page size
4857 * may be less than (but not more than a buffer package buffer.
4859 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4860 temp &= ~(2048 - 1); /* turn off intra-page bits */
4861 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4863 /* now determine which entry we're looking at in the page. If it is
4864 * free (there's a free bitmap at the start of the dir), we should
4865 * skip these 32 bytes.
4867 slotInPage = (entryInDir & 0x7e0) >> 5;
4868 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4869 /* this entry is free */
4870 numDirChunks = 1; /* only skip this guy */
4874 tp = bufferp->datap + entryInBuffer;
4875 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4877 /* while we're here, compute the next entry's location, too,
4878 * since we'll need it when writing out the cookie into the dir
4881 * XXXX Probably should do more sanity checking.
4883 numDirChunks = cm_NameEntries(dep->name, NULL);
4885 /* compute the offset of the cookie representing the next entry */
4886 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4888 /* Compute 8.3 name if necessary */
4889 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4890 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4893 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4894 actualName = shortName;
4895 free_actualName = 0;
4897 free_actualName = 1;
4900 if (actualName == NULL) {
4901 /* Couldn't convert the name for some reason */
4902 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4903 osi_LogSaveString(smb_logp, dep->name));
4907 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4908 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4909 osi_LogSaveClientString(smb_logp, actualName));
4911 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4912 /* this is one of the entries to use: it is not deleted
4913 * and it matches the star pattern we're looking for.
4916 /* Eliminate entries that don't match requested
4919 /* no hidden files */
4920 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4921 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4925 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4927 /* We have already done the cm_TryBulkStat above */
4928 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4929 fileType = cm_FindFileType(&fid);
4930 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4931 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4933 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4934 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4935 fileType == CM_SCACHETYPE_DFSLINK ||
4936 fileType == CM_SCACHETYPE_INVALID)
4937 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4942 memcpy(op, mask, 11); op += 11;
4943 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4944 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4945 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4946 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4947 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4948 memcpy(op, &clientCookie, 4); op += 4;
4950 /* now we emit the attribute. This is sort of tricky,
4951 * since we need to really stat the file to find out
4952 * what type of entry we've got. Right now, we're
4953 * copying out data from a buffer, while holding the
4954 * scp locked, so it isn't really convenient to stat
4955 * something now. We'll put in a place holder now,
4956 * and make a second pass before returning this to get
4957 * the real attributes. So, we just skip the data for
4958 * now, and adjust it later. We allocate a patch
4959 * record to make it easy to find this point later.
4960 * The replay will happen at a time when it is safe to
4961 * unlock the directory.
4963 curPatchp = malloc(sizeof(*curPatchp));
4964 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4965 curPatchp->dptr = op;
4966 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4968 /* do hidden attribute here since name won't be around when applying
4972 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4973 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4975 curPatchp->flags = 0;
4977 op += 9; /* skip attr, time, date and size */
4979 /* zero out name area. The spec says to pad with
4980 * spaces, but Samba doesn't, and neither do we.
4984 /* finally, we get to copy out the name; we know that
4985 * it fits in 8.3 or the pattern wouldn't match, but it
4986 * never hurts to be sure.
4988 cm_ClientStringToUtf8(actualName, -1, op, 13);
4989 if (smb_StoreAnsiFilenames)
4991 /* This is a UCHAR field, which is ASCII even if Unicode
4994 /* Uppercase if requested by client */
4995 if (!KNOWS_LONG_NAMES(inp))
5000 /* now, adjust the # of entries copied */
5002 } /* if we're including this name */
5005 if (free_actualName && actualName) {
5010 /* and adjust curOffset to be where the new cookie is */
5011 thyper.HighPart = 0;
5012 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5013 curOffset = LargeIntegerAdd(thyper, curOffset);
5014 } /* while copying data for dir listing */
5016 /* release the mutex */
5017 lock_ReleaseWrite(&scp->rw);
5019 buf_Release(bufferp);
5023 /* apply and free last set of patches; if not doing a star match, this
5024 * will be empty, but better safe (and freeing everything) than sorry.
5026 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5028 /* special return code for unsuccessful search */
5029 if (code == 0 && dataLength < 21 && returnedNames == 0)
5030 code = CM_ERROR_NOFILES;
5032 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5033 returnedNames, code);
5036 smb_DeleteDirSearch(dsp);
5037 smb_ReleaseDirSearch(dsp);
5038 cm_ReleaseSCache(scp);
5039 cm_ReleaseUser(userp);
5043 /* finalize the output buffer */
5044 smb_SetSMBParm(outp, 0, returnedNames);
5045 temp = (long) (op - origOp);
5046 smb_SetSMBDataLength(outp, temp);
5048 /* the data area is a variable block, which has a 5 (already there)
5049 * followed by the length of the # of data bytes. We now know this to
5050 * be "temp," although that includes the 3 bytes of vbl block header.
5051 * Deduct for them and fill in the length field.
5053 temp -= 3; /* deduct vbl block info */
5054 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5055 origOp[1] = (unsigned char)(temp & 0xff);
5056 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5057 if (returnedNames == 0)
5058 smb_DeleteDirSearch(dsp);
5059 smb_ReleaseDirSearch(dsp);
5060 cm_ReleaseSCache(scp);
5061 cm_ReleaseUser(userp);
5066 /* verify that this is a valid path to a directory. I don't know why they
5067 * don't use the get file attributes call.
5069 * SMB_COM_CHECK_DIRECTORY
5071 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5073 clientchar_t *pathp;
5075 cm_scache_t *rootScp;
5076 cm_scache_t *newScp;
5080 clientchar_t *tidPathp;
5086 pdata = smb_GetSMBData(inp, NULL);
5087 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5089 return CM_ERROR_BADSMB;
5090 osi_Log1(smb_logp, "SMB receive check path %S",
5091 osi_LogSaveClientString(smb_logp, pathp));
5093 rootScp = cm_data.rootSCachep;
5095 userp = smb_GetUserFromVCP(vcp, inp);
5097 caseFold = CM_FLAG_CASEFOLD;
5099 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5101 cm_ReleaseUser(userp);
5102 return CM_ERROR_NOSUCHPATH;
5104 code = cm_NameI(rootScp, pathp,
5105 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5106 userp, tidPathp, &req, &newScp);
5109 cm_ReleaseUser(userp);
5114 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5115 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5116 cm_ReleaseSCache(newScp);
5117 cm_ReleaseUser(userp);
5118 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5119 return CM_ERROR_PATH_NOT_COVERED;
5121 return CM_ERROR_BADSHARENAME;
5123 #endif /* DFS_SUPPORT */
5125 /* now lock the vnode with a callback; returns with newScp locked */
5126 lock_ObtainWrite(&newScp->rw);
5127 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5128 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5130 if (code != CM_ERROR_NOACCESS) {
5131 lock_ReleaseWrite(&newScp->rw);
5132 cm_ReleaseSCache(newScp);
5133 cm_ReleaseUser(userp);
5137 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5140 attrs = smb_Attributes(newScp);
5142 if (!(attrs & SMB_ATTR_DIRECTORY))
5143 code = CM_ERROR_NOTDIR;
5145 lock_ReleaseWrite(&newScp->rw);
5147 cm_ReleaseSCache(newScp);
5148 cm_ReleaseUser(userp);
5152 /* SMB_COM_SET_INFORMATION */
5153 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5155 clientchar_t *pathp;
5157 cm_scache_t *rootScp;
5158 unsigned short attribute;
5160 cm_scache_t *newScp;
5164 clientchar_t *tidPathp;
5170 /* decode basic attributes we're passed */
5171 attribute = smb_GetSMBParm(inp, 0);
5172 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5174 datap = smb_GetSMBData(inp, NULL);
5175 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5177 return CM_ERROR_BADSMB;
5179 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5180 dosTime, attribute);
5182 rootScp = cm_data.rootSCachep;
5184 userp = smb_GetUserFromVCP(vcp, inp);
5186 caseFold = CM_FLAG_CASEFOLD;
5188 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5190 cm_ReleaseUser(userp);
5191 return CM_ERROR_NOSUCHFILE;
5193 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5194 tidPathp, &req, &newScp);
5197 cm_ReleaseUser(userp);
5202 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5203 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5204 cm_ReleaseSCache(newScp);
5205 cm_ReleaseUser(userp);
5206 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5207 return CM_ERROR_PATH_NOT_COVERED;
5209 return CM_ERROR_BADSHARENAME;
5211 #endif /* DFS_SUPPORT */
5213 /* now lock the vnode with a callback; returns with newScp locked; we
5214 * need the current status to determine what the new status is, in some
5217 lock_ObtainWrite(&newScp->rw);
5218 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5219 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5221 lock_ReleaseWrite(&newScp->rw);
5222 cm_ReleaseSCache(newScp);
5223 cm_ReleaseUser(userp);
5227 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5229 /* Check for RO volume */
5230 if (newScp->flags & CM_SCACHEFLAG_RO) {
5231 lock_ReleaseWrite(&newScp->rw);
5232 cm_ReleaseSCache(newScp);
5233 cm_ReleaseUser(userp);
5234 return CM_ERROR_READONLY;
5237 /* prepare for setattr call */
5240 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5241 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5243 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5244 /* we're told to make a writable file read-only */
5245 attr.unixModeBits = newScp->unixModeBits & ~0222;
5246 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5248 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5249 /* we're told to make a read-only file writable */
5250 attr.unixModeBits = newScp->unixModeBits | 0222;
5251 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5253 lock_ReleaseWrite(&newScp->rw);
5255 /* now call setattr */
5257 code = cm_SetAttr(newScp, &attr, userp, &req);
5261 cm_ReleaseSCache(newScp);
5262 cm_ReleaseUser(userp);
5268 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5270 clientchar_t *pathp;
5272 cm_scache_t *rootScp;
5273 cm_scache_t *newScp, *dscp;
5278 clientchar_t *tidPathp;
5280 clientchar_t *lastComp;
5286 datap = smb_GetSMBData(inp, NULL);
5287 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5289 return CM_ERROR_BADSMB;
5291 if (*pathp == 0) /* null path */
5294 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5295 osi_LogSaveClientString(smb_logp, pathp));
5297 rootScp = cm_data.rootSCachep;
5299 userp = smb_GetUserFromVCP(vcp, inp);
5301 /* we shouldn't need this for V3 requests, but we seem to */
5302 caseFold = CM_FLAG_CASEFOLD;
5304 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5306 cm_ReleaseUser(userp);
5307 return CM_ERROR_NOSUCHFILE;
5311 * XXX Strange hack XXX
5313 * As of Patch 5 (16 July 97), we are having the following problem:
5314 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5315 * requests to look up "desktop.ini" in all the subdirectories.
5316 * This can cause zillions of timeouts looking up non-existent cells
5317 * and volumes, especially in the top-level directory.
5319 * We have not found any way to avoid this or work around it except
5320 * to explicitly ignore the requests for mount points that haven't
5321 * yet been evaluated and for directories that haven't yet been
5324 * We should modify this hack to provide a fake desktop.ini file
5325 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5327 spacep = inp->spacep;
5328 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5329 #ifndef SPECIAL_FOLDERS
5330 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5331 code = cm_NameI(rootScp, spacep->wdata,
5332 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5333 userp, tidPathp, &req, &dscp);
5336 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5337 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5339 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5340 return CM_ERROR_PATH_NOT_COVERED;
5342 return CM_ERROR_BADSHARENAME;
5344 #endif /* DFS_SUPPORT */
5345 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5346 code = CM_ERROR_NOSUCHFILE;
5347 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5348 cm_buf_t *bp = buf_Find(dscp, &hzero);
5353 code = CM_ERROR_NOSUCHFILE;
5355 cm_ReleaseSCache(dscp);
5357 cm_ReleaseUser(userp);
5362 #endif /* SPECIAL_FOLDERS */
5364 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5365 tidPathp, &req, &newScp);
5367 cm_ReleaseUser(userp);
5372 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5373 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5374 cm_ReleaseSCache(newScp);
5375 cm_ReleaseUser(userp);
5376 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5377 return CM_ERROR_PATH_NOT_COVERED;
5379 return CM_ERROR_BADSHARENAME;
5381 #endif /* DFS_SUPPORT */
5383 /* now lock the vnode with a callback; returns with newScp locked */
5384 lock_ObtainWrite(&newScp->rw);
5385 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5386 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5388 lock_ReleaseWrite(&newScp->rw);
5389 cm_ReleaseSCache(newScp);
5390 cm_ReleaseUser(userp);
5394 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5396 attrs = smb_Attributes(newScp);
5398 smb_SetSMBParm(outp, 0, attrs);
5400 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5401 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5402 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5403 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5404 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5405 smb_SetSMBParm(outp, 5, 0);
5406 smb_SetSMBParm(outp, 6, 0);
5407 smb_SetSMBParm(outp, 7, 0);
5408 smb_SetSMBParm(outp, 8, 0);
5409 smb_SetSMBParm(outp, 9, 0);
5410 smb_SetSMBDataLength(outp, 0);
5411 lock_ReleaseWrite(&newScp->rw);
5413 cm_ReleaseSCache(newScp);
5414 cm_ReleaseUser(userp);
5419 /* SMB_COM_TREE_DISCONNECT */
5420 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5424 osi_Log0(smb_logp, "SMB receive tree disconnect");
5426 /* find the tree and free it */
5427 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5429 lock_ObtainWrite(&smb_rctLock);
5431 smb_ReleaseTID(tidp, TRUE);
5432 lock_ReleaseWrite(&smb_rctLock);
5439 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5442 clientchar_t *pathp;
5443 clientchar_t *lastNamep;
5452 clientchar_t *tidPathp;
5458 datap = smb_GetSMBData(inp, NULL);
5459 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5461 return CM_ERROR_BADSMB;
5463 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5465 #ifdef DEBUG_VERBOSE
5469 hexpath = osi_HexifyString( pathp );
5470 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5475 if (!cm_IsValidClientString(pathp)) {
5477 clientchar_t * hexp;
5479 hexp = cm_GetRawCharsAlloc(pathp, -1);
5480 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5481 osi_LogSaveClientString(smb_logp, hexp));
5485 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5487 return CM_ERROR_BADNTFILENAME;
5490 share = smb_GetSMBParm(inp, 0);
5491 attribute = smb_GetSMBParm(inp, 1);
5493 spacep = inp->spacep;
5494 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5495 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5496 /* special case magic file name for receiving IOCTL requests
5497 * (since IOCTL calls themselves aren't getting through).
5499 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5500 smb_SetupIoctlFid(fidp, spacep);
5501 smb_SetSMBParm(outp, 0, fidp->fid);
5502 smb_SetSMBParm(outp, 1, 0); /* attrs */
5503 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5504 smb_SetSMBParm(outp, 3, 0);
5505 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5506 smb_SetSMBParm(outp, 5, 0x7fff);
5507 /* pass the open mode back */
5508 smb_SetSMBParm(outp, 6, (share & 0xf));
5509 smb_SetSMBDataLength(outp, 0);
5510 smb_ReleaseFID(fidp);
5514 userp = smb_GetUserFromVCP(vcp, inp);
5516 caseFold = CM_FLAG_CASEFOLD;
5518 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5520 cm_ReleaseUser(userp);
5521 return CM_ERROR_NOSUCHPATH;
5523 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5524 tidPathp, &req, &scp);
5527 cm_ReleaseUser(userp);
5532 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5533 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5534 cm_ReleaseSCache(scp);
5535 cm_ReleaseUser(userp);
5536 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5537 return CM_ERROR_PATH_NOT_COVERED;
5539 return CM_ERROR_BADSHARENAME;
5541 #endif /* DFS_SUPPORT */
5543 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5545 cm_ReleaseSCache(scp);
5546 cm_ReleaseUser(userp);
5550 /* don't need callback to check file type, since file types never
5551 * change, and namei and cm_Lookup all stat the object at least once on
5552 * a successful return.
5554 if (scp->fileType != CM_SCACHETYPE_FILE) {
5555 cm_ReleaseSCache(scp);
5556 cm_ReleaseUser(userp);
5557 return CM_ERROR_ISDIR;
5560 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5561 osi_assertx(fidp, "null smb_fid_t");
5563 lock_ObtainMutex(&fidp->mx);
5564 if ((share & 0xf) == 0)
5565 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5566 else if ((share & 0xf) == 1)
5567 fidp->flags |= SMB_FID_OPENWRITE;
5569 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5573 fidp->userp = userp;
5575 /* and a pointer to the vnode */
5577 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5578 lock_ObtainWrite(&scp->rw);
5579 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5581 smb_SetSMBParm(outp, 0, fidp->fid);
5582 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5583 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5584 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5585 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5586 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5587 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5588 /* pass the open mode back; XXXX add access checks */
5589 smb_SetSMBParm(outp, 6, (share & 0xf));
5590 smb_SetSMBDataLength(outp, 0);
5591 lock_ReleaseMutex(&fidp->mx);
5592 lock_ReleaseRead(&scp->rw);
5595 cm_Open(scp, 0, userp);
5597 /* send and free packet */
5598 smb_ReleaseFID(fidp);
5599 cm_ReleaseUser(userp);
5600 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5604 typedef struct smb_unlinkRock {
5609 clientchar_t *maskp; /* pointer to the star pattern */
5612 cm_dirEntryList_t * matches;
5615 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5618 smb_unlinkRock_t *rockp;
5621 normchar_t matchName[MAX_PATH];
5625 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5626 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5627 caseFold |= CM_FLAG_8DOT3;
5629 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5630 /* Can't convert name */
5631 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5632 osi_LogSaveString(smb_logp, dep->name));
5636 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5638 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5639 !cm_Is8Dot3(matchName)) {
5640 cm_Gen8Dot3Name(dep, matchName, NULL);
5641 /* 8.3 matches are always case insensitive */
5642 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5645 osi_Log1(smb_logp, "Found match %S",
5646 osi_LogSaveClientString(smb_logp, matchName));
5648 cm_DirEntryListAdd(dep->name, &rockp->matches);
5652 /* If we made a case sensitive exact match, we might as well quit now. */
5653 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5654 code = CM_ERROR_STOPNOW;
5663 /* SMB_COM_DELETE */
5664 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5668 clientchar_t *pathp;
5672 clientchar_t *lastNamep;
5673 smb_unlinkRock_t rock;
5677 clientchar_t *tidPathp;
5681 memset(&rock, 0, sizeof(rock));
5683 attribute = smb_GetSMBParm(inp, 0);
5685 tp = smb_GetSMBData(inp, NULL);
5686 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5688 return CM_ERROR_BADSMB;
5690 osi_Log1(smb_logp, "SMB receive unlink %S",
5691 osi_LogSaveClientString(smb_logp, pathp));
5693 spacep = inp->spacep;
5694 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5696 userp = smb_GetUserFromVCP(vcp, inp);
5698 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5700 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5702 cm_ReleaseUser(userp);
5703 return CM_ERROR_NOSUCHPATH;
5705 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5708 cm_ReleaseUser(userp);
5713 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5714 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5715 cm_ReleaseSCache(dscp);
5716 cm_ReleaseUser(userp);
5717 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5718 return CM_ERROR_PATH_NOT_COVERED;
5720 return CM_ERROR_BADSHARENAME;
5722 #endif /* DFS_SUPPORT */
5724 /* otherwise, scp points to the parent directory. */
5731 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5733 code = CM_ERROR_NOSUCHFILE;
5736 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5739 thyper.HighPart = 0;
5744 rock.matches = NULL;
5746 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5747 * match. If that fails, we do a case insensitve match.
5749 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5750 !smb_IsStarMask(rock.maskp)) {
5751 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5754 thyper.HighPart = 0;
5755 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5760 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5762 if (code == CM_ERROR_STOPNOW)
5765 if (code == 0 && rock.matches) {
5766 cm_dirEntryList_t * entry;
5768 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5769 normchar_t normalizedName[MAX_PATH];
5771 /* Note: entry->name is a non-normalized name */
5773 osi_Log1(smb_logp, "Unlinking %s",
5774 osi_LogSaveString(smb_logp, entry->name));
5776 /* We assume this works because entry->name was
5777 successfully converted in smb_UnlinkProc() once. */
5778 cm_FsStringToNormString(entry->name, -1,
5779 normalizedName, lengthof(normalizedName));
5781 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5783 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5784 smb_NotifyChange(FILE_ACTION_REMOVED,
5785 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5786 dscp, normalizedName, NULL, TRUE);
5790 cm_DirEntryListFree(&rock.matches);
5794 cm_ReleaseUser(userp);
5797 cm_ReleaseSCache(dscp);
5802 if (code == 0 && !rock.any)
5803 code = CM_ERROR_NOSUCHFILE;
5807 typedef struct smb_renameRock {
5808 cm_scache_t *odscp; /* old dir */
5809 cm_scache_t *ndscp; /* new dir */
5810 cm_user_t *userp; /* user */
5811 cm_req_t *reqp; /* request struct */
5812 smb_vc_t *vcp; /* virtual circuit */
5813 normchar_t *maskp; /* pointer to star pattern of old file name */
5814 int flags; /* tilde, casefold, etc */
5815 clientchar_t *newNamep; /* ptr to the new file's name */
5816 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5817 clientchar_t clOldName[MAX_PATH]; /* client name */
5821 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5824 smb_renameRock_t *rockp;
5827 normchar_t matchName[MAX_PATH];
5829 rockp = (smb_renameRock_t *) vrockp;
5831 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5832 /* Can't convert string */
5833 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5834 osi_LogSaveString(smb_logp, dep->name));
5838 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5839 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5840 caseFold |= CM_FLAG_8DOT3;
5842 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5844 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5845 !cm_Is8Dot3(matchName)) {
5846 cm_Gen8Dot3Name(dep, matchName, NULL);
5847 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5852 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5853 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5855 code = CM_ERROR_STOPNOW;
5865 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5868 cm_space_t *spacep = NULL;
5869 smb_renameRock_t rock;
5870 cm_scache_t *oldDscp = NULL;
5871 cm_scache_t *newDscp = NULL;
5872 cm_scache_t *tmpscp= NULL;
5873 cm_scache_t *tmpscp2 = NULL;
5874 clientchar_t *oldLastNamep;
5875 clientchar_t *newLastNamep;
5879 clientchar_t *tidPathp;
5883 userp = smb_GetUserFromVCP(vcp, inp);
5884 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5886 cm_ReleaseUser(userp);
5887 return CM_ERROR_NOSUCHPATH;
5891 memset(&rock, 0, sizeof(rock));
5893 spacep = inp->spacep;
5894 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5896 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5897 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5898 userp, tidPathp, &req, &oldDscp);
5900 cm_ReleaseUser(userp);
5905 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5906 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5907 cm_ReleaseSCache(oldDscp);
5908 cm_ReleaseUser(userp);
5909 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5910 return CM_ERROR_PATH_NOT_COVERED;
5912 return CM_ERROR_BADSHARENAME;
5914 #endif /* DFS_SUPPORT */
5916 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5917 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5918 userp, tidPathp, &req, &newDscp);
5921 cm_ReleaseSCache(oldDscp);
5922 cm_ReleaseUser(userp);
5927 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5928 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5929 cm_ReleaseSCache(oldDscp);
5930 cm_ReleaseSCache(newDscp);
5931 cm_ReleaseUser(userp);
5932 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5933 return CM_ERROR_PATH_NOT_COVERED;
5935 return CM_ERROR_BADSHARENAME;
5937 #endif /* DFS_SUPPORT */
5940 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5941 * next, get the component names, and lower case them.
5944 /* handle the old name first */
5946 oldLastNamep = oldPathp;
5950 /* and handle the new name, too */
5952 newLastNamep = newPathp;
5956 /* TODO: The old name could be a wildcard. The new name must not be */
5958 /* Check if the file already exists; if so return error */
5959 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5960 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5961 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5963 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5964 osi_LogSaveClientString(smb_logp, newLastNamep));
5966 /* Check if the old and the new names differ only in case. If so return
5967 * success, else return CM_ERROR_EXISTS
5969 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5971 /* This would be a success only if the old file is *as same as* the new file */
5972 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5974 if (tmpscp == tmpscp2)
5977 code = CM_ERROR_EXISTS;
5978 cm_ReleaseSCache(tmpscp2);
5981 code = CM_ERROR_NOSUCHFILE;
5984 /* file exist, do not rename, also fixes move */
5985 osi_Log0(smb_logp, "Can't rename. Target already exists");
5986 code = CM_ERROR_EXISTS;
5991 /* do the vnode call */
5992 rock.odscp = oldDscp;
5993 rock.ndscp = newDscp;
5997 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5999 code = CM_ERROR_NOSUCHFILE;
6002 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6003 rock.newNamep = newLastNamep;
6004 rock.fsOldName[0] = '\0';
6005 rock.clOldName[0] = '\0';
6008 /* Now search the directory for the pattern, and do the appropriate rename when found */
6009 thyper.LowPart = 0; /* search dir from here */
6010 thyper.HighPart = 0;
6012 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6013 if (code == 0 && !rock.any) {
6015 thyper.HighPart = 0;
6016 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6017 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6019 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6021 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6022 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6023 rock.ndscp, rock.newNamep, rock.userp,
6025 /* if the call worked, stop doing the search now, since we
6026 * really only want to rename one file.
6029 osi_Log0(smb_logp, "cm_Rename failure");
6030 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6031 } else if (code == 0) {
6032 code = CM_ERROR_NOSUCHFILE;
6035 /* Handle Change Notification */
6037 * Being lazy, not distinguishing between files and dirs in this
6038 * filter, since we'd have to do a lookup.
6041 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6042 if (oldDscp == newDscp) {
6043 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6044 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6045 filter, oldDscp, rock.clOldName,
6046 newLastNamep, TRUE);
6048 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6049 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6050 filter, oldDscp, rock.clOldName,
6052 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6053 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6054 filter, newDscp, newLastNamep,
6061 cm_ReleaseSCache(tmpscp);
6063 cm_ReleaseUser(userp);
6065 cm_ReleaseSCache(oldDscp);
6067 cm_ReleaseSCache(newDscp);
6075 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6078 cm_space_t *spacep = NULL;
6079 cm_scache_t *oldDscp = NULL;
6080 cm_scache_t *newDscp = NULL;
6081 cm_scache_t *tmpscp= NULL;
6082 cm_scache_t *tmpscp2 = NULL;
6083 cm_scache_t *sscp = NULL;
6084 clientchar_t *oldLastNamep;
6085 clientchar_t *newLastNamep;
6088 clientchar_t *tidPathp;
6092 userp = smb_GetUserFromVCP(vcp, inp);
6094 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6096 cm_ReleaseUser(userp);
6097 return CM_ERROR_NOSUCHPATH;
6102 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6104 spacep = inp->spacep;
6105 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6107 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6108 userp, tidPathp, &req, &oldDscp);
6110 cm_ReleaseUser(userp);
6115 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6116 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6117 cm_ReleaseSCache(oldDscp);
6118 cm_ReleaseUser(userp);
6119 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6120 return CM_ERROR_PATH_NOT_COVERED;
6122 return CM_ERROR_BADSHARENAME;
6124 #endif /* DFS_SUPPORT */
6126 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6127 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6128 userp, tidPathp, &req, &newDscp);
6130 cm_ReleaseSCache(oldDscp);
6131 cm_ReleaseUser(userp);
6136 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6137 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6138 cm_ReleaseSCache(newDscp);
6139 cm_ReleaseSCache(oldDscp);
6140 cm_ReleaseUser(userp);
6141 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6142 return CM_ERROR_PATH_NOT_COVERED;
6144 return CM_ERROR_BADSHARENAME;
6146 #endif /* DFS_SUPPORT */
6148 /* Now, although we did two lookups for the two directories (because the same
6149 * directory can be referenced through different paths), we only allow hard links
6150 * within the same directory. */
6151 if (oldDscp != newDscp) {
6152 cm_ReleaseSCache(oldDscp);
6153 cm_ReleaseSCache(newDscp);
6154 cm_ReleaseUser(userp);
6155 return CM_ERROR_CROSSDEVLINK;
6158 /* handle the old name first */
6160 oldLastNamep = oldPathp;
6164 /* and handle the new name, too */
6166 newLastNamep = newPathp;
6170 /* now lookup the old name */
6171 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6172 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6174 cm_ReleaseSCache(oldDscp);
6175 cm_ReleaseSCache(newDscp);
6176 cm_ReleaseUser(userp);
6180 /* Check if the file already exists; if so return error */
6181 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6182 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6183 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6185 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6186 osi_LogSaveClientString(smb_logp, newLastNamep));
6188 /* if the existing link is to the same file, then we return success */
6190 if(sscp == tmpscp) {
6193 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6194 code = CM_ERROR_EXISTS;
6199 cm_ReleaseSCache(tmpscp);
6200 cm_ReleaseSCache(sscp);
6201 cm_ReleaseSCache(newDscp);
6202 cm_ReleaseSCache(oldDscp);
6203 cm_ReleaseUser(userp);
6207 /* now create the hardlink */
6208 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6209 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6210 osi_Log1(smb_logp," Link returns 0x%x", code);
6212 /* Handle Change Notification */
6214 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6215 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6216 smb_NotifyChange(FILE_ACTION_ADDED,
6217 filter, newDscp, newLastNamep,
6222 cm_ReleaseSCache(tmpscp);
6223 cm_ReleaseUser(userp);
6224 cm_ReleaseSCache(sscp);
6225 cm_ReleaseSCache(oldDscp);
6226 cm_ReleaseSCache(newDscp);
6230 /* SMB_COM_RENAME */
6232 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6234 clientchar_t *oldPathp;
6235 clientchar_t *newPathp;
6239 tp = smb_GetSMBData(inp, NULL);
6240 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6242 return CM_ERROR_BADSMB;
6243 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6245 return CM_ERROR_BADSMB;
6247 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6248 osi_LogSaveClientString(smb_logp, oldPathp),
6249 osi_LogSaveClientString(smb_logp, newPathp));
6251 if (!cm_IsValidClientString(newPathp)) {
6253 clientchar_t * hexp;
6255 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6256 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6257 osi_LogSaveClientString(smb_logp, hexp));
6261 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6263 return CM_ERROR_BADNTFILENAME;
6266 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6268 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6274 typedef struct smb_rmdirRock {
6278 normchar_t *maskp; /* pointer to the star pattern */
6281 cm_dirEntryList_t * matches;
6284 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6287 smb_rmdirRock_t *rockp;
6289 normchar_t matchName[MAX_PATH];
6291 rockp = (smb_rmdirRock_t *) vrockp;
6293 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6294 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6295 osi_LogSaveString(smb_logp, dep->name));
6299 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6300 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6302 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6304 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6305 !cm_Is8Dot3(matchName)) {
6306 cm_Gen8Dot3Name(dep, matchName, NULL);
6307 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6312 cm_DirEntryListAdd(dep->name, &rockp->matches);
6319 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6322 clientchar_t *pathp;
6326 clientchar_t *lastNamep;
6327 smb_rmdirRock_t rock;
6331 clientchar_t *tidPathp;
6335 memset(&rock, 0, sizeof(rock));
6337 tp = smb_GetSMBData(inp, NULL);
6338 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6340 return CM_ERROR_BADSMB;
6342 spacep = inp->spacep;
6343 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6345 userp = smb_GetUserFromVCP(vcp, inp);
6347 caseFold = CM_FLAG_CASEFOLD;
6349 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6351 cm_ReleaseUser(userp);
6352 return CM_ERROR_NOSUCHPATH;
6354 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6355 userp, tidPathp, &req, &dscp);
6358 cm_ReleaseUser(userp);
6363 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6364 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6365 cm_ReleaseSCache(dscp);
6366 cm_ReleaseUser(userp);
6367 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6368 return CM_ERROR_PATH_NOT_COVERED;
6370 return CM_ERROR_BADSHARENAME;
6372 #endif /* DFS_SUPPORT */
6374 /* otherwise, scp points to the parent directory. */
6381 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6383 code = CM_ERROR_NOSUCHFILE;
6386 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6389 thyper.HighPart = 0;
6393 rock.matches = NULL;
6395 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6396 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6397 if (code == 0 && !rock.any) {
6399 thyper.HighPart = 0;
6400 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6401 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6404 if (code == 0 && rock.matches) {
6405 cm_dirEntryList_t * entry;
6407 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6408 clientchar_t clientName[MAX_PATH];
6410 /* We assume this will succeed because smb_RmdirProc()
6411 successfully converted entry->name once above. */
6412 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6414 osi_Log1(smb_logp, "Removing directory %s",
6415 osi_LogSaveString(smb_logp, entry->name));
6417 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6419 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6420 smb_NotifyChange(FILE_ACTION_REMOVED,
6421 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6422 dscp, clientName, NULL, TRUE);
6428 cm_DirEntryListFree(&rock.matches);
6431 cm_ReleaseUser(userp);
6434 cm_ReleaseSCache(dscp);
6436 if (code == 0 && !rock.any)
6437 code = CM_ERROR_NOSUCHFILE;
6446 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6456 fid = smb_GetSMBParm(inp, 0);
6458 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6460 fid = smb_ChainFID(fid, inp);
6461 fidp = smb_FindFID(vcp, fid, 0);
6463 return CM_ERROR_BADFD;
6465 userp = smb_GetUserFromVCP(vcp, inp);
6467 lock_ObtainMutex(&fidp->mx);
6468 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6469 lock_ReleaseMutex(&fidp->mx);
6470 cm_ReleaseUser(userp);
6471 smb_CloseFID(vcp, fidp, NULL, 0);
6472 smb_ReleaseFID(fidp);
6473 return CM_ERROR_NOSUCHFILE;
6476 if (fidp->flags & SMB_FID_IOCTL) {
6477 cm_ReleaseUser(userp);
6478 lock_ReleaseMutex(&fidp->mx);
6479 smb_ReleaseFID(fidp);
6480 return CM_ERROR_BADFD;
6483 if (fidp->scp && (fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6484 cm_scache_t * scp = fidp->scp;
6486 lock_ReleaseMutex(&fidp->mx);
6487 code = cm_FSync(scp, userp, &req);
6488 cm_ReleaseSCache(scp);
6490 lock_ReleaseMutex(&fidp->mx);
6494 cm_ReleaseUser(userp);
6495 smb_ReleaseFID(fidp);
6499 struct smb_FullNameRock {
6502 clientchar_t *fullName;
6503 fschar_t *originalName;
6506 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6509 normchar_t matchName[MAX_PATH];
6510 struct smb_FullNameRock *vrockp;
6512 vrockp = (struct smb_FullNameRock *)rockp;
6514 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6515 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6516 osi_LogSaveString(smb_logp, dep->name));
6520 if (!cm_Is8Dot3(matchName)) {
6521 clientchar_t shortName[13];
6523 cm_Gen8Dot3Name(dep, shortName, NULL);
6525 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6526 vrockp->fullName = cm_ClientStrDup(matchName);
6527 vrockp->originalName = cm_FsStrDup(dep->name);
6528 return CM_ERROR_STOPNOW;
6531 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6532 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6533 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6534 vrockp->fullName = cm_ClientStrDup(matchName);
6535 vrockp->originalName = cm_FsStrDup(dep->name);
6536 return CM_ERROR_STOPNOW;
6541 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6542 clientchar_t **newPathp, fschar_t ** originalPathp,
6543 cm_user_t *userp, cm_req_t *reqp)
6545 struct smb_FullNameRock rock;
6548 memset(&rock, 0, sizeof(rock));
6552 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6553 if (code == CM_ERROR_STOPNOW) {
6554 *newPathp = rock.fullName;
6555 *originalPathp = rock.originalName;
6557 *newPathp = cm_ClientStrDup(pathp);
6558 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6562 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6563 afs_uint32 dosTime) {
6566 cm_scache_t *dscp = NULL;
6567 clientchar_t *pathp = NULL;
6568 cm_scache_t * scp = NULL;
6569 cm_scache_t *delscp = NULL;
6570 int nullcreator = 0;
6572 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6573 fidp, fidp->fid, scp, vcp);
6576 lock_ObtainMutex(&fidp->mx);
6577 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6578 lock_ReleaseMutex(&fidp->mx);
6579 osi_Log0(smb_logp, " No user specified. Not closing fid");
6580 return CM_ERROR_BADFD;
6583 userp = fidp->userp; /* no hold required since fidp is held
6584 throughout the function */
6585 lock_ReleaseMutex(&fidp->mx);
6590 lock_ObtainWrite(&smb_rctLock);
6591 if (fidp->deleteOk) {
6592 osi_Log0(smb_logp, " Fid already closed.");
6593 lock_ReleaseWrite(&smb_rctLock);
6594 return CM_ERROR_BADFD;
6597 lock_ReleaseWrite(&smb_rctLock);
6599 lock_ObtainMutex(&fidp->mx);
6600 if (fidp->NTopen_dscp) {
6601 dscp = fidp->NTopen_dscp;
6602 cm_HoldSCache(dscp);
6605 if (fidp->NTopen_pathp)
6606 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6613 /* Don't jump the gun on an async raw write */
6614 while (fidp->raw_writers) {
6615 lock_ReleaseMutex(&fidp->mx);
6616 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6617 lock_ObtainMutex(&fidp->mx);
6620 /* watch for ioctl closes, and read-only opens */
6622 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6623 == SMB_FID_OPENWRITE) {
6624 if (dosTime != 0 && dosTime != -1) {
6625 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6626 /* This fixes defect 10958 */
6627 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6628 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6630 if (smb_AsyncStore != 2) {
6631 lock_ReleaseMutex(&fidp->mx);
6632 code = cm_FSync(scp, userp, &req);
6633 lock_ObtainMutex(&fidp->mx);
6639 /* unlock any pending locks */
6640 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6641 scp->fileType == CM_SCACHETYPE_FILE) {
6645 lock_ReleaseMutex(&fidp->mx);
6647 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6649 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6650 lock_ObtainWrite(&scp->rw);
6652 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6653 CM_SCACHESYNC_NEEDCALLBACK
6654 | CM_SCACHESYNC_GETSTATUS
6655 | CM_SCACHESYNC_LOCK);
6659 "smb CoreClose SyncOp failure code 0x%x", tcode);
6660 goto post_syncopdone;
6663 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6665 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6669 lock_ReleaseWrite(&scp->rw);
6670 lock_ObtainMutex(&fidp->mx);
6673 if (fidp->flags & SMB_FID_DELONCLOSE) {
6674 clientchar_t *fullPathp = NULL;
6675 fschar_t *originalNamep = NULL;
6677 lock_ReleaseMutex(&fidp->mx);
6679 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6684 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6685 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6686 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6688 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6689 smb_NotifyChange(FILE_ACTION_REMOVED,
6690 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6691 dscp, fullPathp, NULL, TRUE);
6694 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6696 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6697 smb_NotifyChange(FILE_ACTION_REMOVED,
6698 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6699 dscp, fullPathp, NULL, TRUE);
6706 free(originalNamep);
6708 lock_ObtainMutex(&fidp->mx);
6709 fidp->flags &= ~SMB_FID_DELONCLOSE;
6712 /* if this was a newly created file, then clear the creator
6713 * in the stat cache entry. */
6714 if (fidp->flags & SMB_FID_CREATED) {
6716 fidp->flags &= ~SMB_FID_CREATED;
6719 if (fidp->flags & SMB_FID_NTOPEN) {
6720 cm_ReleaseSCache(fidp->NTopen_dscp);
6721 fidp->NTopen_dscp = NULL;
6722 free(fidp->NTopen_pathp);
6723 fidp->NTopen_pathp = NULL;
6724 fidp->flags &= ~SMB_FID_NTOPEN;
6726 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6727 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6730 if (fidp->NTopen_wholepathp) {
6731 free(fidp->NTopen_wholepathp);
6732 fidp->NTopen_wholepathp = NULL;
6736 cm_ReleaseSCache(fidp->scp);
6739 lock_ReleaseMutex(&fidp->mx);
6742 cm_ReleaseSCache(dscp);
6745 cm_ReleaseSCache(delscp);
6749 lock_ObtainWrite(&scp->rw);
6750 if (nullcreator && scp->creator == userp)
6751 scp->creator = NULL;
6752 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6753 lock_ReleaseWrite(&scp->rw);
6754 cm_ReleaseSCache(scp);
6764 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6772 fid = smb_GetSMBParm(inp, 0);
6773 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6775 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6777 fid = smb_ChainFID(fid, inp);
6778 fidp = smb_FindFID(vcp, fid, 0);
6780 return CM_ERROR_BADFD;
6783 userp = smb_GetUserFromVCP(vcp, inp);
6785 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6787 smb_ReleaseFID(fidp);
6788 cm_ReleaseUser(userp);
6793 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6795 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6796 cm_user_t *userp, long *readp)
6802 osi_hyper_t fileLength;
6804 osi_hyper_t lastByte;
6805 osi_hyper_t bufferOffset;
6809 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6812 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6813 fidp->fid, offsetp->LowPart, count);
6817 lock_ObtainMutex(&fidp->mx);
6818 /* make sure we have a readable FD */
6819 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6820 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6821 fidp->fid, fidp->flags);
6822 lock_ReleaseMutex(&fidp->mx);
6823 code = CM_ERROR_BADFDOP;
6828 lock_ReleaseMutex(&fidp->mx);
6829 code = CM_ERROR_BADFD;
6840 lock_ObtainWrite(&scp->rw);
6842 if (offset.HighPart == 0) {
6843 chunk = offset.LowPart >> cm_logChunkSize;
6844 if (chunk != fidp->curr_chunk) {
6845 fidp->prev_chunk = fidp->curr_chunk;
6846 fidp->curr_chunk = chunk;
6848 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6851 lock_ReleaseMutex(&fidp->mx);
6853 /* start by looking up the file's end */
6854 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6855 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6859 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6861 /* now we have the entry locked, look up the length */
6862 fileLength = scp->length;
6864 /* adjust count down so that it won't go past EOF */
6865 thyper.LowPart = count;
6866 thyper.HighPart = 0;
6867 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6869 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6870 /* we'd read past EOF, so just stop at fileLength bytes.
6871 * Start by computing how many bytes remain in the file.
6873 thyper = LargeIntegerSubtract(fileLength, offset);
6875 /* if we are past EOF, read 0 bytes */
6876 if (LargeIntegerLessThanZero(thyper))
6879 count = thyper.LowPart;
6884 /* now, copy the data one buffer at a time,
6885 * until we've filled the request packet
6888 /* if we've copied all the data requested, we're done */
6889 if (count <= 0) break;
6891 /* otherwise, load up a buffer of data */
6892 thyper.HighPart = offset.HighPart;
6893 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6894 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6897 buf_Release(bufferp);
6900 lock_ReleaseWrite(&scp->rw);
6902 code = buf_Get(scp, &thyper, &bufferp);
6904 lock_ObtainWrite(&scp->rw);
6905 if (code) goto done;
6906 bufferOffset = thyper;
6908 /* now get the data in the cache */
6910 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6911 CM_SCACHESYNC_NEEDCALLBACK |
6912 CM_SCACHESYNC_READ);
6916 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6918 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6920 /* otherwise, load the buffer and try again */
6921 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6925 buf_Release(bufferp);
6929 } /* if (wrong buffer) ... */
6931 /* now we have the right buffer loaded. Copy out the
6932 * data from here to the user's buffer.
6934 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6936 /* and figure out how many bytes we want from this buffer */
6937 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6938 if (nbytes > count) nbytes = count; /* don't go past EOF */
6940 /* now copy the data */
6941 memcpy(op, bufferp->datap + bufIndex, nbytes);
6943 /* adjust counters, pointers, etc. */
6946 thyper.LowPart = nbytes;
6947 thyper.HighPart = 0;
6948 offset = LargeIntegerAdd(thyper, offset);
6952 lock_ReleaseWrite(&scp->rw);
6954 buf_Release(bufferp);
6956 if (code == 0 && sequential)
6957 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6959 cm_ReleaseSCache(scp);
6962 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6963 fidp->fid, code, *readp);
6968 * smb_WriteData -- common code for Write and Raw Write
6970 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6971 cm_user_t *userp, long *writtenp)
6973 osi_hyper_t offset = *offsetp;
6976 cm_scache_t *scp = NULL;
6977 osi_hyper_t fileLength; /* file's length at start of write */
6978 osi_hyper_t minLength; /* don't read past this */
6979 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6980 cm_buf_t *bufferp = NULL;
6981 osi_hyper_t thyper; /* hyper tmp variable */
6982 osi_hyper_t bufferOffset;
6983 afs_uint32 bufIndex; /* index in buffer where our data is */
6984 int doWriteBack = 0;
6985 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6989 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6990 fidp->fid, offsetp->LowPart, count);
6994 lock_ObtainMutex(&fidp->mx);
6995 /* make sure we have a writable FD */
6996 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6997 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6998 fidp->fid, fidp->flags);
6999 lock_ReleaseMutex(&fidp->mx);
7000 code = CM_ERROR_BADFDOP;
7008 lock_ReleaseMutex(&fidp->mx);
7010 lock_ObtainWrite(&scp->rw);
7011 /* start by looking up the file's end */
7012 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7013 CM_SCACHESYNC_NEEDCALLBACK
7014 | CM_SCACHESYNC_SETSTATUS
7015 | CM_SCACHESYNC_GETSTATUS);
7019 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7021 /* now we have the entry locked, look up the length */
7022 fileLength = scp->length;
7023 minLength = fileLength;
7024 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7025 minLength = scp->serverLength;
7027 /* adjust file length if we extend past EOF */
7028 thyper.LowPart = count;
7029 thyper.HighPart = 0;
7030 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7031 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7032 /* we'd write past EOF, so extend the file */
7033 scp->mask |= CM_SCACHEMASK_LENGTH;
7034 scp->length = thyper;
7035 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7037 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7039 /* now, if the new position (thyper) and the old (offset) are in
7040 * different storeback windows, remember to store back the previous
7041 * storeback window when we're done with the write.
7043 * the purpose of this logic is to slow down the CIFS client
7044 * in order to avoid the client disconnecting during the CLOSE
7045 * operation if there are too many dirty buffers left to write
7046 * than can be accomplished during 45 seconds. This used to be
7047 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7048 * so that we can read larger amounts of data at a time.
7050 if (smb_AsyncStore == 1 &&
7051 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7052 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7053 /* they're different */
7055 writeBackOffset.HighPart = offset.HighPart;
7056 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7061 /* now, copy the data one buffer at a time, until we've filled the
7064 /* if we've copied all the data requested, we're done */
7068 /* handle over quota or out of space */
7069 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7070 *writtenp = written;
7071 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7075 /* otherwise, load up a buffer of data */
7076 thyper.HighPart = offset.HighPart;
7077 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7078 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7081 lock_ReleaseMutex(&bufferp->mx);
7082 buf_Release(bufferp);
7085 lock_ReleaseWrite(&scp->rw);
7087 code = buf_Get(scp, &thyper, &bufferp);
7089 lock_ObtainMutex(&bufferp->mx);
7090 lock_ObtainWrite(&scp->rw);
7091 if (code) goto done;
7093 bufferOffset = thyper;
7095 /* now get the data in the cache */
7097 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7098 CM_SCACHESYNC_NEEDCALLBACK
7099 | CM_SCACHESYNC_WRITE
7100 | CM_SCACHESYNC_BUFLOCKED);
7104 cm_SyncOpDone(scp, bufferp,
7105 CM_SCACHESYNC_NEEDCALLBACK
7106 | CM_SCACHESYNC_WRITE
7107 | CM_SCACHESYNC_BUFLOCKED);
7109 /* If we're overwriting the entire buffer, or
7110 * if we're writing at or past EOF, mark the
7111 * buffer as current so we don't call
7112 * cm_GetBuffer. This skips the fetch from the
7113 * server in those cases where we're going to
7114 * obliterate all the data in the buffer anyway,
7115 * or in those cases where there is no useful
7116 * data at the server to start with.
7118 * Use minLength instead of scp->length, since
7119 * the latter has already been updated by this
7122 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7123 || LargeIntegerEqualTo(offset, bufferp->offset)
7124 && (count >= cm_data.buf_blockSize
7125 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7126 ConvertLongToLargeInteger(count)),
7128 if (count < cm_data.buf_blockSize
7129 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7130 memset(bufferp->datap, 0,
7131 cm_data.buf_blockSize);
7132 bufferp->dataVersion = scp->dataVersion;
7135 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7137 /* otherwise, load the buffer and try again */
7138 lock_ReleaseMutex(&bufferp->mx);
7139 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7141 lock_ReleaseWrite(&scp->rw);
7142 lock_ObtainMutex(&bufferp->mx);
7143 lock_ObtainWrite(&scp->rw);
7147 lock_ReleaseMutex(&bufferp->mx);
7148 buf_Release(bufferp);
7152 } /* if (wrong buffer) ... */
7154 /* now we have the right buffer loaded. Copy out the
7155 * data from here to the user's buffer.
7157 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7159 /* and figure out how many bytes we want from this buffer */
7160 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7162 nbytes = count; /* don't go past end of request */
7164 /* now copy the data */
7165 memcpy(bufferp->datap + bufIndex, op, nbytes);
7166 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7168 /* adjust counters, pointers, etc. */
7172 thyper.LowPart = nbytes;
7173 thyper.HighPart = 0;
7174 offset = LargeIntegerAdd(thyper, offset);
7178 lock_ReleaseWrite(&scp->rw);
7181 lock_ReleaseMutex(&bufferp->mx);
7182 buf_Release(bufferp);
7185 lock_ObtainMutex(&fidp->mx);
7186 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7187 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7189 lock_ReleaseMutex(&fidp->mx);
7190 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7191 fidp->NTopen_dscp, fidp->NTopen_pathp,
7194 lock_ReleaseMutex(&fidp->mx);
7198 if (smb_AsyncStore > 0) {
7202 lock_ObtainWrite(&scp->rw);
7203 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7205 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7206 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7208 lock_ReleaseWrite(&scp->rw);
7209 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7210 writeBackOffset.HighPart,
7211 smb_AsyncStoreSize, 0, userp);
7212 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7215 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7219 cm_ReleaseSCache(scp);
7222 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7223 fidp->fid, code, *writtenp);
7228 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7231 unsigned short count;
7233 unsigned short hint;
7234 long written = 0, total_written = 0;
7237 smb_t* smbp = (smb_t*) inp;
7241 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7243 int inDataBlockCount;
7245 fd = smb_GetSMBParm(inp, 0);
7246 count = smb_GetSMBParm(inp, 1);
7247 offset.HighPart = 0; /* too bad */
7248 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7249 hint = smb_GetSMBParm(inp, 4);
7251 op = smb_GetSMBData(inp, NULL);
7252 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7254 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7255 fd, offset.LowPart, count);
7257 fd = smb_ChainFID(fd, inp);
7258 fidp = smb_FindFID(vcp, fd, 0);
7260 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7261 return CM_ERROR_BADFD;
7264 lock_ObtainMutex(&fidp->mx);
7265 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7266 lock_ReleaseMutex(&fidp->mx);
7267 smb_CloseFID(vcp, fidp, NULL, 0);
7268 smb_ReleaseFID(fidp);
7269 return CM_ERROR_NOSUCHFILE;
7272 if (fidp->flags & SMB_FID_IOCTL) {
7273 lock_ReleaseMutex(&fidp->mx);
7274 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7275 smb_ReleaseFID(fidp);
7276 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7281 lock_ReleaseMutex(&fidp->mx);
7282 smb_ReleaseFID(fidp);
7283 return CM_ERROR_BADFD;
7288 lock_ReleaseMutex(&fidp->mx);
7289 userp = smb_GetUserFromVCP(vcp, inp);
7293 LARGE_INTEGER LOffset;
7294 LARGE_INTEGER LLength;
7297 key = cm_GenerateKey(vcp->vcID, pid, fd);
7299 LOffset.HighPart = offset.HighPart;
7300 LOffset.LowPart = offset.LowPart;
7301 LLength.HighPart = 0;
7302 LLength.LowPart = count;
7304 lock_ObtainWrite(&scp->rw);
7305 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7306 lock_ReleaseWrite(&scp->rw);
7309 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7314 /* special case: 0 bytes transferred means truncate to this position */
7318 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7322 truncAttr.mask = CM_ATTRMASK_LENGTH;
7323 truncAttr.length.LowPart = offset.LowPart;
7324 truncAttr.length.HighPart = 0;
7325 lock_ObtainMutex(&fidp->mx);
7326 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7327 fidp->flags |= SMB_FID_LENGTHSETDONE;
7328 lock_ReleaseMutex(&fidp->mx);
7329 smb_SetSMBParm(outp, 0, 0 /* count */);
7330 smb_SetSMBDataLength(outp, 0);
7335 * Work around bug in NT client
7337 * When copying a file, the NT client should first copy the data,
7338 * then copy the last write time. But sometimes the NT client does
7339 * these in the wrong order, so the data copies would inadvertently
7340 * cause the last write time to be overwritten. We try to detect this,
7341 * and don't set client mod time if we think that would go against the
7344 lock_ObtainMutex(&fidp->mx);
7345 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7346 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7347 fidp->scp->clientModTime = time(NULL);
7349 lock_ReleaseMutex(&fidp->mx);
7352 while ( code == 0 && count > 0 ) {
7353 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7354 if (code == 0 && written == 0)
7355 code = CM_ERROR_PARTIALWRITE;
7357 offset = LargeIntegerAdd(offset,
7358 ConvertLongToLargeInteger(written));
7359 count -= (unsigned short)written;
7360 total_written += written;
7364 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7365 total_written, code);
7367 /* set the packet data length to 3 bytes for the data block header,
7368 * plus the size of the data.
7370 smb_SetSMBParm(outp, 0, total_written);
7371 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7372 smb_SetSMBParm(outp, 3, hint);
7373 smb_SetSMBDataLength(outp, 0);
7376 smb_ReleaseFID(fidp);
7377 cm_ReleaseUser(userp);
7378 cm_ReleaseSCache(scp);
7383 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7384 NCB *ncbp, raw_write_cont_t *rwcp)
7393 fd = smb_GetSMBParm(inp, 0);
7394 fidp = smb_FindFID(vcp, fd, 0);
7396 lock_ObtainMutex(&fidp->mx);
7397 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7398 lock_ReleaseMutex(&fidp->mx);
7399 smb_CloseFID(vcp, fidp, NULL, 0);
7400 smb_ReleaseFID(fidp);
7403 lock_ReleaseMutex(&fidp->mx);
7405 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7406 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7408 userp = smb_GetUserFromVCP(vcp, inp);
7411 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7413 if (rwcp->writeMode & 0x1) { /* synchronous */
7416 smb_FormatResponsePacket(vcp, inp, outp);
7417 op = (smb_t *) outp;
7418 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7419 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7420 smb_SetSMBDataLength(outp, 0);
7421 smb_SendPacket(vcp, outp);
7422 smb_FreePacket(outp);
7424 else { /* asynchronous */
7425 lock_ObtainMutex(&fidp->mx);
7426 fidp->raw_writers--;
7427 if (fidp->raw_writers == 0)
7428 thrd_SetEvent(fidp->raw_write_event);
7429 lock_ReleaseMutex(&fidp->mx);
7432 /* Give back raw buffer */
7433 lock_ObtainMutex(&smb_RawBufLock);
7434 *((char **)rawBuf) = smb_RawBufs;
7435 smb_RawBufs = rawBuf;
7436 lock_ReleaseMutex(&smb_RawBufLock);
7438 smb_ReleaseFID(fidp);
7439 cm_ReleaseUser(userp);
7442 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7447 /* SMB_COM_WRITE_RAW */
7448 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7451 long count, written = 0, total_written = 0;
7455 smb_t *smbp = (smb_t*) inp;
7460 unsigned short writeMode;
7462 fd = smb_GetSMBParm(inp, 0);
7463 totalCount = smb_GetSMBParm(inp, 1);
7464 count = smb_GetSMBParm(inp, 10);
7465 writeMode = smb_GetSMBParm(inp, 7);
7467 op = (char *) inp->data;
7468 op += smb_GetSMBParm(inp, 11);
7470 offset.HighPart = 0;
7471 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7473 if (*inp->wctp == 14) {
7474 /* we received a 64-bit file offset */
7475 #ifdef AFS_LARGEFILES
7476 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7478 if (LargeIntegerLessThanZero(offset)) {
7480 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7481 offset.HighPart, offset.LowPart);
7482 return CM_ERROR_BADSMB;
7485 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7487 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7488 return CM_ERROR_BADSMB;
7491 offset.HighPart = 0;
7494 offset.HighPart = 0; /* 32-bit file offset */
7498 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7499 fd, offset.HighPart, offset.LowPart, count);
7501 " WriteRaw WriteMode 0x%x",
7504 fd = smb_ChainFID(fd, inp);
7505 fidp = smb_FindFID(vcp, fd, 0);
7507 return CM_ERROR_BADFD;
7509 lock_ObtainMutex(&fidp->mx);
7510 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7511 lock_ReleaseMutex(&fidp->mx);
7512 smb_CloseFID(vcp, fidp, NULL, 0);
7513 smb_ReleaseFID(fidp);
7514 return CM_ERROR_NOSUCHFILE;
7518 lock_ReleaseMutex(&fidp->mx);
7519 smb_ReleaseFID(fidp);
7520 return CM_ERROR_BADFDOP;
7524 lock_ReleaseMutex(&fidp->mx);
7529 LARGE_INTEGER LOffset;
7530 LARGE_INTEGER LLength;
7533 key = cm_GenerateKey(vcp->vcID, pid, fd);
7535 LOffset.HighPart = offset.HighPart;
7536 LOffset.LowPart = offset.LowPart;
7537 LLength.HighPart = 0;
7538 LLength.LowPart = count;
7540 lock_ObtainWrite(&scp->rw);
7541 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7542 lock_ReleaseWrite(&scp->rw);
7545 cm_ReleaseSCache(scp);
7546 smb_ReleaseFID(fidp);
7551 userp = smb_GetUserFromVCP(vcp, inp);
7554 * Work around bug in NT client
7556 * When copying a file, the NT client should first copy the data,
7557 * then copy the last write time. But sometimes the NT client does
7558 * these in the wrong order, so the data copies would inadvertently
7559 * cause the last write time to be overwritten. We try to detect this,
7560 * and don't set client mod time if we think that would go against the
7563 lock_ObtainMutex(&fidp->mx);
7564 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7565 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7566 fidp->scp->clientModTime = time(NULL);
7568 lock_ReleaseMutex(&fidp->mx);
7571 while ( code == 0 && count > 0 ) {
7572 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7573 if (code == 0 && written == 0)
7574 code = CM_ERROR_PARTIALWRITE;
7576 offset = LargeIntegerAdd(offset,
7577 ConvertLongToLargeInteger(written));
7580 total_written += written;
7584 /* Get a raw buffer */
7587 lock_ObtainMutex(&smb_RawBufLock);
7589 /* Get a raw buf, from head of list */
7590 rawBuf = smb_RawBufs;
7591 smb_RawBufs = *(char **)smb_RawBufs;
7594 code = CM_ERROR_USESTD;
7596 lock_ReleaseMutex(&smb_RawBufLock);
7599 /* Don't allow a premature Close */
7600 if (code == 0 && (writeMode & 1) == 0) {
7601 lock_ObtainMutex(&fidp->mx);
7602 fidp->raw_writers++;
7603 thrd_ResetEvent(fidp->raw_write_event);
7604 lock_ReleaseMutex(&fidp->mx);
7607 smb_ReleaseFID(fidp);
7608 cm_ReleaseUser(userp);
7609 cm_ReleaseSCache(scp);
7612 smb_SetSMBParm(outp, 0, total_written);
7613 smb_SetSMBDataLength(outp, 0);
7614 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7619 offset = LargeIntegerAdd(offset,
7620 ConvertLongToLargeInteger(count));
7624 rwcp->offset.HighPart = offset.HighPart;
7625 rwcp->offset.LowPart = offset.LowPart;
7626 rwcp->count = totalCount - count;
7627 rwcp->writeMode = writeMode;
7628 rwcp->alreadyWritten = total_written;
7630 /* set the packet data length to 3 bytes for the data block header,
7631 * plus the size of the data.
7633 smb_SetSMBParm(outp, 0, 0xffff);
7634 smb_SetSMBDataLength(outp, 0);
7640 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7643 long count, finalCount;
7647 smb_t *smbp = (smb_t*) inp;
7653 fd = smb_GetSMBParm(inp, 0);
7654 count = smb_GetSMBParm(inp, 1);
7655 offset.HighPart = 0; /* too bad */
7656 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7658 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7659 fd, offset.LowPart, count);
7661 fd = smb_ChainFID(fd, inp);
7662 fidp = smb_FindFID(vcp, fd, 0);
7664 return CM_ERROR_BADFD;
7666 lock_ObtainMutex(&fidp->mx);
7667 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7668 lock_ReleaseMutex(&fidp->mx);
7669 smb_CloseFID(vcp, fidp, NULL, 0);
7670 smb_ReleaseFID(fidp);
7671 return CM_ERROR_NOSUCHFILE;
7674 if (fidp->flags & SMB_FID_IOCTL) {
7675 lock_ReleaseMutex(&fidp->mx);
7676 code = smb_IoctlRead(fidp, vcp, inp, outp);
7677 smb_ReleaseFID(fidp);
7682 lock_ReleaseMutex(&fidp->mx);
7683 smb_ReleaseFID(fidp);
7684 return CM_ERROR_BADFDOP;
7688 lock_ReleaseMutex(&fidp->mx);
7691 LARGE_INTEGER LOffset, LLength;
7695 key = cm_GenerateKey(vcp->vcID, pid, fd);
7697 LOffset.HighPart = 0;
7698 LOffset.LowPart = offset.LowPart;
7699 LLength.HighPart = 0;
7700 LLength.LowPart = count;
7702 lock_ObtainWrite(&scp->rw);
7703 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7704 lock_ReleaseWrite(&scp->rw);
7707 cm_ReleaseSCache(scp);
7708 smb_ReleaseFID(fidp);
7712 userp = smb_GetUserFromVCP(vcp, inp);
7714 /* remember this for final results */
7715 smb_SetSMBParm(outp, 0, count);
7716 smb_SetSMBParm(outp, 1, 0);
7717 smb_SetSMBParm(outp, 2, 0);
7718 smb_SetSMBParm(outp, 3, 0);
7719 smb_SetSMBParm(outp, 4, 0);
7721 /* set the packet data length to 3 bytes for the data block header,
7722 * plus the size of the data.
7724 smb_SetSMBDataLength(outp, count+3);
7726 /* get op ptr after putting in the parms, since otherwise we don't
7727 * know where the data really is.
7729 op = smb_GetSMBData(outp, NULL);
7731 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7732 *op++ = 1; /* data block marker */
7733 *op++ = (unsigned char) (count & 0xff);
7734 *op++ = (unsigned char) ((count >> 8) & 0xff);
7736 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7738 /* fix some things up */
7739 smb_SetSMBParm(outp, 0, finalCount);
7740 smb_SetSMBDataLength(outp, finalCount+3);
7742 smb_ReleaseFID(fidp);
7744 cm_ReleaseUser(userp);
7745 cm_ReleaseSCache(scp);
7749 /* SMB_COM_CREATE_DIRECTORY */
7750 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7752 clientchar_t *pathp;
7757 cm_scache_t *dscp; /* dir we're dealing with */
7758 cm_scache_t *scp; /* file we're creating */
7760 int initialModeBits;
7761 clientchar_t *lastNamep;
7763 clientchar_t *tidPathp;
7770 /* compute initial mode bits based on read-only flag in attributes */
7771 initialModeBits = 0777;
7773 tp = smb_GetSMBData(inp, NULL);
7774 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7776 return CM_ERROR_BADSMB;
7778 spacep = inp->spacep;
7779 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7781 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7782 return CM_ERROR_EXISTS;
7784 userp = smb_GetUserFromVCP(vcp, inp);
7786 caseFold = CM_FLAG_CASEFOLD;
7788 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7790 cm_ReleaseUser(userp);
7791 return CM_ERROR_NOSUCHPATH;
7794 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7795 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7796 userp, tidPathp, &req, &dscp);
7799 cm_ReleaseUser(userp);
7804 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7805 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7806 cm_ReleaseSCache(dscp);
7807 cm_ReleaseUser(userp);
7808 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7809 return CM_ERROR_PATH_NOT_COVERED;
7811 return CM_ERROR_BADSHARENAME;
7813 #endif /* DFS_SUPPORT */
7815 /* otherwise, scp points to the parent directory. Do a lookup, and
7816 * fail if we find it. Otherwise, we do the create.
7822 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7823 if (scp) cm_ReleaseSCache(scp);
7824 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7825 if (code == 0) code = CM_ERROR_EXISTS;
7826 cm_ReleaseSCache(dscp);
7827 cm_ReleaseUser(userp);
7831 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7832 setAttr.clientModTime = time(NULL);
7833 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7834 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7835 smb_NotifyChange(FILE_ACTION_ADDED,
7836 FILE_NOTIFY_CHANGE_DIR_NAME,
7837 dscp, lastNamep, NULL, TRUE);
7839 /* we don't need this any longer */
7840 cm_ReleaseSCache(dscp);
7843 /* something went wrong creating or truncating the file */
7844 cm_ReleaseUser(userp);
7848 /* otherwise we succeeded */
7849 smb_SetSMBDataLength(outp, 0);
7850 cm_ReleaseUser(userp);
7855 BOOL smb_IsLegalFilename(clientchar_t *filename)
7858 * Find the longest substring of filename that does not contain
7859 * any of the chars in illegalChars. If that substring is less
7860 * than the length of the whole string, then one or more of the
7861 * illegal chars is in filename.
7863 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7869 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7870 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7872 clientchar_t *pathp;
7878 cm_scache_t *dscp; /* dir we're dealing with */
7879 cm_scache_t *scp; /* file we're creating */
7881 int initialModeBits;
7884 clientchar_t *lastNamep;
7887 clientchar_t *tidPathp;
7889 int created = 0; /* the file was new */
7894 excl = (inp->inCom == 0x03)? 0 : 1;
7896 attributes = smb_GetSMBParm(inp, 0);
7897 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7899 /* compute initial mode bits based on read-only flag in attributes */
7900 initialModeBits = 0666;
7901 if (attributes & SMB_ATTR_READONLY)
7902 initialModeBits &= ~0222;
7904 tp = smb_GetSMBData(inp, NULL);
7905 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7907 return CM_ERROR_BADSMB;
7909 if (!cm_IsValidClientString(pathp)) {
7911 clientchar_t * hexp;
7913 hexp = cm_GetRawCharsAlloc(pathp, -1);
7914 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7915 osi_LogSaveClientString(smb_logp, hexp));
7919 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7921 return CM_ERROR_BADNTFILENAME;
7924 spacep = inp->spacep;
7925 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7927 userp = smb_GetUserFromVCP(vcp, inp);
7929 caseFold = CM_FLAG_CASEFOLD;
7931 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7933 cm_ReleaseUser(userp);
7934 return CM_ERROR_NOSUCHPATH;
7936 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7937 userp, tidPathp, &req, &dscp);
7940 cm_ReleaseUser(userp);
7945 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7946 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7947 cm_ReleaseSCache(dscp);
7948 cm_ReleaseUser(userp);
7949 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7950 return CM_ERROR_PATH_NOT_COVERED;
7952 return CM_ERROR_BADSHARENAME;
7954 #endif /* DFS_SUPPORT */
7956 /* otherwise, scp points to the parent directory. Do a lookup, and
7957 * truncate the file if we find it, otherwise we create the file.
7964 if (!smb_IsLegalFilename(lastNamep))
7965 return CM_ERROR_BADNTFILENAME;
7967 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7968 #ifdef DEBUG_VERBOSE
7971 hexp = osi_HexifyString( lastNamep );
7972 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7977 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7978 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7979 cm_ReleaseSCache(dscp);
7980 cm_ReleaseUser(userp);
7984 /* if we get here, if code is 0, the file exists and is represented by
7985 * scp. Otherwise, we have to create it.
7989 /* oops, file shouldn't be there */
7990 cm_ReleaseSCache(dscp);
7991 cm_ReleaseSCache(scp);
7992 cm_ReleaseUser(userp);
7993 return CM_ERROR_EXISTS;
7996 setAttr.mask = CM_ATTRMASK_LENGTH;
7997 setAttr.length.LowPart = 0;
7998 setAttr.length.HighPart = 0;
7999 code = cm_SetAttr(scp, &setAttr, userp, &req);
8002 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8003 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8004 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8008 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8009 smb_NotifyChange(FILE_ACTION_ADDED,
8010 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8011 dscp, lastNamep, NULL, TRUE);
8012 } else if (!excl && code == CM_ERROR_EXISTS) {
8013 /* not an exclusive create, and someone else tried
8014 * creating it already, then we open it anyway. We
8015 * don't bother retrying after this, since if this next
8016 * fails, that means that the file was deleted after
8017 * we started this call.
8019 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8022 setAttr.mask = CM_ATTRMASK_LENGTH;
8023 setAttr.length.LowPart = 0;
8024 setAttr.length.HighPart = 0;
8025 code = cm_SetAttr(scp, &setAttr, userp, &req);
8030 /* we don't need this any longer */
8031 cm_ReleaseSCache(dscp);
8034 /* something went wrong creating or truncating the file */
8035 if (scp) cm_ReleaseSCache(scp);
8036 cm_ReleaseUser(userp);
8040 /* make sure we only open files */
8041 if (scp->fileType != CM_SCACHETYPE_FILE) {
8042 cm_ReleaseSCache(scp);
8043 cm_ReleaseUser(userp);
8044 return CM_ERROR_ISDIR;
8047 /* now all we have to do is open the file itself */
8048 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8049 osi_assertx(fidp, "null smb_fid_t");
8053 lock_ObtainMutex(&fidp->mx);
8054 /* always create it open for read/write */
8055 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8057 /* remember that the file was newly created */
8059 fidp->flags |= SMB_FID_CREATED;
8061 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8063 /* save a pointer to the vnode */
8065 lock_ObtainWrite(&scp->rw);
8066 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8067 lock_ReleaseWrite(&scp->rw);
8070 fidp->userp = userp;
8071 lock_ReleaseMutex(&fidp->mx);
8073 smb_SetSMBParm(outp, 0, fidp->fid);
8074 smb_SetSMBDataLength(outp, 0);
8076 cm_Open(scp, 0, userp);
8078 smb_ReleaseFID(fidp);
8079 cm_ReleaseUser(userp);
8080 /* leave scp held since we put it in fidp->scp */
8085 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8088 osi_hyper_t new_offset;
8099 fd = smb_GetSMBParm(inp, 0);
8100 whence = smb_GetSMBParm(inp, 1);
8101 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8103 /* try to find the file descriptor */
8104 fd = smb_ChainFID(fd, inp);
8105 fidp = smb_FindFID(vcp, fd, 0);
8107 return CM_ERROR_BADFD;
8109 lock_ObtainMutex(&fidp->mx);
8110 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8111 lock_ReleaseMutex(&fidp->mx);
8112 smb_CloseFID(vcp, fidp, NULL, 0);
8113 smb_ReleaseFID(fidp);
8114 return CM_ERROR_NOSUCHFILE;
8117 if (fidp->flags & SMB_FID_IOCTL) {
8118 lock_ReleaseMutex(&fidp->mx);
8119 smb_ReleaseFID(fidp);
8120 return CM_ERROR_BADFD;
8124 lock_ReleaseMutex(&fidp->mx);
8125 smb_ReleaseFID(fidp);
8126 return CM_ERROR_BADFDOP;
8129 lock_ReleaseMutex(&fidp->mx);
8131 userp = smb_GetUserFromVCP(vcp, inp);
8133 lock_ObtainMutex(&fidp->mx);
8136 lock_ReleaseMutex(&fidp->mx);
8137 lock_ObtainWrite(&scp->rw);
8138 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8139 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8141 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8143 /* offset from current offset */
8144 new_offset = LargeIntegerAdd(fidp->offset,
8145 ConvertLongToLargeInteger(offset));
8147 else if (whence == 2) {
8148 /* offset from current EOF */
8149 new_offset = LargeIntegerAdd(scp->length,
8150 ConvertLongToLargeInteger(offset));
8152 new_offset = ConvertLongToLargeInteger(offset);
8155 fidp->offset = new_offset;
8156 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8157 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8158 smb_SetSMBDataLength(outp, 0);
8160 lock_ReleaseWrite(&scp->rw);
8161 smb_ReleaseFID(fidp);
8162 cm_ReleaseSCache(scp);
8163 cm_ReleaseUser(userp);
8167 /* dispatch all of the requests received in a packet. Due to chaining, this may
8168 * be more than one request.
8170 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8171 NCB *ncbp, raw_write_cont_t *rwcp)
8175 unsigned long code = 0;
8176 unsigned char *outWctp;
8177 int nparms; /* # of bytes of parameters */
8179 int nbytes; /* bytes of data, excluding count */
8182 unsigned short errCode;
8183 unsigned long NTStatus;
8185 unsigned char errClass;
8186 unsigned int oldGen;
8187 DWORD oldTime, newTime;
8189 /* get easy pointer to the data */
8190 smbp = (smb_t *) inp->data;
8192 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8193 /* setup the basic parms for the initial request in the packet */
8194 inp->inCom = smbp->com;
8195 inp->wctp = &smbp->wct;
8197 inp->ncb_length = ncbp->ncb_length;
8202 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8203 /* log it and discard it */
8204 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8205 __FILE__, __LINE__, ncbp->ncb_length);
8206 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8210 /* We are an ongoing op */
8211 thrd_Increment(&ongoingOps);
8213 /* set up response packet for receiving output */
8214 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8215 smb_FormatResponsePacket(vcp, inp, outp);
8216 outWctp = outp->wctp;
8218 /* Remember session generation number and time */
8219 oldGen = sessionGen;
8220 oldTime = GetTickCount();
8222 while (inp->inCom != 0xff) {
8223 dp = &smb_dispatchTable[inp->inCom];
8225 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8226 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8227 code = outp->resumeCode;
8231 /* process each request in the packet; inCom, wctp and inCount
8232 * are already set up.
8234 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8237 /* now do the dispatch */
8238 /* start by formatting the response record a little, as a default */
8239 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8241 outWctp[1] = 0xff; /* no operation */
8242 outWctp[2] = 0; /* padding */
8247 /* not a chained request, this is a more reasonable default */
8248 outWctp[0] = 0; /* wct of zero */
8249 outWctp[1] = 0; /* and bcc (word) of zero */
8253 /* once set, stays set. Doesn't matter, since we never chain
8254 * "no response" calls.
8256 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8260 /* we have a recognized operation */
8261 char * opName = myCrt_Dispatch(inp->inCom);
8263 if (inp->inCom == 0x1d)
8265 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8267 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8268 opName,vcp,vcp->lana,vcp->lsn);
8269 code = (*(dp->procp)) (vcp, inp, outp);
8270 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8271 code,vcp,vcp->lana,vcp->lsn);
8273 if ( code == CM_ERROR_BADSMB ||
8274 code == CM_ERROR_BADOP )
8276 #endif /* LOG_PACKET */
8279 newTime = GetTickCount();
8280 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8282 /* ReceiveV3Tran2A handles its own logging */
8283 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8286 clientchar_t *treepath = NULL; /* do not free */
8287 clientchar_t *pathname = NULL;
8288 cm_fid_t afid = {0,0,0,0,0};
8290 uidp = smb_FindUID(vcp, smbp->uid, 0);
8291 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8292 fidp = smb_FindFID(vcp, inp->fid, 0);
8295 lock_ObtainMutex(&fidp->mx);
8296 if (fidp->NTopen_pathp)
8297 pathname = fidp->NTopen_pathp;
8299 afid = fidp->scp->fid;
8301 if (inp->stringsp->wdata)
8302 pathname = inp->stringsp->wdata;
8305 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8306 opName, newTime - oldTime,
8307 uidp ? uidp->unp->name : NULL,
8310 afid.cell, afid.volume, afid.vnode, afid.unique);
8313 lock_ReleaseMutex(&fidp->mx);
8316 smb_ReleaseUID(uidp);
8318 smb_ReleaseFID(fidp);
8321 if (oldGen != sessionGen) {
8322 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8323 newTime - oldTime, ncbp->ncb_length);
8324 osi_Log3(smb_logp, "Request %s straddled session startup, "
8325 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8328 FreeSMBStrings(inp);
8330 /* bad opcode, fail the request, after displaying it */
8331 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8334 #endif /* LOG_PACKET */
8337 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8338 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8339 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8340 if (code == IDCANCEL)
8343 code = CM_ERROR_BADOP;
8346 /* catastrophic failure: log as much as possible */
8347 if (code == CM_ERROR_BADSMB) {
8348 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8352 #endif /* LOG_PACKET */
8353 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8356 code = CM_ERROR_INVAL;
8359 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8360 thrd_Decrement(&ongoingOps);
8365 /* now, if we failed, turn the current response into an empty
8366 * one, and fill in the response packet's error code.
8369 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8370 smb_MapNTError(code, &NTStatus);
8371 outWctp = outp->wctp;
8372 smbp = (smb_t *) &outp->data;
8373 if (code != CM_ERROR_PARTIALWRITE
8374 && code != CM_ERROR_BUFFERTOOSMALL
8375 && code != CM_ERROR_GSSCONTINUE) {
8376 /* nuke wct and bcc. For a partial
8377 * write or an in-process authentication handshake,
8378 * assume they're OK.
8384 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8385 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8386 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8387 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8388 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8392 smb_MapCoreError(code, vcp, &errCode, &errClass);
8393 outWctp = outp->wctp;
8394 smbp = (smb_t *) &outp->data;
8395 if (code != CM_ERROR_PARTIALWRITE) {
8396 /* nuke wct and bcc. For a partial
8397 * write, assume they're OK.
8403 smbp->errLow = (unsigned char) (errCode & 0xff);
8404 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8405 smbp->rcls = errClass;
8408 } /* error occurred */
8410 /* if we're here, we've finished one request. Look to see if
8411 * this is a chained opcode. If it is, setup things to process
8412 * the chained request, and setup the output buffer to hold the
8413 * chained response. Start by finding the next input record.
8415 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8416 break; /* not a chained req */
8417 tp = inp->wctp; /* points to start of last request */
8418 /* in a chained request, the first two
8419 * parm fields are required, and are
8420 * AndXCommand/AndXReserved and
8422 if (tp[0] < 2) break;
8423 if (tp[1] == 0xff) break; /* no more chained opcodes */
8425 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8428 /* and now append the next output request to the end of this
8429 * last request. Begin by finding out where the last response
8430 * ends, since that's where we'll put our new response.
8432 outWctp = outp->wctp; /* ptr to out parameters */
8433 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8434 nparms = outWctp[0] << 1;
8435 tp = outWctp + nparms + 1; /* now points to bcc field */
8436 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8437 tp += 2 /* for the count itself */ + nbytes;
8438 /* tp now points to the new output record; go back and patch the
8439 * second parameter (off2) to point to the new record.
8441 temp = (unsigned int)(tp - outp->data);
8442 outWctp[3] = (unsigned char) (temp & 0xff);
8443 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8444 outWctp[2] = 0; /* padding */
8445 outWctp[1] = inp->inCom; /* next opcode */
8447 /* finally, setup for the next iteration */
8450 } /* while loop over all requests in the packet */
8452 /* now send the output packet, and return */
8454 smb_SendPacket(vcp, outp);
8455 thrd_Decrement(&ongoingOps);
8460 /* Wait for Netbios() calls to return, and make the results available to server
8461 * threads. Note that server threads can't wait on the NCBevents array
8462 * themselves, because NCB events are manual-reset, and the servers would race
8463 * each other to reset them.
8465 void smb_ClientWaiter(void *parmp)
8470 while (smbShutdownFlag == 0) {
8471 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8473 if (code == WAIT_OBJECT_0)
8476 /* error checking */
8477 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8479 int abandonIdx = code - WAIT_ABANDONED_0;
8480 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8483 if (code == WAIT_IO_COMPLETION)
8485 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8489 if (code == WAIT_TIMEOUT)
8491 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8494 if (code == WAIT_FAILED)
8496 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8499 idx = code - WAIT_OBJECT_0;
8501 /* check idx range! */
8502 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8504 /* this is fatal - log as much as possible */
8505 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8506 osi_assertx(0, "invalid index");
8509 thrd_ResetEvent(NCBevents[idx]);
8510 thrd_SetEvent(NCBreturns[0][idx]);
8515 * Try to have one NCBRECV request waiting for every live session. Not more
8516 * than one, because if there is more than one, it's hard to handle Write Raw.
8518 void smb_ServerWaiter(void *parmp)
8521 int idx_session, idx_NCB;
8524 while (smbShutdownFlag == 0) {
8526 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8528 if (code == WAIT_OBJECT_0)
8531 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8533 int abandonIdx = code - WAIT_ABANDONED_0;
8534 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8537 if (code == WAIT_IO_COMPLETION)
8539 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8543 if (code == WAIT_TIMEOUT)
8545 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8548 if (code == WAIT_FAILED)
8550 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8553 idx_session = code - WAIT_OBJECT_0;
8555 /* check idx range! */
8556 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8558 /* this is fatal - log as much as possible */
8559 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8560 osi_assertx(0, "invalid index");
8565 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8567 if (code == WAIT_OBJECT_0) {
8568 if (smbShutdownFlag == 1)
8574 /* error checking */
8575 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8577 int abandonIdx = code - WAIT_ABANDONED_0;
8578 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8581 if (code == WAIT_IO_COMPLETION)
8583 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8587 if (code == WAIT_TIMEOUT)
8589 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8592 if (code == WAIT_FAILED)
8594 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8597 idx_NCB = code - WAIT_OBJECT_0;
8599 /* check idx range! */
8600 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8602 /* this is fatal - log as much as possible */
8603 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8604 osi_assertx(0, "invalid index");
8607 /* Link them together */
8608 NCBsessions[idx_NCB] = idx_session;
8611 ncbp = NCBs[idx_NCB];
8612 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8613 ncbp->ncb_command = NCBRECV | ASYNCH;
8614 ncbp->ncb_lana_num = lanas[idx_session];
8615 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8616 ncbp->ncb_event = NCBevents[idx_NCB];
8617 ncbp->ncb_length = SMB_PACKETSIZE;
8623 * The top level loop for handling SMB request messages. Each server thread
8624 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8625 * NCB and buffer for the incoming request are loaned to us.
8627 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8628 * to immediately send a request for the rest of the data. This must come
8629 * before any other traffic for that session, so we delay setting the session
8630 * event until that data has come in.
8632 void smb_Server(VOID *parmp)
8634 INT_PTR myIdx = (INT_PTR) parmp;
8638 smb_packet_t *outbufp;
8640 int idx_NCB, idx_session;
8642 smb_vc_t *vcp = NULL;
8644 extern void rx_StartClientThread(void);
8646 rx_StartClientThread();
8648 outncbp = smb_GetNCB();
8649 outbufp = smb_GetPacket();
8650 outbufp->ncbp = outncbp;
8658 smb_ResetServerPriority();
8660 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8663 /* terminate silently if shutdown flag is set */
8664 if (code == WAIT_OBJECT_0) {
8665 if (smbShutdownFlag == 1) {
8666 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8672 /* error checking */
8673 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8675 int abandonIdx = code - WAIT_ABANDONED_0;
8676 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8679 if (code == WAIT_IO_COMPLETION)
8681 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8685 if (code == WAIT_TIMEOUT)
8687 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8690 if (code == WAIT_FAILED)
8692 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8695 idx_NCB = code - WAIT_OBJECT_0;
8697 /* check idx range! */
8698 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8700 /* this is fatal - log as much as possible */
8701 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8702 osi_assertx(0, "invalid index");
8705 ncbp = NCBs[idx_NCB];
8706 idx_session = NCBsessions[idx_NCB];
8707 rc = ncbp->ncb_retcode;
8709 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8710 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8714 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8718 /* Can this happen? Or is it just my UNIX paranoia? */
8719 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8724 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8727 /* Client closed session */
8728 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8730 lock_ObtainMutex(&vcp->mx);
8731 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8732 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8734 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8735 lock_ReleaseMutex(&vcp->mx);
8736 lock_ObtainWrite(&smb_globalLock);
8737 dead_sessions[vcp->session] = TRUE;
8738 lock_ReleaseWrite(&smb_globalLock);
8740 lock_ReleaseMutex(&vcp->mx);
8742 smb_CleanupDeadVC(vcp);
8749 /* Treat as transient error */
8750 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8753 "dispatch smb recv failed, message incomplete, ncb_length %d",
8756 "SMB message incomplete, "
8757 "length %d", ncbp->ncb_length);
8760 * We used to discard the packet.
8761 * Instead, try handling it normally.
8765 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8769 /* A weird error code. Log it, sleep, and continue. */
8770 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8772 lock_ObtainMutex(&vcp->mx);
8773 if (vcp->errorCount++ > 3) {
8774 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8775 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8776 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8778 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8779 lock_ReleaseMutex(&vcp->mx);
8780 lock_ObtainWrite(&smb_globalLock);
8781 dead_sessions[vcp->session] = TRUE;
8782 lock_ReleaseWrite(&smb_globalLock);
8784 lock_ReleaseMutex(&vcp->mx);
8786 smb_CleanupDeadVC(vcp);
8792 lock_ReleaseMutex(&vcp->mx);
8796 thrd_SetEvent(SessionEvents[idx_session]);
8802 /* Success, so now dispatch on all the data in the packet */
8804 smb_concurrentCalls++;
8805 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8806 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8809 * If at this point vcp is NULL (implies that packet was invalid)
8810 * then we are in big trouble. This means either :
8811 * a) we have the wrong NCB.
8812 * b) Netbios screwed up the call.
8813 * c) The VC was already marked dead before we were able to
8815 * Obviously this implies that
8816 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8817 * lanas[idx_session] != ncbp->ncb_lana_num )
8818 * Either way, we can't do anything with this packet.
8819 * Log, sleep and resume.
8822 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8826 ncbp->ncb_lana_num);
8828 /* Also log in the trace log. */
8829 osi_Log4(smb_logp, "Server: VCP does not exist!"
8830 "LSNs[idx_session]=[%d],"
8831 "lanas[idx_session]=[%d],"
8832 "ncbp->ncb_lsn=[%d],"
8833 "ncbp->ncb_lana_num=[%d]",
8837 ncbp->ncb_lana_num);
8839 /* thrd_Sleep(1000); Don't bother sleeping */
8840 thrd_SetEvent(SessionEvents[idx_session]);
8841 smb_concurrentCalls--;
8845 smb_SetRequestStartTime();
8847 vcp->errorCount = 0;
8848 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8849 smbp = (smb_t *)bufp->data;
8856 if (smbp->com == 0x1d) {
8857 /* Special handling for Write Raw */
8858 raw_write_cont_t rwc;
8860 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8861 if (rwc.code == 0) {
8862 EVENT_HANDLE rwevent;
8863 char eventName[MAX_PATH];
8865 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
8866 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8867 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8868 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8870 ncbp->ncb_command = NCBRECV | ASYNCH;
8871 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8872 ncbp->ncb_lana_num = vcp->lana;
8873 ncbp->ncb_buffer = rwc.buf;
8874 ncbp->ncb_length = 65535;
8875 ncbp->ncb_event = rwevent;
8877 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8878 thrd_CloseHandle(rwevent);
8880 thrd_SetEvent(SessionEvents[idx_session]);
8882 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8884 else if (smbp->com == 0xa0) {
8886 * Serialize the handling for NT Transact
8889 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8890 thrd_SetEvent(SessionEvents[idx_session]);
8892 thrd_SetEvent(SessionEvents[idx_session]);
8893 /* TODO: what else needs to be serialized? */
8894 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8898 __except( smb_ServerExceptionFilter() ) {
8902 smb_concurrentCalls--;
8905 thrd_SetEvent(NCBavails[idx_NCB]);
8910 smb_FreePacket(outbufp);
8912 smb_FreeNCB(outncbp);
8916 * Exception filter for the server threads. If an exception occurs in the
8917 * dispatch routines, which is where exceptions are most common, then do a
8918 * force trace and give control to upstream exception handlers. Useful for
8921 DWORD smb_ServerExceptionFilter(void) {
8922 /* While this is not the best time to do a trace, if it succeeds, then
8923 * we have a trace (assuming tracing was enabled). Otherwise, this should
8924 * throw a second exception.
8926 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8927 afsd_ForceTrace(TRUE);
8928 buf_ForceTrace(TRUE);
8929 return EXCEPTION_CONTINUE_SEARCH;
8933 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8934 * If the number of server threads is M, and the number of live sessions is
8935 * N, then the number of NCB's in use at any time either waiting for, or
8936 * holding, received messages is M + N, so that is how many NCB's get created.
8938 void InitNCBslot(int idx)
8940 struct smb_packet *bufp;
8941 EVENT_HANDLE retHandle;
8943 char eventName[MAX_PATH];
8945 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8947 NCBs[idx] = smb_GetNCB();
8948 sprintf(eventName,"NCBavails[%d]", idx);
8949 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8950 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8951 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8952 sprintf(eventName,"NCBevents[%d]", idx);
8953 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8954 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8955 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8956 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8957 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8958 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8959 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8960 for (i=0; i<smb_NumServerThreads; i++)
8961 NCBreturns[i][idx] = retHandle;
8962 bufp = smb_GetPacket();
8963 bufp->spacep = cm_GetSpace();
8967 /* listen for new connections */
8968 void smb_Listener(void *parmp)
8974 afs_uint32 session, thread;
8975 smb_vc_t *vcp = NULL;
8977 char rname[NCBNAMSZ+1];
8978 char cname[MAX_COMPUTERNAME_LENGTH+1];
8979 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8980 INT_PTR lana = (INT_PTR) parmp;
8981 char eventName[MAX_PATH];
8982 int bridgeCount = 0;
8983 int nowildCount = 0;
8985 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8986 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8987 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8988 thrd_ResetEvent(ListenerShutdown[lana]);
8990 ncbp = smb_GetNCB();
8992 /* retrieve computer name */
8993 GetComputerName(cname, &cnamelen);
8996 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8997 memset(ncbp, 0, sizeof(NCB));
9000 ncbp->ncb_command = NCBLISTEN;
9001 ncbp->ncb_rto = 0; /* No receive timeout */
9002 ncbp->ncb_sto = 0; /* No send timeout */
9004 /* pad out with spaces instead of null termination */
9005 len = (long)strlen(smb_localNamep);
9006 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9007 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9009 strcpy(ncbp->ncb_callname, "*");
9010 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9012 ncbp->ncb_lana_num = (UCHAR)lana;
9014 code = Netbios(ncbp);
9016 if (code == NRC_NAMERR) {
9017 /* An smb shutdown or Vista resume must have taken place */
9019 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9020 ncbp->ncb_lana_num);
9021 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9023 if (lock_TryMutex(&smb_StartedLock)) {
9024 lana_list.lana[i] = LANA_INVALID;
9025 lock_ReleaseMutex(&smb_StartedLock);
9028 } else if (code == NRC_BRIDGE || code != 0) {
9029 int lanaRemaining = 0;
9031 if (code == NRC_BRIDGE) {
9032 if (++bridgeCount <= 5) {
9033 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9036 } else if (code == NRC_NOWILD) {
9037 if (++nowildCount <= 5) {
9038 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9040 if (bridgeCount > 0) {
9041 memset(ncbp, 0, sizeof(*ncbp));
9042 ncbp->ncb_command = NCBADDNAME;
9043 ncbp->ncb_lana_num = (UCHAR)lana;
9044 /* pad out with spaces instead of null termination */
9045 len = (long)strlen(smb_localNamep);
9046 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9047 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9048 code = Netbios(ncbp);
9054 while (!lock_TryMutex(&smb_StartedLock)) {
9055 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9061 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9062 ncbp->ncb_lana_num, ncb_error_string(code));
9063 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9064 ncbp->ncb_lana_num, ncb_error_string(code));
9066 for (i = 0; i < lana_list.length; i++) {
9067 if (lana_list.lana[i] == lana) {
9068 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9069 lana_list.lana[i] = LANA_INVALID;
9071 if (lana_list.lana[i] != LANA_INVALID)
9075 if (lanaRemaining == 0) {
9076 cm_VolStatus_Network_Stopped(cm_NetbiosName
9081 smb_ListenerState = SMB_LISTENER_STOPPED;
9082 smb_LANadapter = LANA_INVALID;
9083 lana_list.length = 0;
9085 lock_ReleaseMutex(&smb_StartedLock);
9089 else if (code != 0) {
9090 char tbuffer[AFSPATHMAX];
9092 /* terminate silently if shutdown flag is set */
9093 while (!lock_TryMutex(&smb_StartedLock)) {
9094 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9100 "NCBLISTEN lana=%d failed with code %d [%s]",
9101 ncbp->ncb_lana_num, code, ncb_error_string(code));
9103 "Client exiting due to network failure. Please restart client.\n");
9106 "Client exiting due to network failure. Please restart client.\n"
9107 "NCBLISTEN lana=%d failed with code %d [%s]",
9108 ncbp->ncb_lana_num, code, ncb_error_string(code));
9110 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9111 MB_OK|MB_SERVICE_NOTIFICATION);
9112 osi_panic(tbuffer, __FILE__, __LINE__);
9114 lock_ReleaseMutex(&smb_StartedLock);
9119 /* a successful packet received. clear bridge error count */
9123 /* check for remote conns */
9124 /* first get remote name and insert null terminator */
9125 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9126 for (i=NCBNAMSZ; i>0; i--) {
9127 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9133 /* compare with local name */
9135 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9136 flags |= SMB_VCFLAG_REMOTECONN;
9139 lock_ObtainMutex(&smb_ListenerLock);
9141 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9142 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9144 /* now ncbp->ncb_lsn is the connection ID */
9145 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9146 if (vcp->session == 0) {
9147 /* New generation */
9148 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9151 /* Log session startup */
9153 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9154 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9155 #endif /* NOTSERVICE */
9156 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9157 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9159 if (reportSessionStartups) {
9160 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9163 lock_ObtainMutex(&vcp->mx);
9164 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9165 vcp->flags |= flags;
9166 lock_ReleaseMutex(&vcp->mx);
9168 /* Allocate slot in session arrays */
9169 /* Re-use dead session if possible, otherwise add one more */
9170 /* But don't look at session[0], it is reserved */
9171 lock_ObtainWrite(&smb_globalLock);
9172 for (session = 1; session < numSessions; session++) {
9173 if (dead_sessions[session]) {
9174 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9175 dead_sessions[session] = FALSE;
9179 lock_ReleaseWrite(&smb_globalLock);
9181 /* We are re-using an existing VC because the lsn and lana
9183 session = vcp->session;
9185 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9187 /* Log session startup */
9189 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9190 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9191 #endif /* NOTSERVICE */
9192 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9193 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9195 if (reportSessionStartups) {
9196 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9200 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9201 unsigned long code = CM_ERROR_ALLBUSY;
9202 smb_packet_t * outp = smb_GetPacket();
9203 unsigned char *outWctp;
9206 smb_FormatResponsePacket(vcp, NULL, outp);
9209 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9210 unsigned long NTStatus;
9211 smb_MapNTError(code, &NTStatus);
9212 outWctp = outp->wctp;
9213 smbp = (smb_t *) &outp->data;
9217 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9218 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9219 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9220 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9221 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9223 unsigned short errCode;
9224 unsigned char errClass;
9225 smb_MapCoreError(code, vcp, &errCode, &errClass);
9226 outWctp = outp->wctp;
9227 smbp = (smb_t *) &outp->data;
9231 smbp->errLow = (unsigned char) (errCode & 0xff);
9232 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9233 smbp->rcls = errClass;
9236 smb_SendPacket(vcp, outp);
9237 smb_FreePacket(outp);
9239 lock_ObtainMutex(&vcp->mx);
9240 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9241 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9243 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9244 lock_ReleaseMutex(&vcp->mx);
9245 lock_ObtainWrite(&smb_globalLock);
9246 dead_sessions[vcp->session] = TRUE;
9247 lock_ReleaseWrite(&smb_globalLock);
9248 smb_CleanupDeadVC(vcp);
9250 lock_ReleaseMutex(&vcp->mx);
9253 /* assert that we do not exceed the maximum number of sessions or NCBs.
9254 * we should probably want to wait for a session to be freed in case
9257 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9258 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9260 lock_ObtainMutex(&vcp->mx);
9261 vcp->session = session;
9262 lock_ReleaseMutex(&vcp->mx);
9263 lock_ObtainWrite(&smb_globalLock);
9264 LSNs[session] = ncbp->ncb_lsn;
9265 lanas[session] = ncbp->ncb_lana_num;
9266 lock_ReleaseWrite(&smb_globalLock);
9268 if (session == numSessions) {
9269 /* Add new NCB for new session */
9270 char eventName[MAX_PATH];
9272 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9274 InitNCBslot(numNCBs);
9275 lock_ObtainWrite(&smb_globalLock);
9277 lock_ReleaseWrite(&smb_globalLock);
9278 thrd_SetEvent(NCBavails[0]);
9279 thrd_SetEvent(NCBevents[0]);
9280 for (thread = 0; thread < smb_NumServerThreads; thread++)
9281 thrd_SetEvent(NCBreturns[thread][0]);
9282 /* Also add new session event */
9283 sprintf(eventName, "SessionEvents[%d]", session);
9284 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9285 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9286 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9287 lock_ObtainWrite(&smb_globalLock);
9289 lock_ReleaseWrite(&smb_globalLock);
9290 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9291 thrd_SetEvent(SessionEvents[0]);
9293 thrd_SetEvent(SessionEvents[session]);
9299 lock_ReleaseMutex(&smb_ListenerLock);
9300 } /* dispatch while loop */
9304 thrd_SetEvent(ListenerShutdown[lana]);
9309 smb_LanAdapterChangeThread(void *param)
9312 * Give the IPAddrDaemon thread a chance
9313 * to block before we trigger.
9316 smb_LanAdapterChange(0);
9319 void smb_SetLanAdapterChangeDetected(void)
9324 lock_ObtainMutex(&smb_StartedLock);
9326 if (!powerStateSuspended) {
9327 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9328 NULL, 0, &lpid, "smb_LanAdapterChange");
9329 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9330 thrd_CloseHandle(phandle);
9333 smb_LanAdapterChangeDetected = 1;
9334 lock_ReleaseMutex(&smb_StartedLock);
9337 void smb_LanAdapterChange(int locked) {
9338 lana_number_t lanaNum;
9340 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9342 LANA_ENUM temp_list;
9347 afsi_log("smb_LanAdapterChange");
9350 lock_ObtainMutex(&smb_StartedLock);
9352 smb_LanAdapterChangeDetected = 0;
9354 if (!powerStateSuspended &&
9355 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9356 LANA_NETBIOS_NAME_FULL)) &&
9357 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9358 if ( isGateway != bGateway ) {
9359 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9360 smb_LANadapter, lanaNum, isGateway, bGateway);
9362 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9363 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9364 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9367 NCB *ncbp = smb_GetNCB();
9368 ncbp->ncb_command = NCBENUM;
9369 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9370 ncbp->ncb_length = sizeof(temp_list);
9371 code = Netbios(ncbp);
9373 if (temp_list.length != lana_list.length) {
9374 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9375 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9378 for (i=0; i<lana_list.length; i++) {
9379 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9380 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9381 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9393 smb_StopListeners(1);
9394 smb_RestartListeners(1);
9397 lock_ReleaseMutex(&smb_StartedLock);
9400 /* initialize Netbios */
9401 int smb_NetbiosInit(int locked)
9404 int i, lana, code, l;
9406 int delname_tried=0;
9409 lana_number_t lanaNum;
9412 lock_ObtainMutex(&smb_StartedLock);
9414 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9415 smb_ListenerState != SMB_LISTENER_STOPPED) {
9418 lock_ReleaseMutex(&smb_StartedLock);
9421 /* setup the NCB system */
9422 ncbp = smb_GetNCB();
9424 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9425 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9426 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9428 if (smb_LANadapter != LANA_INVALID)
9429 afsi_log("LAN adapter number %d", smb_LANadapter);
9431 afsi_log("LAN adapter number not determined");
9434 afsi_log("Set for gateway service");
9436 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9438 /* something went horribly wrong. We can't proceed without a netbios name */
9440 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9441 osi_panic(buf, __FILE__, __LINE__);
9444 /* remember the name */
9445 len = (int)strlen(cm_NetbiosName);
9447 free(smb_localNamep);
9448 smb_localNamep = malloc(len+1);
9449 strcpy(smb_localNamep, cm_NetbiosName);
9450 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9452 /* Also copy the value to the client character encoded string */
9453 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9455 if (smb_LANadapter == LANA_INVALID) {
9456 ncbp->ncb_command = NCBENUM;
9457 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9458 ncbp->ncb_length = sizeof(lana_list);
9459 code = Netbios(ncbp);
9461 afsi_log("Netbios NCBENUM error code %d", code);
9462 osi_panic(s, __FILE__, __LINE__);
9466 lana_list.length = 1;
9467 lana_list.lana[0] = smb_LANadapter;
9470 for (i = 0; i < lana_list.length; i++) {
9471 /* reset the adaptor: in Win32, this is required for every process, and
9472 * acts as an init call, not as a real hardware reset.
9474 ncbp->ncb_command = NCBRESET;
9475 ncbp->ncb_callname[0] = 100;
9476 ncbp->ncb_callname[2] = 100;
9477 ncbp->ncb_lana_num = lana_list.lana[i];
9478 code = Netbios(ncbp);
9480 code = ncbp->ncb_retcode;
9482 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9483 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9485 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9489 /* and declare our name so we can receive connections */
9490 memset(ncbp, 0, sizeof(*ncbp));
9491 len=lstrlen(smb_localNamep);
9492 memset(smb_sharename,' ',NCBNAMSZ);
9493 memcpy(smb_sharename,smb_localNamep,len);
9494 afsi_log("lana_list.length %d", lana_list.length);
9496 /* Keep the name so we can unregister it later */
9497 for (l = 0; l < lana_list.length; l++) {
9498 lana = lana_list.lana[l];
9500 ncbp->ncb_command = NCBADDNAME;
9501 ncbp->ncb_lana_num = lana;
9502 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9503 code = Netbios(ncbp);
9505 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9506 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9508 char name[NCBNAMSZ+1];
9510 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9511 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9515 code = ncbp->ncb_retcode;
9518 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9521 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9522 if (code == NRC_BRIDGE) { /* invalid LANA num */
9523 lana_list.lana[l] = LANA_INVALID;
9526 else if (code == NRC_DUPNAME) {
9527 afsi_log("Name already exists; try to delete it");
9528 memset(ncbp, 0, sizeof(*ncbp));
9529 ncbp->ncb_command = NCBDELNAME;
9530 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9531 ncbp->ncb_lana_num = lana;
9532 code = Netbios(ncbp);
9534 code = ncbp->ncb_retcode;
9536 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9538 if (code != 0 || delname_tried) {
9539 lana_list.lana[l] = LANA_INVALID;
9541 else if (code == 0) {
9542 if (!delname_tried) {
9550 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9551 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9555 smb_LANadapter = lana;
9556 lana_found = 1; /* at least one worked */
9560 osi_assertx(lana_list.length >= 0, "empty lana list");
9562 afsi_log("No valid LANA numbers found!");
9563 lana_list.length = 0;
9564 smb_LANadapter = LANA_INVALID;
9565 smb_ListenerState = SMB_LISTENER_STOPPED;
9566 cm_VolStatus_Network_Stopped(cm_NetbiosName
9573 /* we're done with the NCB now */
9576 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9577 if (lana_list.length > 0)
9578 osi_assert(smb_LANadapter != LANA_INVALID);
9581 lock_ReleaseMutex(&smb_StartedLock);
9583 return (lana_list.length > 0 ? 1 : 0);
9586 void smb_StartListeners(int locked)
9593 lock_ObtainMutex(&smb_StartedLock);
9595 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9597 lock_ReleaseMutex(&smb_StartedLock);
9601 afsi_log("smb_StartListeners");
9602 smb_ListenerState = SMB_LISTENER_STARTED;
9603 cm_VolStatus_Network_Started(cm_NetbiosName
9609 for (i = 0; i < lana_list.length; i++) {
9610 if (lana_list.lana[i] == LANA_INVALID)
9612 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9613 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9614 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9615 thrd_CloseHandle(phandle);
9618 lock_ReleaseMutex(&smb_StartedLock);
9621 void smb_RestartListeners(int locked)
9624 lock_ObtainMutex(&smb_StartedLock);
9626 if (powerStateSuspended)
9627 afsi_log("smb_RestartListeners called while suspended");
9629 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9630 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9631 if (smb_NetbiosInit(1))
9632 smb_StartListeners(1);
9633 } else if (smb_LanAdapterChangeDetected) {
9634 smb_LanAdapterChange(1);
9638 lock_ReleaseMutex(&smb_StartedLock);
9641 void smb_StopListener(NCB *ncbp, int lana, int wait)
9645 memset(ncbp, 0, sizeof(*ncbp));
9646 ncbp->ncb_command = NCBDELNAME;
9647 ncbp->ncb_lana_num = lana;
9648 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9649 code = Netbios(ncbp);
9651 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9652 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9654 /* and then reset the LANA; this will cause the listener threads to exit */
9655 ncbp->ncb_command = NCBRESET;
9656 ncbp->ncb_callname[0] = 100;
9657 ncbp->ncb_callname[2] = 100;
9658 ncbp->ncb_lana_num = lana;
9659 code = Netbios(ncbp);
9661 code = ncbp->ncb_retcode;
9663 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9665 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9669 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9672 void smb_StopListeners(int locked)
9678 lock_ObtainMutex(&smb_StartedLock);
9680 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9682 lock_ReleaseMutex(&smb_StartedLock);
9686 afsi_log("smb_StopListeners");
9687 smb_ListenerState = SMB_LISTENER_STOPPED;
9688 cm_VolStatus_Network_Stopped(cm_NetbiosName
9694 ncbp = smb_GetNCB();
9696 /* Unregister the SMB name */
9697 for (l = 0; l < lana_list.length; l++) {
9698 lana = lana_list.lana[l];
9700 if (lana != LANA_INVALID) {
9701 smb_StopListener(ncbp, lana, TRUE);
9703 /* mark the adapter invalid */
9704 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9708 /* force a re-evaluation of the network adapters */
9709 lana_list.length = 0;
9710 smb_LANadapter = LANA_INVALID;
9713 lock_ReleaseMutex(&smb_StartedLock);
9716 void smb_Init(osi_log_t *logp, int useV3,
9726 EVENT_HANDLE retHandle;
9727 char eventName[MAX_PATH];
9728 int startListeners = 0;
9730 smb_TlsRequestSlot = TlsAlloc();
9732 smb_MBfunc = aMBfunc;
9736 /* Initialize smb_localZero */
9737 myTime.tm_isdst = -1; /* compute whether on DST or not */
9738 myTime.tm_year = 70;
9744 smb_localZero = mktime(&myTime);
9746 #ifndef USE_NUMERIC_TIME_CONV
9747 /* Initialize kludge-GMT */
9748 smb_CalculateNowTZ();
9749 #endif /* USE_NUMERIC_TIME_CONV */
9750 #ifdef AFS_FREELANCE_CLIENT
9751 /* Make sure the root.afs volume has the correct time */
9752 cm_noteLocalMountPointChange();
9755 /* initialize the remote debugging log */
9758 /* and the global lock */
9759 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9760 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9762 /* Raw I/O data structures */
9763 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9765 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9766 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9768 /* 4 Raw I/O buffers */
9769 smb_RawBufs = calloc(65536,1);
9770 *((char **)smb_RawBufs) = NULL;
9771 for (i=0; i<3; i++) {
9772 char *rawBuf = calloc(65536,1);
9773 *((char **)rawBuf) = smb_RawBufs;
9774 smb_RawBufs = rawBuf;
9777 /* global free lists */
9778 smb_ncbFreeListp = NULL;
9779 smb_packetFreeListp = NULL;
9781 lock_ObtainMutex(&smb_StartedLock);
9782 startListeners = smb_NetbiosInit(1);
9784 /* Initialize listener and server structures */
9786 memset(dead_sessions, 0, sizeof(dead_sessions));
9787 sprintf(eventName, "SessionEvents[0]");
9788 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9789 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9790 afsi_log("Event Object Already Exists: %s", eventName);
9792 smb_NumServerThreads = nThreads;
9793 sprintf(eventName, "NCBavails[0]");
9794 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9795 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9796 afsi_log("Event Object Already Exists: %s", eventName);
9797 sprintf(eventName, "NCBevents[0]");
9798 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9799 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9800 afsi_log("Event Object Already Exists: %s", eventName);
9801 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9802 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9803 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9804 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9805 afsi_log("Event Object Already Exists: %s", eventName);
9806 for (i = 0; i < smb_NumServerThreads; i++) {
9807 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9808 NCBreturns[i][0] = retHandle;
9811 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9812 for (i = 0; i < smb_NumServerThreads; i++) {
9813 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9814 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9815 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9816 afsi_log("Event Object Already Exists: %s", eventName);
9817 InitNCBslot((int)(i+1));
9819 numNCBs = smb_NumServerThreads + 1;
9821 /* Initialize dispatch table */
9822 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9823 /* Prepare the table for unknown operations */
9824 for(i=0; i<= SMB_NOPCODES; i++) {
9825 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9827 /* Fill in the ones we do know */
9828 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9829 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9830 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9831 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9832 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9833 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9834 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9835 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9836 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9837 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9838 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9839 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9840 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9841 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9842 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9843 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9844 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9845 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9846 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9847 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9848 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9849 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9850 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9851 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9852 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9853 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9854 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9855 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9856 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9857 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9858 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9859 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9860 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9861 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9862 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9863 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9864 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9865 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9866 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9867 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9868 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9869 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9870 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9871 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9872 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9873 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9874 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9875 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9876 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9877 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9878 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9879 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9880 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9881 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9882 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9883 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9884 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9885 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9886 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9887 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9888 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9889 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9890 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9891 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9892 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9893 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9894 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9895 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9896 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9897 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9898 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9899 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9900 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9901 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9903 /* setup tran 2 dispatch table */
9904 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9905 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9906 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9907 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9908 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9909 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9910 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9911 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9912 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9913 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9914 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9915 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9916 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9917 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9918 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9919 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9920 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9921 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9923 /* setup the rap dispatch table */
9924 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9925 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9926 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9927 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9928 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9932 /* if we are doing SMB authentication we have register outselves as a logon process */
9933 if (smb_authType != SMB_AUTH_NONE) {
9934 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9935 LSA_STRING afsProcessName;
9936 LSA_OPERATIONAL_MODE dummy; /*junk*/
9938 afsProcessName.Buffer = "OpenAFSClientDaemon";
9939 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9940 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9942 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9944 if (nts == STATUS_SUCCESS) {
9945 LSA_STRING packageName;
9946 /* we are registered. Find out the security package id */
9947 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9948 packageName.Length = (USHORT)strlen(packageName.Buffer);
9949 packageName.MaximumLength = packageName.Length + 1;
9950 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9951 if (nts == STATUS_SUCCESS) {
9953 * This code forces Windows to authenticate against the Logon Cache
9954 * first instead of attempting to authenticate against the Domain
9955 * Controller. When the Windows logon cache is enabled this improves
9956 * performance by removing the network access and works around a bug
9957 * seen at sites which are using a MIT Kerberos principal to login
9958 * to machines joined to a non-root domain in a multi-domain forest.
9959 * MsV1_0SetProcessOption was added in Windows XP.
9961 PVOID pResponse = NULL;
9962 ULONG cbResponse = 0;
9963 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9965 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9966 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9967 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9968 OptionsRequest.DisableOptions = FALSE;
9970 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9973 sizeof(OptionsRequest),
9979 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9980 char message[AFSPATHMAX];
9981 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9983 OutputDebugString(message);
9986 OutputDebugString("MsV1_0SetProcessOption success");
9987 afsi_log("MsV1_0SetProcessOption success");
9989 /* END - code from Larry */
9991 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9992 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9993 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9995 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9997 /* something went wrong. We report the error and revert back to no authentication
9998 because we can't perform any auth requests without a successful lsa handle
9999 or sec package id. */
10000 afsi_log("Reverting to NO SMB AUTH");
10001 smb_authType = SMB_AUTH_NONE;
10004 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10006 /* something went wrong. We report the error and revert back to no authentication
10007 because we can't perform any auth requests without a successful lsa handle
10008 or sec package id. */
10009 afsi_log("Reverting to NO SMB AUTH");
10010 smb_authType = SMB_AUTH_NONE;
10014 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10015 * time prevents the failure of authentication when logged into Windows with an
10016 * external Kerberos principal mapped to a local account.
10018 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10019 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10020 * then the only option is NTLMSSP anyway; so just fallback.
10025 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10026 if (secBlobLength == 0) {
10027 smb_authType = SMB_AUTH_NTLM;
10028 afsi_log("Reverting to SMB AUTH NTLM");
10037 /* Now get ourselves a domain name. */
10038 /* For now we are using the local computer name as the domain name.
10039 * It is actually the domain for local logins, and we are acting as
10040 * a local SMB server.
10042 bufsize = lengthof(smb_ServerDomainName) - 1;
10043 GetComputerNameW(smb_ServerDomainName, &bufsize);
10044 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10045 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10048 /* Start listeners, waiters, servers, and daemons */
10049 if (startListeners)
10050 smb_StartListeners(1);
10052 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10053 NULL, 0, &lpid, "smb_ClientWaiter");
10054 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10055 thrd_CloseHandle(phandle);
10057 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10058 NULL, 0, &lpid, "smb_ServerWaiter");
10059 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10060 thrd_CloseHandle(phandle);
10062 for (i=0; i<smb_NumServerThreads; i++) {
10063 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10064 (void *) i, 0, &lpid, "smb_Server");
10065 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10066 thrd_CloseHandle(phandle);
10069 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10070 NULL, 0, &lpid, "smb_Daemon");
10071 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10072 thrd_CloseHandle(phandle);
10074 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10075 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10076 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10077 thrd_CloseHandle(phandle);
10079 lock_ReleaseMutex(&smb_StartedLock);
10083 void smb_Shutdown(void)
10090 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10092 /* setup the NCB system */
10093 ncbp = smb_GetNCB();
10095 /* Block new sessions by setting shutdown flag */
10096 smbShutdownFlag = 1;
10098 /* Hang up all sessions */
10099 memset((char *)ncbp, 0, sizeof(NCB));
10100 for (i = 1; i < numSessions; i++)
10102 if (dead_sessions[i])
10105 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10106 ncbp->ncb_command = NCBHANGUP;
10107 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10108 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10109 code = Netbios(ncbp);
10110 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10111 if (code == 0) code = ncbp->ncb_retcode;
10113 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10114 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10118 /* Trigger the shutdown of all SMB threads */
10119 for (i = 0; i < smb_NumServerThreads; i++)
10120 thrd_SetEvent(NCBreturns[i][0]);
10122 thrd_SetEvent(NCBevents[0]);
10123 thrd_SetEvent(SessionEvents[0]);
10124 thrd_SetEvent(NCBavails[0]);
10126 for (i = 0;i < smb_NumServerThreads; i++) {
10127 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10128 if (code == WAIT_OBJECT_0) {
10131 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10132 thrd_SetEvent(NCBreturns[i--][0]);
10136 /* Delete Netbios name */
10137 memset((char *)ncbp, 0, sizeof(NCB));
10138 for (i = 0; i < lana_list.length; i++) {
10139 if (lana_list.lana[i] == LANA_INVALID) continue;
10140 ncbp->ncb_command = NCBDELNAME;
10141 ncbp->ncb_lana_num = lana_list.lana[i];
10142 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10143 code = Netbios(ncbp);
10145 code = ncbp->ncb_retcode;
10147 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10148 ncbp->ncb_lana_num, code);
10153 /* Release the reference counts held by the VCs */
10154 lock_ObtainWrite(&smb_rctLock);
10155 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10160 if (vcp->magic != SMB_VC_MAGIC)
10161 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10162 __FILE__, __LINE__);
10164 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10166 if (fidp->scp != NULL) {
10169 lock_ReleaseWrite(&smb_rctLock);
10170 lock_ObtainMutex(&fidp->mx);
10171 if (fidp->scp != NULL) {
10174 lock_ObtainWrite(&scp->rw);
10175 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10176 lock_ReleaseWrite(&scp->rw);
10177 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10178 cm_ReleaseSCache(scp);
10180 lock_ReleaseMutex(&fidp->mx);
10181 lock_ObtainWrite(&smb_rctLock);
10185 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10187 smb_ReleaseVCNoLock(tidp->vcp);
10189 cm_user_t *userp = tidp->userp;
10190 tidp->userp = NULL;
10191 cm_ReleaseUser(userp);
10195 lock_ReleaseWrite(&smb_rctLock);
10197 TlsFree(smb_TlsRequestSlot);
10200 /* Get the UNC \\<servername>\<sharename> prefix. */
10201 char *smb_GetSharename()
10206 /* Make sure we have been properly initialized. */
10207 if (smb_localNamep == NULL)
10210 /* Allocate space for \\<servername>\<sharename>, plus the
10213 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10214 name = malloc(len);
10215 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10221 void smb_LogPacket(smb_packet_t *packet)
10225 unsigned length, paramlen, datalen, i, j;
10227 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10229 if (!packet) return;
10231 osi_Log0(smb_logp, "*** SMB packet dump ***");
10233 smbp = (smb_t *) packet->data;
10234 vp = (BYTE *) packet->data;
10236 paramlen = smbp->wct * 2;
10237 datalen = *((WORD *) (smbp->vdata + paramlen));
10238 length = sizeof(*smbp) + paramlen + 1 + datalen;
10240 for (i=0;i < length; i+=16)
10242 memset( buf, ' ', 80 );
10245 itoa( i, buf, 16 );
10247 buf[strlen(buf)] = ' ';
10249 cp = (BYTE*) buf + 7;
10251 for (j=0;j < 16 && (i+j)<length; j++)
10253 *(cp++) = hex[vp[i+j] >> 4];
10254 *(cp++) = hex[vp[i+j] & 0xf];
10264 for (j=0;j < 16 && (i+j)<length;j++)
10266 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10277 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10280 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10282 #endif /* LOG_PACKET */
10285 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10291 smb_username_t *unp;
10292 smb_waitingLockRequest_t *wlrp;
10295 lock_ObtainRead(&smb_rctLock);
10297 sprintf(output, "begin dumping smb_username_t\r\n");
10298 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10299 for (unp = usernamesp; unp; unp=unp->nextp)
10301 cm_ucell_t *ucellp;
10303 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10304 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10305 unp->name ? unp->name : _C("NULL"),
10306 unp->machine ? unp->machine : _C("NULL"));
10307 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10309 sprintf(output, " begin dumping cm_ucell_t\r\n");
10310 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10312 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10313 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",
10314 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10315 ucellp->expirationTime, ucellp->gen,
10317 ucellp->cellp->name);
10318 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10321 sprintf(output, " done dumping cm_ucell_t\r\n");
10322 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10325 sprintf(output, "done dumping smb_username_t\r\n");
10326 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10329 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10330 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10333 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10334 smb_waitingLock_t *lockp;
10336 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10337 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10338 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10340 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10342 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10343 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10344 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10347 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10348 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10351 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10352 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10354 sprintf(output, "begin dumping smb_vc_t\r\n");
10355 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10357 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10363 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10364 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10365 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10367 sprintf(output, " begin dumping smb_user_t\r\n");
10368 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10369 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10370 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10371 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10372 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10374 sprintf(output, " done dumping smb_user_t\r\n");
10375 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10377 sprintf(output, " begin dumping smb_tid_t\r\n");
10378 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10379 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10380 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",
10381 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10382 tidp->pathname ? tidp->pathname : _C("NULL"));
10383 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10385 sprintf(output, " done dumping smb_tid_t\r\n");
10386 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10388 sprintf(output, " begin dumping smb_fid_t\r\n");
10389 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10391 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10393 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",
10394 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10395 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10396 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10397 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10400 sprintf(output, " done dumping smb_fid_t\r\n");
10401 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10404 sprintf(output, "done dumping smb_vc_t\r\n");
10405 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10407 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10408 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10410 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10416 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10417 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10418 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10420 sprintf(output, " begin dumping smb_user_t\r\n");
10421 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10422 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10423 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10424 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10425 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10427 sprintf(output, " done dumping smb_user_t\r\n");
10428 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10430 sprintf(output, " begin dumping smb_tid_t\r\n");
10431 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10432 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10433 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",
10434 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10435 tidp->pathname ? tidp->pathname : _C("NULL"));
10436 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10438 sprintf(output, " done dumping smb_tid_t\r\n");
10439 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10441 sprintf(output, " begin dumping smb_fid_t\r\n");
10442 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10444 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10446 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",
10447 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10448 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10449 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10450 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10453 sprintf(output, " done dumping smb_fid_t\r\n");
10454 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10457 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10458 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10461 lock_ReleaseRead(&smb_rctLock);
10465 long smb_IsNetworkStarted(void)
10468 lock_ObtainWrite(&smb_globalLock);
10469 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10470 lock_ReleaseWrite(&smb_globalLock);