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>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT\afsreg.h>
29 #include "lanahelper.h"
31 /* These characters are illegal in Windows filenames */
32 static char *illegalChars = "\\/:*?\"<>|";
34 int smbShutdownFlag = 0;
36 int smb_LogoffTokenTransfer;
37 time_t smb_LogoffTransferTimeout;
39 int smb_StoreAnsiFilenames = 0;
41 DWORD last_msg_time = 0;
45 unsigned int sessionGen = 0;
47 extern void afsi_log(char *pattern, ...);
48 extern HANDLE afsi_file;
50 osi_hyper_t hzero = {0, 0};
51 osi_hyper_t hones = {0xFFFFFFFF, -1};
54 osi_rwlock_t smb_globalLock;
55 osi_rwlock_t smb_rctLock;
56 osi_mutex_t smb_ListenerLock;
59 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
62 long smb_maxObsConcurrentCalls=0;
63 long smb_concurrentCalls=0;
65 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
67 smb_packet_t *smb_packetFreeListp;
68 smb_ncb_t *smb_ncbFreeListp;
70 int smb_NumServerThreads;
72 int numNCBs, numSessions, numVCs;
74 int smb_maxVCPerServer;
75 int smb_maxMpxRequests;
77 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
79 ULONG smb_lsaSecPackage;
80 LSA_STRING smb_lsaLogonOrigin;
82 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
83 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
84 EVENT_HANDLE **NCBreturns;
85 EVENT_HANDLE **NCBShutdown;
86 EVENT_HANDLE *smb_ServerShutdown;
87 DWORD NCBsessions[NCB_MAX];
89 struct smb_packet *bufs[NCB_MAX];
91 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
92 EVENT_HANDLE SessionEvents[SESSION_MAX];
93 unsigned short LSNs[SESSION_MAX];
94 int lanas[SESSION_MAX];
95 BOOL dead_sessions[SESSION_MAX];
99 osi_mutex_t smb_RawBufLock;
102 #define SMB_MASKFLAG_TILDE 1
103 #define SMB_MASKFLAG_CASEFOLD 2
105 #define RAWTIMEOUT INFINITE
108 typedef struct raw_write_cont {
117 /* dir search stuff */
118 long smb_dirSearchCounter = 1;
119 smb_dirSearch_t *smb_firstDirSearchp;
120 smb_dirSearch_t *smb_lastDirSearchp;
122 /* hide dot files? */
123 int smb_hideDotFiles;
125 /* global state about V3 protocols */
126 int smb_useV3; /* try to negotiate V3 */
128 static showErrors = 0;
129 /* MessageBox or something like it */
130 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
133 * Time in Unix format of midnight, 1/1/1970 local time.
134 * When added to dosUTime, gives Unix (AFS) time.
136 time_t smb_localZero = 0;
138 #define USE_NUMERIC_TIME_CONV 1
140 #ifndef USE_NUMERIC_TIME_CONV
141 /* Time difference for converting to kludge-GMT */
142 afs_uint32 smb_NowTZ;
143 #endif /* USE_NUMERIC_TIME_CONV */
145 char *smb_localNamep = NULL;
147 smb_vc_t *smb_allVCsp;
148 smb_vc_t *smb_deadVCsp;
150 smb_username_t *usernamesp = NULL;
152 smb_waitingLockRequest_t *smb_allWaitingLocks;
154 DWORD smb_TlsRequestSlot = -1;
157 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
158 NCB *ncbp, raw_write_cont_t *rwcp);
159 void smb_NetbiosInit();
162 void smb_LogPacket(smb_packet_t *packet);
163 #endif /* LOG_PACKET */
165 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
166 int smb_ServerDomainNameLength = 0;
167 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
168 int smb_ServerOSLength = sizeof(smb_ServerOS);
169 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
170 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
172 /* Faux server GUID. This is never checked. */
173 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
175 void smb_ResetServerPriority()
177 void * p = TlsGetValue(smb_TlsRequestSlot);
180 TlsSetValue(smb_TlsRequestSlot, NULL);
181 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
185 void smb_SetRequestStartTime()
187 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
189 tp = malloc(sizeof(time_t));
193 if (!TlsSetValue(smb_TlsRequestSlot, tp))
198 void smb_UpdateServerPriority()
200 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
203 time_t now = osi_Time();
205 /* Give one priority boost for each 15 seconds */
206 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
211 const char * ncb_error_string(int code)
215 case 0x01: s = "llegal buffer length"; break;
216 case 0x03: s = "illegal command"; break;
217 case 0x05: s = "command timed out"; break;
218 case 0x06: s = "message incomplete, issue another command"; break;
219 case 0x07: s = "illegal buffer address"; break;
220 case 0x08: s = "session number out of range"; break;
221 case 0x09: s = "no resource available"; break;
222 case 0x0a: s = "session closed"; break;
223 case 0x0b: s = "command cancelled"; break;
224 case 0x0d: s = "duplicate name"; break;
225 case 0x0e: s = "name table full"; break;
226 case 0x0f: s = "no deletions, name has active sessions"; break;
227 case 0x11: s = "local session table full"; break;
228 case 0x12: s = "remote session table full"; break;
229 case 0x13: s = "illegal name number"; break;
230 case 0x14: s = "no callname"; break;
231 case 0x15: s = "cannot put * in NCB_NAME"; break;
232 case 0x16: s = "name in use on remote adapter"; break;
233 case 0x17: s = "name deleted"; break;
234 case 0x18: s = "session ended abnormally"; break;
235 case 0x19: s = "name conflict detected"; break;
236 case 0x21: s = "interface busy, IRET before retrying"; break;
237 case 0x22: s = "too many commands outstanding, retry later";break;
238 case 0x23: s = "ncb_lana_num field invalid"; break;
239 case 0x24: s = "command completed while cancel occurring "; break;
240 case 0x26: s = "command not valid to cancel"; break;
241 case 0x30: s = "name defined by anther local process"; break;
242 case 0x34: s = "environment undefined. RESET required"; break;
243 case 0x35: s = "required OS resources exhausted"; break;
244 case 0x36: s = "max number of applications exceeded"; break;
245 case 0x37: s = "no saps available for netbios"; break;
246 case 0x38: s = "requested resources are not available"; break;
247 case 0x39: s = "invalid ncb address or length > segment"; break;
248 case 0x3B: s = "invalid NCB DDID"; break;
249 case 0x3C: s = "lock of user area failed"; break;
250 case 0x3f: s = "NETBIOS not loaded"; break;
251 case 0x40: s = "system error"; break;
252 default: s = "unknown error";
258 char * myCrt_Dispatch(int i)
263 return "(00)ReceiveCoreMakeDir";
265 return "(01)ReceiveCoreRemoveDir";
267 return "(02)ReceiveCoreOpen";
269 return "(03)ReceiveCoreCreate";
271 return "(04)ReceiveCoreClose";
273 return "(05)ReceiveCoreFlush";
275 return "(06)ReceiveCoreUnlink";
277 return "(07)ReceiveCoreRename";
279 return "(08)ReceiveCoreGetFileAttributes";
281 return "(09)ReceiveCoreSetFileAttributes";
283 return "(0a)ReceiveCoreRead";
285 return "(0b)ReceiveCoreWrite";
287 return "(0c)ReceiveCoreLockRecord";
289 return "(0d)ReceiveCoreUnlockRecord";
291 return "(0e)SendCoreBadOp";
293 return "(0f)ReceiveCoreCreate";
295 return "(10)ReceiveCoreCheckPath";
297 return "(11)SendCoreBadOp";
299 return "(12)ReceiveCoreSeek";
301 return "(1a)ReceiveCoreReadRaw";
303 return "(1d)ReceiveCoreWriteRawDummy";
305 return "(22)ReceiveV3SetAttributes";
307 return "(23)ReceiveV3GetAttributes";
309 return "(24)ReceiveV3LockingX";
311 return "(25)ReceiveV3Trans";
313 return "(26)ReceiveV3Trans[aux]";
315 return "(29)SendCoreBadOp";
317 return "(2b)ReceiveCoreEcho";
319 return "(2d)ReceiveV3OpenX";
321 return "(2e)ReceiveV3ReadX";
323 return "(2f)ReceiveV3WriteX";
325 return "(32)ReceiveV3Tran2A";
327 return "(33)ReceiveV3Tran2A[aux]";
329 return "(34)ReceiveV3FindClose";
331 return "(35)ReceiveV3FindNotifyClose";
333 return "(70)ReceiveCoreTreeConnect";
335 return "(71)ReceiveCoreTreeDisconnect";
337 return "(72)ReceiveNegotiate";
339 return "(73)ReceiveV3SessionSetupX";
341 return "(74)ReceiveV3UserLogoffX";
343 return "(75)ReceiveV3TreeConnectX";
345 return "(80)ReceiveCoreGetDiskAttributes";
347 return "(81)ReceiveCoreSearchDir";
351 return "(83)FindUnique";
353 return "(84)FindClose";
355 return "(A0)ReceiveNTTransact";
357 return "(A2)ReceiveNTCreateX";
359 return "(A4)ReceiveNTCancel";
361 return "(A5)ReceiveNTRename";
363 return "(C0)OpenPrintFile";
365 return "(C1)WritePrintFile";
367 return "(C2)ClosePrintFile";
369 return "(C3)GetPrintQueue";
371 return "(D8)ReadBulk";
373 return "(D9)WriteBulk";
375 return "(DA)WriteBulkData";
377 return "unknown SMB op";
381 char * myCrt_2Dispatch(int i)
386 return "unknown SMB op-2";
388 return "S(00)CreateFile_ReceiveTran2Open";
390 return "S(01)FindFirst_ReceiveTran2SearchDir";
392 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
394 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
396 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
398 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
400 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
402 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
404 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
406 return "S(09)_ReceiveTran2FSCTL";
408 return "S(0a)_ReceiveTran2IOCTL";
410 return "S(0b)_ReceiveTran2FindNotifyFirst";
412 return "S(0c)_ReceiveTran2FindNotifyNext";
414 return "S(0d)_ReceiveTran2CreateDirectory";
416 return "S(0e)_ReceiveTran2SessionSetup";
418 return "S(0f)_QueryFileSystemInformationFid";
420 return "S(10)_ReceiveTran2GetDfsReferral";
422 return "S(11)_ReceiveTran2ReportDfsInconsistency";
426 char * myCrt_RapDispatch(int i)
431 return "unknown RAP OP";
433 return "RAP(0)NetShareEnum";
435 return "RAP(1)NetShareGetInfo";
437 return "RAP(13)NetServerGetInfo";
439 return "RAP(63)NetWkStaGetInfo";
443 /* scache must be locked */
444 unsigned int smb_Attributes(cm_scache_t *scp)
448 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
449 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
450 scp->fileType == CM_SCACHETYPE_INVALID)
452 attrs = SMB_ATTR_DIRECTORY;
453 #ifdef SPECIAL_FOLDERS
454 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
455 #endif /* SPECIAL_FOLDERS */
456 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
457 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
462 * We used to mark a file RO if it was in an RO volume, but that
463 * turns out to be impolitic in NT. See defect 10007.
466 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
467 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
469 if ((scp->unixModeBits & 0222) == 0)
470 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 /* Check if the named file/dir is a dotfile/dotdir */
477 /* String pointed to by lastComp can have leading slashes, but otherwise should have
478 no other patch components */
479 unsigned int smb_IsDotFile(char *lastComp) {
482 /* skip over slashes */
483 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
488 /* nulls, curdir and parent dir doesn't count */
494 if(*(s+1) == '.' && !*(s + 2))
501 static int ExtractBits(WORD bits, short start, short len)
508 num = bits << (16 - end);
509 num = num >> ((16 - end) + start);
514 void ShowUnixTime(char *FuncName, time_t unixTime)
519 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
521 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
522 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
524 int day, month, year, sec, min, hour;
527 day = ExtractBits(wDate, 0, 5);
528 month = ExtractBits(wDate, 5, 4);
529 year = ExtractBits(wDate, 9, 7) + 1980;
531 sec = ExtractBits(wTime, 0, 5);
532 min = ExtractBits(wTime, 5, 6);
533 hour = ExtractBits(wTime, 11, 5);
535 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
536 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
540 /* Determine if we are observing daylight savings time */
541 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
543 TIME_ZONE_INFORMATION timeZoneInformation;
544 SYSTEMTIME utc, local, localDST;
546 /* Get the time zone info. NT uses this to calc if we are in DST. */
547 GetTimeZoneInformation(&timeZoneInformation);
549 /* Return the daylight bias */
550 *pDstBias = timeZoneInformation.DaylightBias;
552 /* Return the bias */
553 *pBias = timeZoneInformation.Bias;
555 /* Now determine if DST is being observed */
557 /* Get the UTC (GMT) time */
560 /* Convert UTC time to local time using the time zone info. If we are
561 observing DST, the calculated local time will include this.
563 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
565 /* Set the daylight bias to 0. The daylight bias is the amount of change
566 * in time that we use for daylight savings time. By setting this to 0
567 * we cause there to be no change in time during daylight savings time.
569 timeZoneInformation.DaylightBias = 0;
571 /* Convert the utc time to local time again, but this time without any
572 adjustment for daylight savings time.
574 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
576 /* If the two times are different, then it means that the localDST that
577 we calculated includes the daylight bias, and therefore we are
578 observing daylight savings time.
580 *pDST = localDST.wHour != local.wHour;
584 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
586 BOOL dst; /* Will be TRUE if observing DST */
587 LONG dstBias; /* Offset from local time if observing DST */
588 LONG bias; /* Offset from GMT for local time */
591 * This function will adjust the last write time to compensate
592 * for two bugs in the smb client:
594 * 1) During Daylight Savings Time, the LastWriteTime is ahead
595 * in time by the DaylightBias (ignoring the sign - the
596 * DaylightBias is always stored as a negative number). If
597 * the DaylightBias is -60, then the LastWriteTime will be
598 * ahead by 60 minutes.
600 * 2) If the local time zone is a positive offset from GMT, then
601 * the LastWriteTime will be the correct local time plus the
602 * Bias (ignoring the sign - a positive offset from GMT is
603 * always stored as a negative Bias). If the Bias is -120,
604 * then the LastWriteTime will be ahead by 120 minutes.
606 * These bugs can occur at the same time.
609 GetTimeZoneInfo(&dst, &dstBias, &bias);
611 /* First adjust for DST */
613 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
615 /* Now adjust for a positive offset from GMT (a negative bias). */
617 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
620 #ifndef USE_NUMERIC_TIME_CONV
622 * Calculate the difference (in seconds) between local time and GMT.
623 * This enables us to convert file times to kludge-GMT.
629 struct tm gmt_tm, local_tm;
630 int days, hours, minutes, seconds;
633 gmt_tm = *(gmtime(&t));
634 local_tm = *(localtime(&t));
636 days = local_tm.tm_yday - gmt_tm.tm_yday;
637 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
638 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
639 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
643 #endif /* USE_NUMERIC_TIME_CONV */
645 #ifdef USE_NUMERIC_TIME_CONV
646 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
648 // Note that LONGLONG is a 64-bit value
651 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
652 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
653 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
656 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
661 time_t ersatz_unixTime;
664 * Must use kludge-GMT instead of real GMT.
665 * kludge-GMT is computed by adding time zone difference to localtime.
668 * ltp = gmtime(&unixTime);
670 ersatz_unixTime = unixTime - smb_NowTZ;
671 ltp = localtime(&ersatz_unixTime);
673 /* if we fail, make up something */
676 localJunk.tm_year = 89 - 20;
677 localJunk.tm_mon = 4;
678 localJunk.tm_mday = 12;
679 localJunk.tm_hour = 0;
680 localJunk.tm_min = 0;
681 localJunk.tm_sec = 0;
684 stm.wYear = ltp->tm_year + 1900;
685 stm.wMonth = ltp->tm_mon + 1;
686 stm.wDayOfWeek = ltp->tm_wday;
687 stm.wDay = ltp->tm_mday;
688 stm.wHour = ltp->tm_hour;
689 stm.wMinute = ltp->tm_min;
690 stm.wSecond = ltp->tm_sec;
691 stm.wMilliseconds = 0;
693 SystemTimeToFileTime(&stm, largeTimep);
695 #endif /* USE_NUMERIC_TIME_CONV */
697 #ifdef USE_NUMERIC_TIME_CONV
698 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
700 // Note that LONGLONG is a 64-bit value
703 ll = largeTimep->dwHighDateTime;
705 ll += largeTimep->dwLowDateTime;
707 ll -= 116444736000000000;
710 *unixTimep = (DWORD)ll;
712 #else /* USE_NUMERIC_TIME_CONV */
713 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
719 FileTimeToSystemTime(largeTimep, &stm);
721 lt.tm_year = stm.wYear - 1900;
722 lt.tm_mon = stm.wMonth - 1;
723 lt.tm_wday = stm.wDayOfWeek;
724 lt.tm_mday = stm.wDay;
725 lt.tm_hour = stm.wHour;
726 lt.tm_min = stm.wMinute;
727 lt.tm_sec = stm.wSecond;
730 save_timezone = _timezone;
731 _timezone += smb_NowTZ;
732 *unixTimep = mktime(<);
733 _timezone = save_timezone;
735 #endif /* USE_NUMERIC_TIME_CONV */
737 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
747 /* if we fail, make up something */
750 localJunk.tm_year = 89 - 20;
751 localJunk.tm_mon = 4;
752 localJunk.tm_mday = 12;
753 localJunk.tm_hour = 0;
754 localJunk.tm_min = 0;
755 localJunk.tm_sec = 0;
758 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
759 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
760 *searchTimep = (dosDate<<16) | dosTime;
763 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
765 unsigned short dosDate;
766 unsigned short dosTime;
769 dosDate = (unsigned short) (searchTime & 0xffff);
770 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
772 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
773 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
774 localTm.tm_mday = (dosDate) & 0x1f;
775 localTm.tm_hour = (dosTime>>11) & 0x1f;
776 localTm.tm_min = (dosTime >> 5) & 0x3f;
777 localTm.tm_sec = (dosTime & 0x1f) * 2;
778 localTm.tm_isdst = -1; /* compute whether DST in effect */
780 *unixTimep = mktime(&localTm);
783 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
785 time_t diff_t = unixTime - smb_localZero;
786 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
787 osi_assert(diff_t < _UI32_MAX);
789 *dosUTimep = (afs_uint32)diff_t;
792 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
794 *unixTimep = dosTime + smb_localZero;
797 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
801 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
802 lock_ObtainWrite(&smb_rctLock);
803 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
804 if (vcp->magic != SMB_VC_MAGIC)
805 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
808 if (lsn == vcp->lsn && lana == vcp->lana &&
809 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
810 smb_HoldVCNoLock(vcp);
814 if (!vcp && (flags & SMB_FLAG_CREATE)) {
815 vcp = malloc(sizeof(*vcp));
816 memset(vcp, 0, sizeof(*vcp));
817 vcp->vcID = ++numVCs;
818 vcp->magic = SMB_VC_MAGIC;
819 vcp->refCount = 2; /* smb_allVCsp and caller */
822 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
823 vcp->nextp = smb_allVCsp;
825 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
830 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
831 /* We must obtain a challenge for extended auth
832 * in case the client negotiates smb v3
834 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
835 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
836 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
837 ULONG lsaRespSize = 0;
839 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
841 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
848 if (nts != STATUS_SUCCESS)
849 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
850 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
851 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
853 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
854 LsaFreeReturnBuffer(lsaResp);
857 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
859 if (numVCs >= CM_SESSION_RESERVED) {
861 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
864 lock_ReleaseWrite(&smb_rctLock);
865 lock_ReleaseWrite(&smb_globalLock);
869 int smb_IsStarMask(char *maskp)
874 for(i=0; i<11; i++) {
876 if (tc == '?' || tc == '*' || tc == '>')
882 void smb_ReleaseVCInternal(smb_vc_t *vcp)
889 if (vcp->refCount == 0) {
890 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
891 /* remove VCP from smb_deadVCsp */
892 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
898 lock_FinalizeMutex(&vcp->mx);
899 memset(vcp,0,sizeof(smb_vc_t));
902 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
906 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
907 avcp?"not ":"",vcp, vcp->refCount);
909 GenerateMiniDump(NULL);
911 /* This is a wrong. However, I suspect that there is an undercount
912 * and I don't want to release 1.4.1 in a state that will allow
913 * smb_vc_t objects to be deallocated while still in the
914 * smb_allVCsp list. The list is supposed to keep a reference
915 * to the smb_vc_t. Put it back.
922 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
924 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
925 smb_ReleaseVCInternal(vcp);
928 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 void smb_HoldVCNoLock(smb_vc_t *vcp)
939 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
942 void smb_HoldVC(smb_vc_t *vcp)
944 lock_ObtainWrite(&smb_rctLock);
946 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
947 lock_ReleaseWrite(&smb_rctLock);
950 void smb_CleanupDeadVC(smb_vc_t *vcp)
958 smb_user_t *uidpIter;
959 smb_user_t *uidpNext;
963 lock_ObtainMutex(&vcp->mx);
964 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
965 lock_ReleaseMutex(&vcp->mx);
966 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
969 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
970 lock_ReleaseMutex(&vcp->mx);
971 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
973 lock_ObtainWrite(&smb_rctLock);
974 /* remove VCP from smb_allVCsp */
975 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
976 if ((*vcpp)->magic != SMB_VC_MAGIC)
977 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
981 vcp->nextp = smb_deadVCsp;
983 /* Hold onto the reference until we are done with this function */
988 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
989 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
991 if (fidpIter->delete)
995 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
997 smb_HoldFIDNoLock(fidpIter);
998 lock_ReleaseWrite(&smb_rctLock);
1000 smb_CloseFID(vcp, fidpIter, NULL, 0);
1001 smb_ReleaseFID(fidpIter);
1003 lock_ObtainWrite(&smb_rctLock);
1004 fidpNext = vcp->fidsp;
1007 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1008 tidpNext = tidpIter->nextp;
1009 if (tidpIter->delete)
1011 tidpIter->delete = 1;
1013 tid = tidpIter->tid;
1014 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1016 smb_HoldTIDNoLock(tidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_ReleaseTID(tidpIter);
1021 lock_ObtainWrite(&smb_rctLock);
1022 tidpNext = vcp->tidsp;
1025 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1026 uidpNext = uidpIter->nextp;
1027 if (uidpIter->delete)
1029 uidpIter->delete = 1;
1031 /* do not add an additional reference count for the smb_user_t
1032 * as the smb_vc_t already is holding a reference */
1033 lock_ReleaseWrite(&smb_rctLock);
1035 smb_ReleaseUID(uidpIter);
1037 lock_ObtainWrite(&smb_rctLock);
1038 uidpNext = vcp->usersp;
1041 /* The vcp is now on the deadVCsp list. We intentionally drop the
1042 * reference so that the refcount can reach 0 and we can delete it */
1043 smb_ReleaseVCNoLock(vcp);
1045 lock_ReleaseWrite(&smb_rctLock);
1046 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1049 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1053 lock_ObtainWrite(&smb_rctLock);
1055 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1056 if (tidp->refCount == 0 && tidp->delete) {
1058 lock_ReleaseWrite(&smb_rctLock);
1059 smb_ReleaseTID(tidp);
1060 lock_ObtainWrite(&smb_rctLock);
1064 if (tid == tidp->tid) {
1069 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1070 tidp = malloc(sizeof(*tidp));
1071 memset(tidp, 0, sizeof(*tidp));
1072 tidp->nextp = vcp->tidsp;
1075 smb_HoldVCNoLock(vcp);
1077 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1080 lock_ReleaseWrite(&smb_rctLock);
1084 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1089 void smb_ReleaseTID(smb_tid_t *tidp)
1096 lock_ObtainWrite(&smb_rctLock);
1097 osi_assert(tidp->refCount-- > 0);
1098 if (tidp->refCount == 0 && (tidp->delete)) {
1099 ltpp = &tidp->vcp->tidsp;
1100 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1104 osi_assert(tp != NULL);
1106 lock_FinalizeMutex(&tidp->mx);
1107 userp = tidp->userp; /* remember to drop ref later */
1109 smb_ReleaseVCNoLock(tidp->vcp);
1112 lock_ReleaseWrite(&smb_rctLock);
1114 cm_ReleaseUser(userp);
1117 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1119 smb_user_t *uidp = NULL;
1121 lock_ObtainWrite(&smb_rctLock);
1122 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1123 if (uid == uidp->userID) {
1125 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1127 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1131 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1132 uidp = malloc(sizeof(*uidp));
1133 memset(uidp, 0, sizeof(*uidp));
1134 uidp->nextp = vcp->usersp;
1135 uidp->refCount = 2; /* one for the vcp and one for the caller */
1137 smb_HoldVCNoLock(vcp);
1139 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1141 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1143 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1145 lock_ReleaseWrite(&smb_rctLock);
1149 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1151 smb_username_t *unp= NULL;
1153 lock_ObtainWrite(&smb_rctLock);
1154 for(unp = usernamesp; unp; unp = unp->nextp) {
1155 if (stricmp(unp->name, usern) == 0 &&
1156 stricmp(unp->machine, machine) == 0) {
1161 if (!unp && (flags & SMB_FLAG_CREATE)) {
1162 unp = malloc(sizeof(*unp));
1163 memset(unp, 0, sizeof(*unp));
1165 unp->nextp = usernamesp;
1166 unp->name = strdup(usern);
1167 unp->machine = strdup(machine);
1169 lock_InitializeMutex(&unp->mx, "username_t mutex");
1170 if (flags & SMB_FLAG_AFSLOGON)
1171 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1174 lock_ReleaseWrite(&smb_rctLock);
1178 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1180 smb_user_t *uidp= NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1186 if (stricmp(uidp->unp->name, usern) == 0) {
1188 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1189 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1194 lock_ReleaseWrite(&smb_rctLock);
1198 void smb_ReleaseUsername(smb_username_t *unp)
1201 smb_username_t **lupp;
1202 cm_user_t *userp = NULL;
1203 time_t now = osi_Time();
1205 lock_ObtainWrite(&smb_rctLock);
1206 osi_assert(unp->refCount-- > 0);
1207 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1208 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1210 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1214 osi_assert(up != NULL);
1216 up->nextp = NULL; /* do not remove this */
1217 lock_FinalizeMutex(&unp->mx);
1223 lock_ReleaseWrite(&smb_rctLock);
1226 cm_ReleaseUser(userp);
1230 void smb_HoldUIDNoLock(smb_user_t *uidp)
1235 void smb_ReleaseUID(smb_user_t *uidp)
1239 smb_username_t *unp = NULL;
1241 lock_ObtainWrite(&smb_rctLock);
1242 osi_assert(uidp->refCount-- > 0);
1243 if (uidp->refCount == 0) {
1244 lupp = &uidp->vcp->usersp;
1245 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1249 osi_assert(up != NULL);
1251 lock_FinalizeMutex(&uidp->mx);
1253 smb_ReleaseVCNoLock(uidp->vcp);
1257 lock_ReleaseWrite(&smb_rctLock);
1261 cm_ReleaseUserVCRef(unp->userp);
1262 smb_ReleaseUsername(unp);
1266 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1268 cm_user_t *up = NULL;
1273 lock_ObtainMutex(&uidp->mx);
1275 up = uidp->unp->userp;
1278 lock_ReleaseMutex(&uidp->mx);
1284 /* retrieve a held reference to a user structure corresponding to an incoming
1286 * corresponding release function is cm_ReleaseUser.
1288 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1291 cm_user_t *up = NULL;
1294 smbp = (smb_t *) inp;
1295 uidp = smb_FindUID(vcp, smbp->uid, 0);
1299 up = smb_GetUserFromUID(uidp);
1301 smb_ReleaseUID(uidp);
1306 * Return a pointer to a pathname extracted from a TID structure. The
1307 * TID structure is not held; assume it won't go away.
1309 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1314 tidp = smb_FindTID(vcp, tid, 0);
1318 if (tidp->flags & SMB_TIDFLAG_IPC) {
1319 code = CM_ERROR_TIDIPC;
1320 /* tidp->pathname would be NULL, but that's fine */
1322 *treepath = tidp->pathname;
1323 smb_ReleaseTID(tidp);
1328 /* check to see if we have a chained fid, that is, a fid that comes from an
1329 * OpenAndX message that ran earlier in this packet. In this case, the fid
1330 * field in a read, for example, request, isn't set, since the value is
1331 * supposed to be inherited from the openAndX call.
1333 int smb_ChainFID(int fid, smb_packet_t *inp)
1335 if (inp->fid == 0 || inp->inCount == 0)
1341 /* are we a priv'd user? What does this mean on NT? */
1342 int smb_SUser(cm_user_t *userp)
1347 /* find a file ID. If we pass in 0 we select an unused File ID.
1348 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1349 * smb_fid_t data structure if desired File ID cannot be found.
1351 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1356 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1359 lock_ObtainWrite(&smb_rctLock);
1360 /* figure out if we need to allocate a new file ID */
1363 fid = vcp->fidCounter;
1367 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1368 if (fidp->refCount == 0 && fidp->delete) {
1370 lock_ReleaseWrite(&smb_rctLock);
1371 smb_ReleaseFID(fidp);
1372 lock_ObtainWrite(&smb_rctLock);
1375 if (fid == fidp->fid) {
1378 if (fid == 0xFFFF) {
1380 "New FID number wraps on vcp 0x%x", vcp);
1390 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1391 char eventName[MAX_PATH];
1393 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1394 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1395 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1396 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1397 thrd_CloseHandle(event);
1399 if (fid == 0xFFFF) {
1400 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1406 fidp = malloc(sizeof(*fidp));
1407 memset(fidp, 0, sizeof(*fidp));
1408 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1411 smb_HoldVCNoLock(vcp);
1412 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1414 fidp->curr_chunk = fidp->prev_chunk = -2;
1415 fidp->raw_write_event = event;
1417 vcp->fidCounter = fid+1;
1418 if (vcp->fidCounter == 0xFFFF) {
1419 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1421 vcp->fidCounter = 1;
1426 lock_ReleaseWrite(&smb_rctLock);
1430 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1432 smb_fid_t *fidp = NULL;
1438 lock_ObtainWrite(&smb_rctLock);
1439 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1440 if (scp == fidp->scp) {
1445 lock_ReleaseWrite(&smb_rctLock);
1449 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1454 void smb_ReleaseFID(smb_fid_t *fidp)
1456 cm_scache_t *scp = NULL;
1457 cm_user_t *userp = NULL;
1458 smb_vc_t *vcp = NULL;
1459 smb_ioctl_t *ioctlp;
1461 lock_ObtainMutex(&fidp->mx);
1462 lock_ObtainWrite(&smb_rctLock);
1463 osi_assert(fidp->refCount-- > 0);
1464 if (fidp->refCount == 0 && (fidp->delete)) {
1467 scp = fidp->scp; /* release after lock is released */
1469 userp = fidp->userp;
1473 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1474 thrd_CloseHandle(fidp->raw_write_event);
1476 /* and see if there is ioctl stuff to free */
1477 ioctlp = fidp->ioctlp;
1480 cm_FreeSpace(ioctlp->prefix);
1481 if (ioctlp->inAllocp)
1482 free(ioctlp->inAllocp);
1483 if (ioctlp->outAllocp)
1484 free(ioctlp->outAllocp);
1487 lock_ReleaseMutex(&fidp->mx);
1488 lock_FinalizeMutex(&fidp->mx);
1492 smb_ReleaseVCNoLock(vcp);
1494 lock_ReleaseMutex(&fidp->mx);
1496 lock_ReleaseWrite(&smb_rctLock);
1498 /* now release the scache structure */
1500 cm_ReleaseSCache(scp);
1503 cm_ReleaseUser(userp);
1507 * Case-insensitive search for one string in another;
1508 * used to find variable names in submount pathnames.
1510 static char *smb_stristr(char *str1, char *str2)
1514 for (cursor = str1; *cursor; cursor++)
1515 if (stricmp(cursor, str2) == 0)
1522 * Substitute a variable value for its name in a submount pathname. Variable
1523 * name has been identified by smb_stristr() and is in substr. Variable name
1524 * length (plus one) is in substr_size. Variable value is in newstr.
1526 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1531 strcpy(temp, substr + substr_size - 1);
1532 strcpy(substr, newstr);
1536 char VNUserName[] = "%USERNAME%";
1537 char VNLCUserName[] = "%LCUSERNAME%";
1538 char VNComputerName[] = "%COMPUTERNAME%";
1539 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1542 typedef struct smb_findShare_rock {
1546 } smb_findShare_rock_t;
1548 #define SMB_FINDSHARE_EXACT_MATCH 1
1549 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1551 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1555 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1556 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1557 if(!stricmp(dep->name, vrock->shareName))
1558 matchType = SMB_FINDSHARE_EXACT_MATCH;
1560 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1561 if(vrock->match) free(vrock->match);
1562 vrock->match = strdup(dep->name);
1563 vrock->matchType = matchType;
1565 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1566 return CM_ERROR_STOPNOW;
1572 /* find a shareName in the table of submounts */
1573 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1577 char pathName[1024];
1584 DWORD allSubmount = 1;
1586 /* if allSubmounts == 0, only return the //mountRoot/all share
1587 * if in fact it has been been created in the subMounts table.
1588 * This is to allow sites that want to restrict access to the
1591 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1592 0, KEY_QUERY_VALUE, &parmKey);
1593 if (code == ERROR_SUCCESS) {
1594 len = sizeof(allSubmount);
1595 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1596 (BYTE *) &allSubmount, &len);
1597 if (code != ERROR_SUCCESS) {
1600 RegCloseKey (parmKey);
1603 if (allSubmount && _stricmp(shareName, "all") == 0) {
1608 /* In case, the all share is disabled we need to still be able
1609 * to handle ioctl requests
1611 if (_stricmp(shareName, "ioctl$") == 0) {
1612 *pathNamep = strdup("/.__ioctl__");
1616 if (_stricmp(shareName, "IPC$") == 0 ||
1617 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1618 _stricmp(shareName, "DESKTOP.INI") == 0
1624 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1625 0, KEY_QUERY_VALUE, &parmKey);
1626 if (code == ERROR_SUCCESS) {
1627 len = sizeof(pathName);
1628 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1629 (BYTE *) pathName, &len);
1630 if (code != ERROR_SUCCESS)
1632 RegCloseKey (parmKey);
1636 if (len != 0 && len != sizeof(pathName) - 1) {
1637 /* We can accept either unix or PC style AFS pathnames. Convert
1638 * Unix-style to PC style here for internal use.
1641 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1642 p += strlen(cm_mountRoot); /* skip mount path */
1645 if (*q == '/') *q = '\\'; /* change to \ */
1651 if (var = smb_stristr(p, VNUserName)) {
1652 if (uidp && uidp->unp)
1653 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1655 smb_subst(p, var, sizeof(VNUserName)," ");
1657 else if (var = smb_stristr(p, VNLCUserName))
1659 if (uidp && uidp->unp)
1660 strcpy(temp, uidp->unp->name);
1664 smb_subst(p, var, sizeof(VNLCUserName), temp);
1666 else if (var = smb_stristr(p, VNComputerName))
1668 sizeTemp = sizeof(temp);
1669 GetComputerName((LPTSTR)temp, &sizeTemp);
1670 smb_subst(p, var, sizeof(VNComputerName), temp);
1672 else if (var = smb_stristr(p, VNLCComputerName))
1674 sizeTemp = sizeof(temp);
1675 GetComputerName((LPTSTR)temp, &sizeTemp);
1677 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1682 *pathNamep = strdup(p);
1687 /* First lookup shareName in root.afs */
1689 smb_findShare_rock_t vrock;
1691 char * p = shareName;
1694 /* attempt to locate a partial match in root.afs. This is because
1695 when using the ANSI RAP calls, the share name is limited to 13 chars
1696 and hence is truncated. Of course we prefer exact matches. */
1698 thyper.HighPart = 0;
1701 vrock.shareName = shareName;
1703 vrock.matchType = 0;
1705 cm_HoldSCache(cm_data.rootSCachep);
1706 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1707 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1708 cm_ReleaseSCache(cm_data.rootSCachep);
1710 if (vrock.matchType) {
1711 sprintf(pathName,"/%s/",vrock.match);
1712 *pathNamep = strdup(strlwr(pathName));
1717 /* if we get here, there was no match for the share in root.afs */
1718 /* so try to create \\<netbiosName>\<cellname> */
1723 /* Get the full name for this cell */
1724 code = cm_SearchCellFile(p, temp, 0, 0);
1725 #ifdef AFS_AFSDB_ENV
1726 if (code && cm_dnsEnabled) {
1728 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1731 /* construct the path */
1733 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1734 *pathNamep = strdup(strlwr(pathName));
1743 /* Client-side offline caching policy types */
1744 #define CSC_POLICY_MANUAL 0
1745 #define CSC_POLICY_DOCUMENTS 1
1746 #define CSC_POLICY_PROGRAMS 2
1747 #define CSC_POLICY_DISABLE 3
1749 int smb_FindShareCSCPolicy(char *shareName)
1755 int retval = CSC_POLICY_MANUAL;
1757 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1758 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1761 REG_OPTION_NON_VOLATILE,
1767 len = sizeof(policy);
1768 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1770 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1772 else if (stricmp(policy, "documents") == 0)
1774 retval = CSC_POLICY_DOCUMENTS;
1776 else if (stricmp(policy, "programs") == 0)
1778 retval = CSC_POLICY_PROGRAMS;
1780 else if (stricmp(policy, "disable") == 0)
1782 retval = CSC_POLICY_DISABLE;
1785 RegCloseKey(hkCSCPolicy);
1789 /* find a dir search structure by cookie value, and return it held.
1790 * Must be called with smb_globalLock held.
1792 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1794 smb_dirSearch_t *dsp;
1796 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1797 if (dsp->cookie == cookie) {
1798 if (dsp != smb_firstDirSearchp) {
1799 /* move to head of LRU queue, too, if we're not already there */
1800 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1801 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1802 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1803 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1804 if (!smb_lastDirSearchp)
1805 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1807 lock_ObtainMutex(&dsp->mx);
1809 lock_ReleaseMutex(&dsp->mx);
1815 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1816 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1817 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1823 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1825 lock_ObtainWrite(&smb_globalLock);
1826 lock_ObtainMutex(&dsp->mx);
1827 dsp->flags |= SMB_DIRSEARCH_DELETE;
1828 if (dsp->scp != NULL) {
1829 lock_ObtainMutex(&dsp->scp->mx);
1830 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1831 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1832 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1833 dsp->scp->bulkStatProgress = hzero;
1835 lock_ReleaseMutex(&dsp->scp->mx);
1837 lock_ReleaseMutex(&dsp->mx);
1838 lock_ReleaseWrite(&smb_globalLock);
1841 /* Must be called with the smb_globalLock held */
1842 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1844 cm_scache_t *scp = NULL;
1846 lock_ObtainMutex(&dsp->mx);
1847 osi_assert(dsp->refCount-- > 0);
1848 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1849 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1850 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1851 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1852 lock_ReleaseMutex(&dsp->mx);
1853 lock_FinalizeMutex(&dsp->mx);
1857 lock_ReleaseMutex(&dsp->mx);
1859 /* do this now to avoid spurious locking hierarchy creation */
1861 cm_ReleaseSCache(scp);
1864 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1866 lock_ObtainWrite(&smb_globalLock);
1867 smb_ReleaseDirSearchNoLock(dsp);
1868 lock_ReleaseWrite(&smb_globalLock);
1871 /* find a dir search structure by cookie value, and return it held */
1872 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1874 smb_dirSearch_t *dsp;
1876 lock_ObtainWrite(&smb_globalLock);
1877 dsp = smb_FindDirSearchNoLock(cookie);
1878 lock_ReleaseWrite(&smb_globalLock);
1882 /* GC some dir search entries, in the address space expected by the specific protocol.
1883 * Must be called with smb_globalLock held; release the lock temporarily.
1885 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1886 void smb_GCDirSearches(int isV3)
1888 smb_dirSearch_t *prevp;
1889 smb_dirSearch_t *tp;
1890 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1894 victimCount = 0; /* how many have we got so far */
1895 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1896 /* we'll move tp from queue, so
1899 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1900 /* if no one is using this guy, and we're either in the new protocol,
1901 * or we're in the old one and this is a small enough ID to be useful
1902 * to the old protocol, GC this guy.
1904 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1905 /* hold and delete */
1906 lock_ObtainMutex(&tp->mx);
1907 tp->flags |= SMB_DIRSEARCH_DELETE;
1908 lock_ReleaseMutex(&tp->mx);
1909 victimsp[victimCount++] = tp;
1913 /* don't do more than this */
1914 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1918 /* now release them */
1919 for (i = 0; i < victimCount; i++) {
1920 smb_ReleaseDirSearchNoLock(victimsp[i]);
1924 /* function for allocating a dir search entry. We need these to remember enough context
1925 * since we don't get passed the path from call to call during a directory search.
1927 * Returns a held dir search structure, and bumps the reference count on the vnode,
1928 * since it saves a pointer to the vnode.
1930 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1932 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1941 /* what's the biggest ID allowed in this version of the protocol */
1942 maxAllowed = isV3 ? 65535 : 255;
1943 if (smb_dirSearchCounter > maxAllowed)
1944 smb_dirSearchCounter = 1;
1946 start = smb_dirSearchCounter;
1949 /* twice so we have enough tries to find guys we GC after one pass;
1950 * 10 extra is just in case I mis-counted.
1952 if (++counter > 2*maxAllowed+10)
1953 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1955 if (smb_dirSearchCounter > maxAllowed) {
1956 smb_dirSearchCounter = 1;
1958 if (smb_dirSearchCounter == start) {
1960 smb_GCDirSearches(isV3);
1963 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1965 /* don't need to watch for refcount zero and deleted, since
1966 * we haven't dropped the global lock.
1968 lock_ObtainMutex(&dsp->mx);
1970 lock_ReleaseMutex(&dsp->mx);
1971 ++smb_dirSearchCounter;
1975 dsp = malloc(sizeof(*dsp));
1976 memset(dsp, 0, sizeof(*dsp));
1977 dsp->cookie = smb_dirSearchCounter;
1978 ++smb_dirSearchCounter;
1980 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1981 dsp->lastTime = osi_Time();
1982 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1983 if (!smb_lastDirSearchp)
1984 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1987 lock_ReleaseWrite(&smb_globalLock);
1991 static smb_packet_t *GetPacket(void)
1995 lock_ObtainWrite(&smb_globalLock);
1996 tbp = smb_packetFreeListp;
1998 smb_packetFreeListp = tbp->nextp;
1999 lock_ReleaseWrite(&smb_globalLock);
2001 tbp = calloc(65540,1);
2002 tbp->magic = SMB_PACKETMAGIC;
2005 tbp->resumeCode = 0;
2011 tbp->ncb_length = 0;
2016 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2021 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2025 memcpy(tbp, pkt, sizeof(smb_packet_t));
2026 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2028 smb_HoldVC(tbp->vcp);
2032 static NCB *GetNCB(void)
2037 lock_ObtainWrite(&smb_globalLock);
2038 tbp = smb_ncbFreeListp;
2040 smb_ncbFreeListp = tbp->nextp;
2041 lock_ReleaseWrite(&smb_globalLock);
2043 tbp = calloc(sizeof(*tbp),1);
2044 tbp->magic = SMB_NCBMAGIC;
2047 osi_assert(tbp->magic == SMB_NCBMAGIC);
2049 memset(&tbp->ncb, 0, sizeof(NCB));
2054 void smb_FreePacket(smb_packet_t *tbp)
2056 smb_vc_t * vcp = NULL;
2057 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2059 lock_ObtainWrite(&smb_globalLock);
2060 tbp->nextp = smb_packetFreeListp;
2061 smb_packetFreeListp = tbp;
2062 tbp->magic = SMB_PACKETMAGIC;
2066 tbp->resumeCode = 0;
2072 tbp->ncb_length = 0;
2074 lock_ReleaseWrite(&smb_globalLock);
2080 static void FreeNCB(NCB *bufferp)
2084 tbp = (smb_ncb_t *) bufferp;
2085 osi_assert(tbp->magic == SMB_NCBMAGIC);
2087 lock_ObtainWrite(&smb_globalLock);
2088 tbp->nextp = smb_ncbFreeListp;
2089 smb_ncbFreeListp = tbp;
2090 lock_ReleaseWrite(&smb_globalLock);
2093 /* get a ptr to the data part of a packet, and its count */
2094 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2098 unsigned char *afterParmsp;
2100 parmBytes = *smbp->wctp << 1;
2101 afterParmsp = smbp->wctp + parmBytes + 1;
2103 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2104 if (nbytesp) *nbytesp = dataBytes;
2106 /* don't forget to skip the data byte count, since it follows
2107 * the parameters; that's where the "2" comes from below.
2109 return (unsigned char *) (afterParmsp + 2);
2112 /* must set all the returned parameters before playing around with the
2113 * data region, since the data region is located past the end of the
2114 * variable number of parameters.
2116 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2118 unsigned char *afterParmsp;
2120 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2122 *afterParmsp++ = dsize & 0xff;
2123 *afterParmsp = (dsize>>8) & 0xff;
2126 /* return the parm'th parameter in the smbp packet */
2127 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2130 unsigned char *parmDatap;
2132 parmCount = *smbp->wctp;
2134 if (parm >= parmCount) {
2137 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2138 parm, parmCount, smbp->ncb_length);
2139 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2140 parm, parmCount, smbp->ncb_length);
2141 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2142 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2143 osi_panic(s, __FILE__, __LINE__);
2145 parmDatap = smbp->wctp + (2*parm) + 1;
2147 return parmDatap[0] + (parmDatap[1] << 8);
2150 /* return the parm'th parameter in the smbp packet */
2151 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2154 unsigned char *parmDatap;
2156 parmCount = *smbp->wctp;
2158 if (parm + 1 >= parmCount) {
2161 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2162 parm, parmCount, smbp->ncb_length);
2163 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2164 parm, parmCount, smbp->ncb_length);
2165 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2166 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2167 osi_panic(s, __FILE__, __LINE__);
2169 parmDatap = smbp->wctp + (2*parm) + 1;
2171 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2174 /* return the parm'th parameter in the smbp packet */
2175 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2178 unsigned char *parmDatap;
2180 parmCount = *smbp->wctp;
2182 if (parm * 2 + offset >= parmCount * 2) {
2185 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2186 parm, offset, parmCount, smbp->ncb_length);
2187 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2188 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2189 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2190 parm, offset, parmCount, smbp->ncb_length);
2191 osi_panic(s, __FILE__, __LINE__);
2193 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2195 return parmDatap[0] + (parmDatap[1] << 8);
2198 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2202 /* make sure we have enough slots */
2203 if (*smbp->wctp <= slot)
2204 *smbp->wctp = slot+1;
2206 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2207 *parmDatap++ = parmValue & 0xff;
2208 *parmDatap = (parmValue>>8) & 0xff;
2211 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2215 /* make sure we have enough slots */
2216 if (*smbp->wctp <= slot)
2217 *smbp->wctp = slot+2;
2219 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2220 *parmDatap++ = parmValue & 0xff;
2221 *parmDatap++ = (parmValue>>8) & 0xff;
2222 *parmDatap++ = (parmValue>>16) & 0xff;
2223 *parmDatap = (parmValue>>24) & 0xff;
2226 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2231 /* make sure we have enough slots */
2232 if (*smbp->wctp <= slot)
2233 *smbp->wctp = slot+4;
2235 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2237 *parmDatap++ = *parmValuep++;
2240 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2244 /* make sure we have enough slots */
2245 if (*smbp->wctp <= slot) {
2246 if (smbp->oddByte) {
2248 *smbp->wctp = slot+1;
2253 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2254 *parmDatap++ = parmValue & 0xff;
2257 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2261 lastSlashp = strrchr(inPathp, '\\');
2263 *lastComponentp = lastSlashp;
2266 if (inPathp == lastSlashp)
2268 *outPathp++ = *inPathp++;
2277 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2282 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2287 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2293 tlen = inp[0] + (inp[1]<<8);
2294 inp += 2; /* skip length field */
2297 *chainpp = inp + tlen;
2306 /* format a packet as a response */
2307 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2312 outp = (smb_t *) op;
2314 /* zero the basic structure through the smb_wct field, and zero the data
2315 * size field, assuming that wct stays zero; otherwise, you have to
2316 * explicitly set the data size field, too.
2318 inSmbp = (smb_t *) inp;
2319 memset(outp, 0, sizeof(smb_t)+2);
2325 outp->com = inSmbp->com;
2326 outp->tid = inSmbp->tid;
2327 outp->pid = inSmbp->pid;
2328 outp->uid = inSmbp->uid;
2329 outp->mid = inSmbp->mid;
2330 outp->res[0] = inSmbp->res[0];
2331 outp->res[1] = inSmbp->res[1];
2332 op->inCom = inSmbp->com;
2334 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2335 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2337 /* copy fields in generic packet area */
2338 op->wctp = &outp->wct;
2341 /* send a (probably response) packet; vcp tells us to whom to send it.
2342 * we compute the length by looking at wct and bcc fields.
2344 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2358 memset((char *)ncbp, 0, sizeof(NCB));
2360 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2361 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2362 extra += tp[0] + (tp[1]<<8);
2363 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2364 extra += 3; /* wct and length fields */
2366 ncbp->ncb_length = extra; /* bytes to send */
2367 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2368 ncbp->ncb_lana_num = vcp->lana;
2369 ncbp->ncb_command = NCBSEND; /* op means send data */
2370 ncbp->ncb_buffer = (char *) inp;/* packet */
2371 code = Netbios(ncbp);
2374 const char * s = ncb_error_string(code);
2375 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2376 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2378 lock_ObtainMutex(&vcp->mx);
2379 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2380 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2382 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2383 lock_ReleaseMutex(&vcp->mx);
2384 lock_ObtainWrite(&smb_globalLock);
2385 dead_sessions[vcp->session] = TRUE;
2386 lock_ReleaseWrite(&smb_globalLock);
2387 smb_CleanupDeadVC(vcp);
2389 lock_ReleaseMutex(&vcp->mx);
2397 void smb_MapNTError(long code, unsigned long *NTStatusp)
2399 unsigned long NTStatus;
2401 /* map CM_ERROR_* errors to NT 32-bit status codes */
2402 /* NT Status codes are listed in ntstatus.h not winerror.h */
2403 if (code == CM_ERROR_NOSUCHCELL) {
2404 NTStatus = 0xC000000FL; /* No such file */
2406 else if (code == CM_ERROR_NOSUCHVOLUME) {
2407 NTStatus = 0xC000000FL; /* No such file */
2409 else if (code == CM_ERROR_TIMEDOUT) {
2411 NTStatus = 0xC00000CFL; /* Sharing Paused */
2413 NTStatus = 0x00000102L; /* Timeout */
2416 else if (code == CM_ERROR_RETRY) {
2417 NTStatus = 0xC000022DL; /* Retry */
2419 else if (code == CM_ERROR_NOACCESS) {
2420 NTStatus = 0xC0000022L; /* Access denied */
2422 else if (code == CM_ERROR_READONLY) {
2423 NTStatus = 0xC00000A2L; /* Write protected */
2425 else if (code == CM_ERROR_NOSUCHFILE) {
2426 NTStatus = 0xC000000FL; /* No such file */
2428 else if (code == CM_ERROR_NOSUCHPATH) {
2429 NTStatus = 0xC000003AL; /* Object path not found */
2431 else if (code == CM_ERROR_TOOBIG) {
2432 NTStatus = 0xC000007BL; /* Invalid image format */
2434 else if (code == CM_ERROR_INVAL) {
2435 NTStatus = 0xC000000DL; /* Invalid parameter */
2437 else if (code == CM_ERROR_BADFD) {
2438 NTStatus = 0xC0000008L; /* Invalid handle */
2440 else if (code == CM_ERROR_BADFDOP) {
2441 NTStatus = 0xC0000022L; /* Access denied */
2443 else if (code == CM_ERROR_EXISTS) {
2444 NTStatus = 0xC0000035L; /* Object name collision */
2446 else if (code == CM_ERROR_NOTEMPTY) {
2447 NTStatus = 0xC0000101L; /* Directory not empty */
2449 else if (code == CM_ERROR_CROSSDEVLINK) {
2450 NTStatus = 0xC00000D4L; /* Not same device */
2452 else if (code == CM_ERROR_NOTDIR) {
2453 NTStatus = 0xC0000103L; /* Not a directory */
2455 else if (code == CM_ERROR_ISDIR) {
2456 NTStatus = 0xC00000BAL; /* File is a directory */
2458 else if (code == CM_ERROR_BADOP) {
2460 /* I have no idea where this comes from */
2461 NTStatus = 0xC09820FFL; /* SMB no support */
2463 NTStatus = 0xC00000BBL; /* Not supported */
2464 #endif /* COMMENT */
2466 else if (code == CM_ERROR_BADSHARENAME) {
2467 NTStatus = 0xC00000CCL; /* Bad network name */
2469 else if (code == CM_ERROR_NOIPC) {
2471 NTStatus = 0xC0000022L; /* Access Denied */
2473 NTStatus = 0xC000013DL; /* Remote Resources */
2476 else if (code == CM_ERROR_CLOCKSKEW) {
2477 NTStatus = 0xC0000133L; /* Time difference at DC */
2479 else if (code == CM_ERROR_BADTID) {
2480 NTStatus = 0xC0982005L; /* SMB bad TID */
2482 else if (code == CM_ERROR_USESTD) {
2483 NTStatus = 0xC09820FBL; /* SMB use standard */
2485 else if (code == CM_ERROR_QUOTA) {
2487 NTStatus = 0xC0000044L; /* Quota exceeded */
2489 NTStatus = 0xC000007FL; /* Disk full */
2492 else if (code == CM_ERROR_SPACE) {
2493 NTStatus = 0xC000007FL; /* Disk full */
2495 else if (code == CM_ERROR_ATSYS) {
2496 NTStatus = 0xC0000033L; /* Object name invalid */
2498 else if (code == CM_ERROR_BADNTFILENAME) {
2499 NTStatus = 0xC0000033L; /* Object name invalid */
2501 else if (code == CM_ERROR_WOULDBLOCK) {
2502 NTStatus = 0xC0000055L; /* Lock not granted */
2504 else if (code == CM_ERROR_SHARING_VIOLATION) {
2505 NTStatus = 0xC0000043L; /* Sharing violation */
2507 else if (code == CM_ERROR_LOCK_CONFLICT) {
2508 NTStatus = 0xC0000054L; /* Lock conflict */
2510 else if (code == CM_ERROR_PARTIALWRITE) {
2511 NTStatus = 0xC000007FL; /* Disk full */
2513 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2514 NTStatus = 0xC0000023L; /* Buffer too small */
2516 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2517 NTStatus = 0xC0000035L; /* Object name collision */
2519 else if (code == CM_ERROR_BADPASSWORD) {
2520 NTStatus = 0xC000006DL; /* unknown username or bad password */
2522 else if (code == CM_ERROR_BADLOGONTYPE) {
2523 NTStatus = 0xC000015BL; /* logon type not granted */
2525 else if (code == CM_ERROR_GSSCONTINUE) {
2526 NTStatus = 0xC0000016L; /* more processing required */
2528 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2530 NTStatus = 0xC0000280L; /* reparse point not resolved */
2532 NTStatus = 0xC0000022L; /* Access Denied */
2535 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2536 NTStatus = 0xC0000257L; /* Path Not Covered */
2539 else if (code == CM_ERROR_ALLBUSY) {
2540 NTStatus = 0xC00000BFL; /* Network Busy */
2542 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2543 NTStatus = 0xC0000350L; /* Remote Host Down */
2546 /* we do not want to be telling the SMB/CIFS client that
2547 * the AFS Client Service is busy or down.
2549 else if (code == CM_ERROR_ALLBUSY ||
2550 code == CM_ERROR_ALLOFFLINE ||
2551 code == CM_ERROR_ALLDOWN) {
2552 NTStatus = 0xC00000BEL; /* Bad Network Path */
2555 else if (code == RXKADUNKNOWNKEY) {
2556 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2558 NTStatus = 0xC0982001L; /* SMB non-specific error */
2561 *NTStatusp = NTStatus;
2562 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2565 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2566 unsigned char *classp)
2568 unsigned char class;
2569 unsigned short error;
2571 /* map CM_ERROR_* errors to SMB errors */
2572 if (code == CM_ERROR_NOSUCHCELL) {
2574 error = 3; /* bad path */
2576 else if (code == CM_ERROR_NOSUCHVOLUME) {
2578 error = 3; /* bad path */
2580 else if (code == CM_ERROR_TIMEDOUT) {
2582 error = 81; /* server is paused */
2584 else if (code == CM_ERROR_RETRY) {
2585 class = 2; /* shouldn't happen */
2588 else if (code == CM_ERROR_NOACCESS) {
2590 error = 4; /* bad access */
2592 else if (code == CM_ERROR_READONLY) {
2594 error = 19; /* read only */
2596 else if (code == CM_ERROR_NOSUCHFILE) {
2598 error = 2; /* ENOENT! */
2600 else if (code == CM_ERROR_NOSUCHPATH) {
2602 error = 3; /* Bad path */
2604 else if (code == CM_ERROR_TOOBIG) {
2606 error = 11; /* bad format */
2608 else if (code == CM_ERROR_INVAL) {
2609 class = 2; /* server non-specific error code */
2612 else if (code == CM_ERROR_BADFD) {
2614 error = 6; /* invalid file handle */
2616 else if (code == CM_ERROR_BADFDOP) {
2617 class = 1; /* invalid op on FD */
2620 else if (code == CM_ERROR_EXISTS) {
2622 error = 80; /* file already exists */
2624 else if (code == CM_ERROR_NOTEMPTY) {
2626 error = 5; /* delete directory not empty */
2628 else if (code == CM_ERROR_CROSSDEVLINK) {
2630 error = 17; /* EXDEV */
2632 else if (code == CM_ERROR_NOTDIR) {
2633 class = 1; /* bad path */
2636 else if (code == CM_ERROR_ISDIR) {
2637 class = 1; /* access denied; DOS doesn't have a good match */
2640 else if (code == CM_ERROR_BADOP) {
2644 else if (code == CM_ERROR_BADSHARENAME) {
2648 else if (code == CM_ERROR_NOIPC) {
2650 error = 4; /* bad access */
2652 else if (code == CM_ERROR_CLOCKSKEW) {
2653 class = 1; /* invalid function */
2656 else if (code == CM_ERROR_BADTID) {
2660 else if (code == CM_ERROR_USESTD) {
2664 else if (code == CM_ERROR_REMOTECONN) {
2668 else if (code == CM_ERROR_QUOTA) {
2669 if (vcp->flags & SMB_VCFLAG_USEV3) {
2671 error = 39; /* disk full */
2675 error = 5; /* access denied */
2678 else if (code == CM_ERROR_SPACE) {
2679 if (vcp->flags & SMB_VCFLAG_USEV3) {
2681 error = 39; /* disk full */
2685 error = 5; /* access denied */
2688 else if (code == CM_ERROR_PARTIALWRITE) {
2690 error = 39; /* disk full */
2692 else if (code == CM_ERROR_ATSYS) {
2694 error = 2; /* ENOENT */
2696 else if (code == CM_ERROR_WOULDBLOCK) {
2698 error = 33; /* lock conflict */
2700 else if (code == CM_ERROR_LOCK_CONFLICT) {
2702 error = 33; /* lock conflict */
2704 else if (code == CM_ERROR_SHARING_VIOLATION) {
2706 error = 33; /* lock conflict */
2708 else if (code == CM_ERROR_NOFILES) {
2710 error = 18; /* no files in search */
2712 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2714 error = 183; /* Samba uses this */
2716 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2717 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2719 error = 2; /* bad password */
2721 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2723 error = 3; /* bad path */
2732 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2735 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2737 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2738 return CM_ERROR_BADOP;
2741 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2743 unsigned short EchoCount, i;
2744 char *data, *outdata;
2747 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2749 for (i=1; i<=EchoCount; i++) {
2750 data = smb_GetSMBData(inp, &dataSize);
2751 smb_SetSMBParm(outp, 0, i);
2752 smb_SetSMBDataLength(outp, dataSize);
2753 outdata = smb_GetSMBData(outp, NULL);
2754 memcpy(outdata, data, dataSize);
2755 smb_SendPacket(vcp, outp);
2761 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2764 long count, minCount, finalCount;
2769 cm_user_t *userp = NULL;
2772 char *rawBuf = NULL;
2777 fd = smb_GetSMBParm(inp, 0);
2778 count = smb_GetSMBParm(inp, 3);
2779 minCount = smb_GetSMBParm(inp, 4);
2780 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2782 if (*inp->wctp == 10) {
2783 /* we were sent a request with 64-bit file offsets */
2784 #ifdef AFS_LARGEFILES
2785 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2787 if (LargeIntegerLessThanZero(offset)) {
2788 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2792 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2793 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2796 offset.HighPart = 0;
2800 /* we were sent a request with 32-bit file offsets */
2801 offset.HighPart = 0;
2804 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2805 fd, offset.HighPart, offset.LowPart, count);
2807 fidp = smb_FindFID(vcp, fd, 0);
2811 pid = ((smb_t *) inp)->pid;
2813 LARGE_INTEGER LOffset, LLength;
2816 key = cm_GenerateKey(vcp->vcID, pid, fd);
2818 LOffset.HighPart = offset.HighPart;
2819 LOffset.LowPart = offset.LowPart;
2820 LLength.HighPart = 0;
2821 LLength.LowPart = count;
2823 lock_ObtainMutex(&fidp->scp->mx);
2824 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2825 lock_ReleaseMutex(&fidp->scp->mx);
2831 lock_ObtainMutex(&smb_RawBufLock);
2833 /* Get a raw buf, from head of list */
2834 rawBuf = smb_RawBufs;
2835 smb_RawBufs = *(char **)smb_RawBufs;
2837 lock_ReleaseMutex(&smb_RawBufLock);
2841 lock_ObtainMutex(&fidp->mx);
2842 if (fidp->flags & SMB_FID_IOCTL)
2844 lock_ReleaseMutex(&fidp->mx);
2845 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2847 /* Give back raw buffer */
2848 lock_ObtainMutex(&smb_RawBufLock);
2849 *((char **) rawBuf) = smb_RawBufs;
2851 smb_RawBufs = rawBuf;
2852 lock_ReleaseMutex(&smb_RawBufLock);
2855 smb_ReleaseFID(fidp);
2858 lock_ReleaseMutex(&fidp->mx);
2860 userp = smb_GetUserFromVCP(vcp, inp);
2862 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2868 cm_ReleaseUser(userp);
2871 smb_ReleaseFID(fidp);
2875 memset((char *)ncbp, 0, sizeof(NCB));
2877 ncbp->ncb_length = (unsigned short) finalCount;
2878 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2879 ncbp->ncb_lana_num = vcp->lana;
2880 ncbp->ncb_command = NCBSEND;
2881 ncbp->ncb_buffer = rawBuf;
2883 code = Netbios(ncbp);
2885 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2888 /* Give back raw buffer */
2889 lock_ObtainMutex(&smb_RawBufLock);
2890 *((char **) rawBuf) = smb_RawBufs;
2892 smb_RawBufs = rawBuf;
2893 lock_ReleaseMutex(&smb_RawBufLock);
2899 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2901 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2906 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2908 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2913 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2920 int VistaProtoIndex;
2921 int protoIndex; /* index we're using */
2926 char protocol_array[10][1024]; /* protocol signature of the client */
2927 int caps; /* capabilities */
2930 TIME_ZONE_INFORMATION tzi;
2932 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2935 namep = smb_GetSMBData(inp, &dbytes);
2938 coreProtoIndex = -1; /* not found */
2941 VistaProtoIndex = -1;
2942 while(namex < dbytes) {
2943 osi_Log1(smb_logp, "Protocol %s",
2944 osi_LogSaveString(smb_logp, namep+1));
2945 strcpy(protocol_array[tcounter], namep+1);
2947 /* namep points at the first protocol, or really, a 0x02
2948 * byte preceding the null-terminated ASCII name.
2950 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2951 coreProtoIndex = tcounter;
2953 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2954 v3ProtoIndex = tcounter;
2956 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2957 NTProtoIndex = tcounter;
2959 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
2960 VistaProtoIndex = tcounter;
2963 /* compute size of protocol entry */
2964 entryLength = (int)strlen(namep+1);
2965 entryLength += 2; /* 0x02 bytes and null termination */
2967 /* advance over this protocol entry */
2968 namex += entryLength;
2969 namep += entryLength;
2970 tcounter++; /* which proto entry we're looking at */
2973 lock_ObtainMutex(&vcp->mx);
2975 if (VistaProtoIndex != -1) {
2976 protoIndex = VistaProtoIndex;
2977 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2980 if (NTProtoIndex != -1) {
2981 protoIndex = NTProtoIndex;
2982 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2984 else if (v3ProtoIndex != -1) {
2985 protoIndex = v3ProtoIndex;
2986 vcp->flags |= SMB_VCFLAG_USEV3;
2988 else if (coreProtoIndex != -1) {
2989 protoIndex = coreProtoIndex;
2990 vcp->flags |= SMB_VCFLAG_USECORE;
2992 else protoIndex = -1;
2993 lock_ReleaseMutex(&vcp->mx);
2995 if (protoIndex == -1)
2996 return CM_ERROR_INVAL;
2997 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
2998 smb_SetSMBParm(outp, 0, protoIndex);
2999 if (smb_authType != SMB_AUTH_NONE) {
3000 smb_SetSMBParmByte(outp, 1,
3001 NEGOTIATE_SECURITY_USER_LEVEL |
3002 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3004 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3006 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3007 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3008 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3009 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3010 /* The session key is not a well documented field however most clients
3011 * will echo back the session key to the server. Currently we are using
3012 * the same value for all sessions. We should generate a random value
3013 * and store it into the vcp
3015 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3016 smb_SetSMBParm(outp, 8, 1);
3018 * Tried changing the capabilities to support for W2K - defect 117695
3019 * Maybe something else needs to be changed here?
3023 smb_SetSMBParmLong(outp, 9, 0x43fd);
3025 smb_SetSMBParmLong(outp, 9, 0x251);
3028 * 32-bit error codes *
3033 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3035 NTNEGOTIATE_CAPABILITY_DFS |
3037 #ifdef AFS_LARGEFILES
3038 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3040 NTNEGOTIATE_CAPABILITY_NTFIND |
3041 NTNEGOTIATE_CAPABILITY_RAWMODE |
3042 NTNEGOTIATE_CAPABILITY_NTSMB;
3044 if ( smb_authType == SMB_AUTH_EXTENDED )
3045 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3047 smb_SetSMBParmLong(outp, 9, caps);
3049 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3050 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3051 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3053 GetTimeZoneInformation(&tzi);
3054 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3056 if (smb_authType == SMB_AUTH_NTLM) {
3057 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3058 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3059 /* paste in encryption key */
3060 datap = smb_GetSMBData(outp, NULL);
3061 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3062 /* and the faux domain name */
3063 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3064 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3068 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3070 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3072 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3074 datap = smb_GetSMBData(outp, NULL);
3075 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3078 datap += sizeof(smb_ServerGUID);
3079 memcpy(datap, secBlob, secBlobLength);
3083 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3084 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3087 else if (v3ProtoIndex != -1) {
3088 smb_SetSMBParm(outp, 0, protoIndex);
3090 /* NOTE: Extended authentication cannot be negotiated with v3
3091 * therefore we fail over to NTLM
3093 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3094 smb_SetSMBParm(outp, 1,
3095 NEGOTIATE_SECURITY_USER_LEVEL |
3096 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3098 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3100 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3101 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3102 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3103 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3104 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3105 smb_SetSMBParm(outp, 7, 1);
3107 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3108 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3109 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3111 GetTimeZoneInformation(&tzi);
3112 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3114 /* NOTE: Extended authentication cannot be negotiated with v3
3115 * therefore we fail over to NTLM
3117 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3118 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3119 smb_SetSMBParm(outp, 12, 0); /* resvd */
3120 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3121 datap = smb_GetSMBData(outp, NULL);
3122 /* paste in a new encryption key */
3123 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3124 /* and the faux domain name */
3125 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3127 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3128 smb_SetSMBParm(outp, 12, 0); /* resvd */
3129 smb_SetSMBDataLength(outp, 0);
3132 else if (coreProtoIndex != -1) { /* not really supported anymore */
3133 smb_SetSMBParm(outp, 0, protoIndex);
3134 smb_SetSMBDataLength(outp, 0);
3139 void smb_CheckVCs(void)
3141 smb_vc_t * vcp, *nextp;
3142 smb_packet_t * outp = GetPacket();
3145 lock_ObtainWrite(&smb_rctLock);
3146 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3148 if (vcp->magic != SMB_VC_MAGIC)
3149 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3150 __FILE__, __LINE__);
3154 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3157 smb_HoldVCNoLock(vcp);
3159 smb_HoldVCNoLock(nextp);
3160 smb_FormatResponsePacket(vcp, NULL, outp);
3161 smbp = (smb_t *)outp;
3162 outp->inCom = smbp->com = 0x2b /* Echo */;
3170 smb_SetSMBParm(outp, 0, 0);
3171 smb_SetSMBDataLength(outp, 0);
3172 lock_ReleaseWrite(&smb_rctLock);
3174 smb_SendPacket(vcp, outp);
3176 lock_ObtainWrite(&smb_rctLock);
3177 smb_ReleaseVCNoLock(vcp);
3179 smb_ReleaseVCNoLock(nextp);
3181 lock_ReleaseWrite(&smb_rctLock);
3182 smb_FreePacket(outp);
3185 void smb_Daemon(void *parmp)
3187 afs_uint32 count = 0;
3188 smb_username_t **unpp;
3191 while(smbShutdownFlag == 0) {
3195 if (smbShutdownFlag == 1)
3198 if ((count % 72) == 0) { /* every five minutes */
3200 time_t old_localZero = smb_localZero;
3202 /* Initialize smb_localZero */
3203 myTime.tm_isdst = -1; /* compute whether on DST or not */
3204 myTime.tm_year = 70;
3210 smb_localZero = mktime(&myTime);
3212 #ifndef USE_NUMERIC_TIME_CONV
3213 smb_CalculateNowTZ();
3214 #endif /* USE_NUMERIC_TIME_CONV */
3215 #ifdef AFS_FREELANCE
3216 if ( smb_localZero != old_localZero )
3217 cm_noteLocalMountPointChange();
3223 /* GC smb_username_t objects that will no longer be used */
3225 lock_ObtainWrite(&smb_rctLock);
3226 for ( unpp=&usernamesp; *unpp; ) {
3228 smb_username_t *unp;
3230 lock_ObtainMutex(&(*unpp)->mx);
3231 if ( (*unpp)->refCount > 0 ||
3232 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3233 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3235 else if (!smb_LogoffTokenTransfer ||
3236 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3238 lock_ReleaseMutex(&(*unpp)->mx);
3246 lock_FinalizeMutex(&unp->mx);
3252 lock_ReleaseWrite(&smb_rctLock);
3253 cm_ReleaseUser(userp);
3254 lock_ObtainWrite(&smb_rctLock);
3257 unpp = &(*unpp)->nextp;
3260 lock_ReleaseWrite(&smb_rctLock);
3262 /* XXX GC dir search entries */
3266 void smb_WaitingLocksDaemon()
3268 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3269 smb_waitingLock_t *wl, *wlNext;
3272 smb_packet_t *inp, *outp;
3276 while (smbShutdownFlag == 0) {
3277 lock_ObtainWrite(&smb_globalLock);
3278 nwlRequest = smb_allWaitingLocks;
3279 if (nwlRequest == NULL) {
3280 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3285 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3292 lock_ObtainWrite(&smb_globalLock);
3294 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3296 wlRequest = nwlRequest;
3297 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3298 lock_ReleaseWrite(&smb_globalLock);
3302 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3303 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3306 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3308 /* wl->state is either _DONE or _WAITING. _ERROR
3309 would no longer be on the queue. */
3310 code = cm_RetryLock( wl->lockp,
3311 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3314 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3315 } else if (code != CM_ERROR_WOULDBLOCK) {
3316 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3321 if (code == CM_ERROR_WOULDBLOCK) {
3324 if (wlRequest->timeRemaining != 0xffffffff
3325 && (wlRequest->timeRemaining -= 1000) < 0)
3337 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3340 scp = wlRequest->scp;
3344 lock_ObtainMutex(&scp->mx);
3346 for (wl = wlRequest->locks; wl; wl = wlNext) {
3347 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3349 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3350 wl->LLength, wl->key, NULL, &req);
3352 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3357 lock_ReleaseMutex(&scp->mx);
3361 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3364 for (wl = wlRequest->locks; wl; wl = wlNext) {
3365 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3366 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3371 vcp = wlRequest->vcp;
3372 inp = wlRequest->inp;
3373 outp = wlRequest->outp;
3375 ncbp->ncb_length = inp->ncb_length;
3376 inp->spacep = cm_GetSpace();
3378 /* Remove waitingLock from list */
3379 lock_ObtainWrite(&smb_globalLock);
3380 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3382 lock_ReleaseWrite(&smb_globalLock);
3384 /* Resume packet processing */
3386 smb_SetSMBDataLength(outp, 0);
3387 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3388 outp->resumeCode = code;
3390 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3393 cm_FreeSpace(inp->spacep);
3394 smb_FreePacket(inp);
3395 smb_FreePacket(outp);
3397 cm_ReleaseSCache(wlRequest->scp);
3400 } while (nwlRequest && smbShutdownFlag == 0);
3405 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3407 osi_Log0(smb_logp, "SMB receive get disk attributes");
3409 smb_SetSMBParm(outp, 0, 32000);
3410 smb_SetSMBParm(outp, 1, 64);
3411 smb_SetSMBParm(outp, 2, 1024);
3412 smb_SetSMBParm(outp, 3, 30000);
3413 smb_SetSMBParm(outp, 4, 0);
3414 smb_SetSMBDataLength(outp, 0);
3418 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3422 unsigned short newTid;
3423 char shareName[256];
3431 osi_Log0(smb_logp, "SMB receive tree connect");
3433 /* parse input parameters */
3434 tp = smb_GetSMBData(inp, NULL);
3435 pathp = smb_ParseASCIIBlock(tp, &tp);
3436 if (smb_StoreAnsiFilenames)
3437 OemToChar(pathp,pathp);
3438 passwordp = smb_ParseASCIIBlock(tp, &tp);
3439 tp = strrchr(pathp, '\\');
3441 return CM_ERROR_BADSMB;
3442 strcpy(shareName, tp+1);
3444 lock_ObtainMutex(&vcp->mx);
3445 newTid = vcp->tidCounter++;
3446 lock_ReleaseMutex(&vcp->mx);
3448 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3449 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3450 userp = smb_GetUserFromUID(uidp);
3451 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3453 smb_ReleaseUID(uidp);
3455 smb_ReleaseTID(tidp);
3456 return CM_ERROR_BADSHARENAME;
3458 lock_ObtainMutex(&tidp->mx);
3459 tidp->userp = userp;
3460 tidp->pathname = sharePath;
3461 lock_ReleaseMutex(&tidp->mx);
3462 smb_ReleaseTID(tidp);
3464 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3465 smb_SetSMBParm(rsp, 1, newTid);
3466 smb_SetSMBDataLength(rsp, 0);
3468 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3472 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3476 if (*inp++ != 0x1) return NULL;
3477 tlen = inp[0] + (inp[1]<<8);
3478 inp += 2; /* skip length field */
3481 *chainpp = inp + tlen;
3484 if (lengthp) *lengthp = tlen;
3489 /* set maskp to the mask part of the incoming path.
3490 * Mask is 11 bytes long (8.3 with the dot elided).
3491 * Returns true if succeeds with a valid name, otherwise it does
3492 * its best, but returns false.
3494 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3502 /* starts off valid */
3505 /* mask starts out all blanks */
3506 memset(maskp, ' ', 11);
3508 /* find last backslash, or use whole thing if there is none */
3509 tp = strrchr(pathp, '\\');
3510 if (!tp) tp = pathp;
3511 else tp++; /* skip slash */
3515 /* names starting with a dot are illegal */
3516 if (*tp == '.') valid8Dot3 = 0;
3520 if (tc == 0) return valid8Dot3;
3521 if (tc == '.' || tc == '"') break;
3522 if (i < 8) *up++ = tc;
3523 else valid8Dot3 = 0;
3526 /* if we get here, tp point after the dot */
3527 up = maskp+8; /* ext goes here */
3534 if (tc == '.' || tc == '"')
3537 /* copy extension if not too long */
3547 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3557 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3559 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3563 /* otherwise, we have a valid 8.3 name; see if we have a match,
3564 * treating '?' as a wildcard in maskp (but not in the file name).
3566 tp1 = umask; /* real name, in mask format */
3567 tp2 = maskp; /* mask, in mask format */
3568 for(i=0; i<11; i++) {
3569 tc1 = *tp1++; /* char from real name */
3570 tc2 = *tp2++; /* char from mask */
3571 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3572 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3575 if (tc2 == '?' && tc1 != ' ')
3582 /* we got a match */
3586 char *smb_FindMask(char *pathp)
3590 tp = strrchr(pathp, '\\'); /* find last slash */
3593 return tp+1; /* skip the slash */
3595 return pathp; /* no slash, return the entire path */
3598 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3600 unsigned char *pathp;
3602 unsigned char mask[11];
3603 unsigned char *statBlockp;
3604 unsigned char initStatBlock[21];
3607 osi_Log0(smb_logp, "SMB receive search volume");
3609 /* pull pathname and stat block out of request */
3610 tp = smb_GetSMBData(inp, NULL);
3611 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3612 osi_assert(pathp != NULL);
3613 if (smb_StoreAnsiFilenames)
3614 OemToChar(pathp,pathp);
3615 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3616 osi_assert(statBlockp != NULL);
3618 statBlockp = initStatBlock;
3622 /* for returning to caller */
3623 smb_Get8Dot3MaskFromPath(mask, pathp);
3625 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3626 tp = smb_GetSMBData(outp, NULL);
3628 *tp++ = 43; /* bytes in a dir entry */
3629 *tp++ = 0; /* high byte in counter */
3631 /* now marshall the dir entry, starting with the search status */
3632 *tp++ = statBlockp[0]; /* Reserved */
3633 memcpy(tp, mask, 11); tp += 11; /* FileName */
3635 /* now pass back server use info, with 1st byte non-zero */
3637 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3639 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3641 *tp++ = 0x8; /* attribute: volume */
3651 /* 4 byte file size */
3657 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3658 memset(tp, ' ', 13);
3661 /* set the length of the data part of the packet to 43 + 3, for the dir
3662 * entry plus the 5 and the length fields.
3664 smb_SetSMBDataLength(outp, 46);
3668 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3669 cm_user_t *userp, cm_req_t *reqp)
3677 smb_dirListPatch_t *patchp;
3678 smb_dirListPatch_t *npatchp;
3680 for (patchp = *dirPatchespp; patchp; patchp =
3681 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3683 dptr = patchp->dptr;
3685 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3687 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3688 *dptr++ = SMB_ATTR_HIDDEN;
3691 lock_ObtainMutex(&scp->mx);
3692 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3693 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3695 lock_ReleaseMutex(&scp->mx);
3696 cm_ReleaseSCache(scp);
3697 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3698 *dptr++ = SMB_ATTR_HIDDEN;
3702 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3704 attr = smb_Attributes(scp);
3705 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3706 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3707 attr |= SMB_ATTR_HIDDEN;
3711 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3714 shortTemp = (unsigned short) (dosTime & 0xffff);
3715 *((u_short *)dptr) = shortTemp;
3718 /* and copy out date */
3719 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3720 *((u_short *)dptr) = shortTemp;
3723 /* copy out file length */
3724 *((u_long *)dptr) = scp->length.LowPart;
3726 lock_ReleaseMutex(&scp->mx);
3727 cm_ReleaseSCache(scp);
3730 /* now free the patches */
3731 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3732 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3736 /* and mark the list as empty */
3737 *dirPatchespp = NULL;
3742 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3751 smb_dirListPatch_t *dirListPatchesp;
3752 smb_dirListPatch_t *curPatchp;
3756 osi_hyper_t dirLength;
3757 osi_hyper_t bufferOffset;
3758 osi_hyper_t curOffset;
3760 unsigned char *inCookiep;
3761 smb_dirSearch_t *dsp;
3765 unsigned long clientCookie;
3766 cm_pageHeader_t *pageHeaderp;
3767 cm_user_t *userp = NULL;
3774 long nextEntryCookie;
3775 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3776 char resByte; /* reserved byte from the cookie */
3777 char *op; /* output data ptr */
3778 char *origOp; /* original value of op */
3779 cm_space_t *spacep; /* for pathname buffer */
3790 maxCount = smb_GetSMBParm(inp, 0);
3792 dirListPatchesp = NULL;
3794 caseFold = CM_FLAG_CASEFOLD;
3796 tp = smb_GetSMBData(inp, NULL);
3797 pathp = smb_ParseASCIIBlock(tp, &tp);
3798 if (smb_StoreAnsiFilenames)
3799 OemToChar(pathp,pathp);
3800 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3802 /* bail out if request looks bad */
3803 if (!tp || !pathp) {
3804 return CM_ERROR_BADSMB;
3807 /* We can handle long names */
3808 if (vcp->flags & SMB_VCFLAG_USENT)
3809 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3811 /* make sure we got a whole search status */
3812 if (dataLength < 21) {
3813 nextCookie = 0; /* start at the beginning of the dir */
3816 attribute = smb_GetSMBParm(inp, 1);
3818 /* handle volume info in another function */
3819 if (attribute & 0x8)
3820 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3822 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3823 maxCount, osi_LogSaveString(smb_logp, pathp));
3825 if (*pathp == 0) { /* null pathp, treat as root dir */
3826 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3827 return CM_ERROR_NOFILES;
3831 dsp = smb_NewDirSearch(0);
3832 dsp->attribute = attribute;
3833 smb_Get8Dot3MaskFromPath(mask, pathp);
3834 memcpy(dsp->mask, mask, 11);
3836 /* track if this is likely to match a lot of entries */
3837 if (smb_IsStarMask(mask))
3842 /* pull the next cookie value out of the search status block */
3843 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3844 + (inCookiep[16]<<24);
3845 dsp = smb_FindDirSearch(inCookiep[12]);
3847 /* can't find dir search status; fatal error */
3848 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3849 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3850 return CM_ERROR_BADFD;
3852 attribute = dsp->attribute;
3853 resByte = inCookiep[0];
3855 /* copy out client cookie, in host byte order. Don't bother
3856 * interpreting it, since we're just passing it through, anyway.
3858 memcpy(&clientCookie, &inCookiep[17], 4);
3860 memcpy(mask, dsp->mask, 11);
3862 /* assume we're doing a star match if it has continued for more
3868 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3869 nextCookie, dsp->cookie, attribute);
3871 userp = smb_GetUserFromVCP(vcp, inp);
3873 /* try to get the vnode for the path name next */
3874 lock_ObtainMutex(&dsp->mx);
3880 spacep = inp->spacep;
3881 smb_StripLastComponent(spacep->data, NULL, pathp);
3882 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3884 lock_ReleaseMutex(&dsp->mx);
3885 cm_ReleaseUser(userp);
3886 smb_DeleteDirSearch(dsp);
3887 smb_ReleaseDirSearch(dsp);
3888 return CM_ERROR_NOFILES;
3890 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3891 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3894 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3895 cm_ReleaseSCache(scp);
3896 lock_ReleaseMutex(&dsp->mx);
3897 cm_ReleaseUser(userp);
3898 smb_DeleteDirSearch(dsp);
3899 smb_ReleaseDirSearch(dsp);
3900 if ( WANTS_DFS_PATHNAMES(inp) )
3901 return CM_ERROR_PATH_NOT_COVERED;
3903 return CM_ERROR_BADSHARENAME;
3905 #endif /* DFS_SUPPORT */
3908 /* we need one hold for the entry we just stored into,
3909 * and one for our own processing. When we're done with this
3910 * function, we'll drop the one for our own processing.
3911 * We held it once from the namei call, and so we do another hold
3915 lock_ObtainMutex(&scp->mx);
3916 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3917 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3918 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3919 dsp->flags |= SMB_DIRSEARCH_BULKST;
3920 dsp->scp->bulkStatProgress = hzero;
3922 lock_ReleaseMutex(&scp->mx);
3925 lock_ReleaseMutex(&dsp->mx);
3927 cm_ReleaseUser(userp);
3928 smb_DeleteDirSearch(dsp);
3929 smb_ReleaseDirSearch(dsp);
3933 /* reserves space for parameter; we'll adjust it again later to the
3934 * real count of the # of entries we returned once we've actually
3935 * assembled the directory listing.
3937 smb_SetSMBParm(outp, 0, 0);
3939 /* get the directory size */
3940 lock_ObtainMutex(&scp->mx);
3941 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3942 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3944 lock_ReleaseMutex(&scp->mx);
3945 cm_ReleaseSCache(scp);
3946 cm_ReleaseUser(userp);
3947 smb_DeleteDirSearch(dsp);
3948 smb_ReleaseDirSearch(dsp);
3952 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3954 dirLength = scp->length;
3956 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3957 curOffset.HighPart = 0;
3958 curOffset.LowPart = nextCookie;
3959 origOp = op = smb_GetSMBData(outp, NULL);
3960 /* and write out the basic header */
3961 *op++ = 5; /* variable block */
3962 op += 2; /* skip vbl block length; we'll fill it in later */
3966 /* make sure that curOffset.LowPart doesn't point to the first
3967 * 32 bytes in the 2nd through last dir page, and that it doesn't
3968 * point at the first 13 32-byte chunks in the first dir page,
3969 * since those are dir and page headers, and don't contain useful
3972 temp = curOffset.LowPart & (2048-1);
3973 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3974 /* we're in the first page */
3975 if (temp < 13*32) temp = 13*32;
3978 /* we're in a later dir page */
3979 if (temp < 32) temp = 32;
3982 /* make sure the low order 5 bits are zero */
3985 /* now put temp bits back ito curOffset.LowPart */
3986 curOffset.LowPart &= ~(2048-1);
3987 curOffset.LowPart |= temp;
3989 /* check if we've returned all the names that will fit in the
3992 if (returnedNames >= maxCount) {
3993 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3994 returnedNames, maxCount);
3998 /* check if we've passed the dir's EOF */
3999 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4001 /* see if we can use the bufferp we have now; compute in which page
4002 * the current offset would be, and check whether that's the offset
4003 * of the buffer we have. If not, get the buffer.
4005 thyper.HighPart = curOffset.HighPart;
4006 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4007 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4010 buf_Release(bufferp);
4013 lock_ReleaseMutex(&scp->mx);
4014 lock_ObtainRead(&scp->bufCreateLock);
4015 code = buf_Get(scp, &thyper, &bufferp);
4016 lock_ReleaseRead(&scp->bufCreateLock);
4017 lock_ObtainMutex(&dsp->mx);
4019 /* now, if we're doing a star match, do bulk fetching of all of
4020 * the status info for files in the dir.
4023 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4024 lock_ObtainMutex(&scp->mx);
4025 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4026 LargeIntegerGreaterThanOrEqualTo(thyper,
4027 scp->bulkStatProgress)) {
4028 /* Don't bulk stat if risking timeout */
4029 int now = GetTickCount();
4030 if (now - req.startTime > RDRtimeout) {
4031 scp->bulkStatProgress = thyper;
4032 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4033 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4034 dsp->scp->bulkStatProgress = hzero;
4036 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4039 lock_ObtainMutex(&scp->mx);
4041 lock_ReleaseMutex(&dsp->mx);
4043 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4047 bufferOffset = thyper;
4049 /* now get the data in the cache */
4051 code = cm_SyncOp(scp, bufferp, userp, &req,
4053 CM_SCACHESYNC_NEEDCALLBACK |
4054 CM_SCACHESYNC_READ);
4056 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4060 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4062 if (cm_HaveBuffer(scp, bufferp, 0)) {
4063 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4067 /* otherwise, load the buffer and try again */
4068 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4070 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4071 scp, bufferp, code);
4076 buf_Release(bufferp);
4080 } /* if (wrong buffer) ... */
4082 /* now we have the buffer containing the entry we're interested in; copy
4083 * it out if it represents a non-deleted entry.
4085 entryInDir = curOffset.LowPart & (2048-1);
4086 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4088 /* page header will help tell us which entries are free. Page header
4089 * can change more often than once per buffer, since AFS 3 dir page size
4090 * may be less than (but not more than a buffer package buffer.
4092 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4093 temp &= ~(2048 - 1); /* turn off intra-page bits */
4094 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4096 /* now determine which entry we're looking at in the page. If it is
4097 * free (there's a free bitmap at the start of the dir), we should
4098 * skip these 32 bytes.
4100 slotInPage = (entryInDir & 0x7e0) >> 5;
4101 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4102 /* this entry is free */
4103 numDirChunks = 1; /* only skip this guy */
4107 tp = bufferp->datap + entryInBuffer;
4108 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4110 /* while we're here, compute the next entry's location, too,
4111 * since we'll need it when writing out the cookie into the dir
4114 * XXXX Probably should do more sanity checking.
4116 numDirChunks = cm_NameEntries(dep->name, NULL);
4118 /* compute the offset of the cookie representing the next entry */
4119 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4121 /* Compute 8.3 name if necessary */
4122 actualName = dep->name;
4123 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4124 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4125 actualName = shortName;
4128 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4129 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4130 osi_LogSaveString(smb_logp, actualName));
4132 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4133 /* this is one of the entries to use: it is not deleted
4134 * and it matches the star pattern we're looking for.
4137 /* Eliminate entries that don't match requested
4140 /* no hidden files */
4141 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4142 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4146 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4148 /* We have already done the cm_TryBulkStat above */
4149 fid.cell = scp->fid.cell;
4150 fid.volume = scp->fid.volume;
4151 fid.vnode = ntohl(dep->fid.vnode);
4152 fid.unique = ntohl(dep->fid.unique);
4153 fileType = cm_FindFileType(&fid);
4154 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4155 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4157 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4158 fileType == CM_SCACHETYPE_DFSLINK ||
4159 fileType == CM_SCACHETYPE_INVALID)
4160 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4165 memcpy(op, mask, 11); op += 11;
4166 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4167 *op++ = (char)(nextEntryCookie & 0xff);
4168 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4169 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4170 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4171 memcpy(op, &clientCookie, 4); op += 4;
4173 /* now we emit the attribute. This is sort of tricky,
4174 * since we need to really stat the file to find out
4175 * what type of entry we've got. Right now, we're
4176 * copying out data from a buffer, while holding the
4177 * scp locked, so it isn't really convenient to stat
4178 * something now. We'll put in a place holder now,
4179 * and make a second pass before returning this to get
4180 * the real attributes. So, we just skip the data for
4181 * now, and adjust it later. We allocate a patch
4182 * record to make it easy to find this point later.
4183 * The replay will happen at a time when it is safe to
4184 * unlock the directory.
4186 curPatchp = malloc(sizeof(*curPatchp));
4187 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4188 curPatchp->dptr = op;
4189 curPatchp->fid.cell = scp->fid.cell;
4190 curPatchp->fid.volume = scp->fid.volume;
4191 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4192 curPatchp->fid.unique = ntohl(dep->fid.unique);
4194 /* do hidden attribute here since name won't be around when applying
4198 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4199 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4201 curPatchp->flags = 0;
4203 op += 9; /* skip attr, time, date and size */
4205 /* zero out name area. The spec says to pad with
4206 * spaces, but Samba doesn't, and neither do we.
4210 /* finally, we get to copy out the name; we know that
4211 * it fits in 8.3 or the pattern wouldn't match, but it
4212 * never hurts to be sure.
4214 strncpy(op, actualName, 13);
4215 if (smb_StoreAnsiFilenames)
4218 /* Uppercase if requested by client */
4219 if (!KNOWS_LONG_NAMES(inp))
4224 /* now, adjust the # of entries copied */
4226 } /* if we're including this name */
4229 /* and adjust curOffset to be where the new cookie is */
4230 thyper.HighPart = 0;
4231 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4232 curOffset = LargeIntegerAdd(thyper, curOffset);
4233 } /* while copying data for dir listing */
4235 /* release the mutex */
4236 lock_ReleaseMutex(&scp->mx);
4238 buf_Release(bufferp);
4242 /* apply and free last set of patches; if not doing a star match, this
4243 * will be empty, but better safe (and freeing everything) than sorry.
4245 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4247 /* special return code for unsuccessful search */
4248 if (code == 0 && dataLength < 21 && returnedNames == 0)
4249 code = CM_ERROR_NOFILES;
4251 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4252 returnedNames, code);
4255 smb_DeleteDirSearch(dsp);
4256 smb_ReleaseDirSearch(dsp);
4257 cm_ReleaseSCache(scp);
4258 cm_ReleaseUser(userp);
4262 /* finalize the output buffer */
4263 smb_SetSMBParm(outp, 0, returnedNames);
4264 temp = (long) (op - origOp);
4265 smb_SetSMBDataLength(outp, temp);
4267 /* the data area is a variable block, which has a 5 (already there)
4268 * followed by the length of the # of data bytes. We now know this to
4269 * be "temp," although that includes the 3 bytes of vbl block header.
4270 * Deduct for them and fill in the length field.
4272 temp -= 3; /* deduct vbl block info */
4273 osi_assert(temp == (43 * returnedNames));
4274 origOp[1] = (char)(temp & 0xff);
4275 origOp[2] = (char)((temp>>8) & 0xff);
4276 if (returnedNames == 0)
4277 smb_DeleteDirSearch(dsp);
4278 smb_ReleaseDirSearch(dsp);
4279 cm_ReleaseSCache(scp);
4280 cm_ReleaseUser(userp);
4284 /* verify that this is a valid path to a directory. I don't know why they
4285 * don't use the get file attributes call.
4287 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4291 cm_scache_t *rootScp;
4292 cm_scache_t *newScp;
4301 pathp = smb_GetSMBData(inp, NULL);
4302 pathp = smb_ParseASCIIBlock(pathp, NULL);
4304 return CM_ERROR_BADFD;
4305 if (smb_StoreAnsiFilenames)
4306 OemToChar(pathp,pathp);
4307 osi_Log1(smb_logp, "SMB receive check path %s",
4308 osi_LogSaveString(smb_logp, pathp));
4310 rootScp = cm_data.rootSCachep;
4312 userp = smb_GetUserFromVCP(vcp, inp);
4314 caseFold = CM_FLAG_CASEFOLD;
4316 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4318 cm_ReleaseUser(userp);
4319 return CM_ERROR_NOSUCHPATH;
4321 code = cm_NameI(rootScp, pathp,
4322 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4323 userp, tidPathp, &req, &newScp);
4326 cm_ReleaseUser(userp);
4331 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4332 cm_ReleaseSCache(newScp);
4333 cm_ReleaseUser(userp);
4334 if ( WANTS_DFS_PATHNAMES(inp) )
4335 return CM_ERROR_PATH_NOT_COVERED;
4337 return CM_ERROR_BADSHARENAME;
4339 #endif /* DFS_SUPPORT */
4341 /* now lock the vnode with a callback; returns with newScp locked */
4342 lock_ObtainMutex(&newScp->mx);
4343 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4344 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4346 if (code != CM_ERROR_NOACCESS) {
4347 lock_ReleaseMutex(&newScp->mx);
4348 cm_ReleaseSCache(newScp);
4349 cm_ReleaseUser(userp);
4353 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4356 attrs = smb_Attributes(newScp);
4358 if (!(attrs & SMB_ATTR_DIRECTORY))
4359 code = CM_ERROR_NOTDIR;
4361 lock_ReleaseMutex(&newScp->mx);
4363 cm_ReleaseSCache(newScp);
4364 cm_ReleaseUser(userp);
4368 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4372 cm_scache_t *rootScp;
4373 unsigned short attribute;
4375 cm_scache_t *newScp;
4384 /* decode basic attributes we're passed */
4385 attribute = smb_GetSMBParm(inp, 0);
4386 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4388 pathp = smb_GetSMBData(inp, NULL);
4389 pathp = smb_ParseASCIIBlock(pathp, NULL);
4391 return CM_ERROR_BADSMB;
4392 if (smb_StoreAnsiFilenames)
4393 OemToChar(pathp,pathp);
4395 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4396 dosTime, attribute);
4398 rootScp = cm_data.rootSCachep;
4400 userp = smb_GetUserFromVCP(vcp, inp);
4402 caseFold = CM_FLAG_CASEFOLD;
4404 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4406 cm_ReleaseUser(userp);
4407 return CM_ERROR_NOSUCHFILE;
4409 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4410 tidPathp, &req, &newScp);
4413 cm_ReleaseUser(userp);
4418 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4419 cm_ReleaseSCache(newScp);
4420 cm_ReleaseUser(userp);
4421 if ( WANTS_DFS_PATHNAMES(inp) )
4422 return CM_ERROR_PATH_NOT_COVERED;
4424 return CM_ERROR_BADSHARENAME;
4426 #endif /* DFS_SUPPORT */
4428 /* now lock the vnode with a callback; returns with newScp locked; we
4429 * need the current status to determine what the new status is, in some
4432 lock_ObtainMutex(&newScp->mx);
4433 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4434 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4436 lock_ReleaseMutex(&newScp->mx);
4437 cm_ReleaseSCache(newScp);
4438 cm_ReleaseUser(userp);
4442 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4444 /* Check for RO volume */
4445 if (newScp->flags & CM_SCACHEFLAG_RO) {
4446 lock_ReleaseMutex(&newScp->mx);
4447 cm_ReleaseSCache(newScp);
4448 cm_ReleaseUser(userp);
4449 return CM_ERROR_READONLY;
4452 /* prepare for setattr call */
4455 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4456 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4458 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4459 /* we're told to make a writable file read-only */
4460 attr.unixModeBits = newScp->unixModeBits & ~0222;
4461 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4463 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4464 /* we're told to make a read-only file writable */
4465 attr.unixModeBits = newScp->unixModeBits | 0222;
4466 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4468 lock_ReleaseMutex(&newScp->mx);
4470 /* now call setattr */
4472 code = cm_SetAttr(newScp, &attr, userp, &req);
4476 cm_ReleaseSCache(newScp);
4477 cm_ReleaseUser(userp);
4482 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4486 cm_scache_t *rootScp;
4487 cm_scache_t *newScp, *dscp;
4499 pathp = smb_GetSMBData(inp, NULL);
4500 pathp = smb_ParseASCIIBlock(pathp, NULL);
4502 return CM_ERROR_BADSMB;
4504 if (*pathp == 0) /* null path */
4507 if (smb_StoreAnsiFilenames)
4508 OemToChar(pathp,pathp);
4510 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4511 osi_LogSaveString(smb_logp, pathp));
4513 rootScp = cm_data.rootSCachep;
4515 userp = smb_GetUserFromVCP(vcp, inp);
4517 /* we shouldn't need this for V3 requests, but we seem to */
4518 caseFold = CM_FLAG_CASEFOLD;
4520 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4522 cm_ReleaseUser(userp);
4523 return CM_ERROR_NOSUCHFILE;
4527 * XXX Strange hack XXX
4529 * As of Patch 5 (16 July 97), we are having the following problem:
4530 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4531 * requests to look up "desktop.ini" in all the subdirectories.
4532 * This can cause zillions of timeouts looking up non-existent cells
4533 * and volumes, especially in the top-level directory.
4535 * We have not found any way to avoid this or work around it except
4536 * to explicitly ignore the requests for mount points that haven't
4537 * yet been evaluated and for directories that haven't yet been
4540 * We should modify this hack to provide a fake desktop.ini file
4541 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4543 spacep = inp->spacep;
4544 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4545 #ifndef SPECIAL_FOLDERS
4546 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4547 code = cm_NameI(rootScp, spacep->data,
4548 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4549 userp, tidPathp, &req, &dscp);
4552 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4553 if ( WANTS_DFS_PATHNAMES(inp) )
4554 return CM_ERROR_PATH_NOT_COVERED;
4556 return CM_ERROR_BADSHARENAME;
4558 #endif /* DFS_SUPPORT */
4559 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4560 code = CM_ERROR_NOSUCHFILE;
4561 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4562 cm_buf_t *bp = buf_Find(dscp, &hzero);
4567 code = CM_ERROR_NOSUCHFILE;
4569 cm_ReleaseSCache(dscp);
4571 cm_ReleaseUser(userp);
4576 #endif /* SPECIAL_FOLDERS */
4578 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4579 tidPathp, &req, &newScp);
4581 cm_ReleaseUser(userp);
4586 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4587 cm_ReleaseSCache(newScp);
4588 cm_ReleaseUser(userp);
4589 if ( WANTS_DFS_PATHNAMES(inp) )
4590 return CM_ERROR_PATH_NOT_COVERED;
4592 return CM_ERROR_BADSHARENAME;
4594 #endif /* DFS_SUPPORT */
4596 /* now lock the vnode with a callback; returns with newScp locked */
4597 lock_ObtainMutex(&newScp->mx);
4598 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4599 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4601 lock_ReleaseMutex(&newScp->mx);
4602 cm_ReleaseSCache(newScp);
4603 cm_ReleaseUser(userp);
4607 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4610 /* use smb_Attributes instead. Also the fact that a file is
4611 * in a readonly volume doesn't mean it shojuld be marked as RO
4613 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4614 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4615 newScp->fileType == CM_SCACHETYPE_INVALID)
4616 attrs = SMB_ATTR_DIRECTORY;
4619 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4620 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4622 attrs = smb_Attributes(newScp);
4625 smb_SetSMBParm(outp, 0, attrs);
4627 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4628 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4629 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4630 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4631 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4632 smb_SetSMBParm(outp, 5, 0);
4633 smb_SetSMBParm(outp, 6, 0);
4634 smb_SetSMBParm(outp, 7, 0);
4635 smb_SetSMBParm(outp, 8, 0);
4636 smb_SetSMBParm(outp, 9, 0);
4637 smb_SetSMBDataLength(outp, 0);
4638 lock_ReleaseMutex(&newScp->mx);
4640 cm_ReleaseSCache(newScp);
4641 cm_ReleaseUser(userp);
4646 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4650 osi_Log0(smb_logp, "SMB receive tree disconnect");
4652 /* find the tree and free it */
4653 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4655 lock_ObtainWrite(&smb_rctLock);
4657 lock_ReleaseWrite(&smb_rctLock);
4658 smb_ReleaseTID(tidp);
4664 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4682 pathp = smb_GetSMBData(inp, NULL);
4683 pathp = smb_ParseASCIIBlock(pathp, NULL);
4684 if (smb_StoreAnsiFilenames)
4685 OemToChar(pathp,pathp);
4687 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4689 #ifdef DEBUG_VERBOSE
4693 hexpath = osi_HexifyString( pathp );
4694 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4699 share = smb_GetSMBParm(inp, 0);
4700 attribute = smb_GetSMBParm(inp, 1);
4702 spacep = inp->spacep;
4703 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4704 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4705 /* special case magic file name for receiving IOCTL requests
4706 * (since IOCTL calls themselves aren't getting through).
4708 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4709 smb_SetupIoctlFid(fidp, spacep);
4710 smb_SetSMBParm(outp, 0, fidp->fid);
4711 smb_SetSMBParm(outp, 1, 0); /* attrs */
4712 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4713 smb_SetSMBParm(outp, 3, 0);
4714 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4715 smb_SetSMBParm(outp, 5, 0x7fff);
4716 /* pass the open mode back */
4717 smb_SetSMBParm(outp, 6, (share & 0xf));
4718 smb_SetSMBDataLength(outp, 0);
4719 smb_ReleaseFID(fidp);
4723 userp = smb_GetUserFromVCP(vcp, inp);
4725 caseFold = CM_FLAG_CASEFOLD;
4727 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4729 cm_ReleaseUser(userp);
4730 return CM_ERROR_NOSUCHPATH;
4732 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4733 tidPathp, &req, &scp);
4736 cm_ReleaseUser(userp);
4741 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4742 cm_ReleaseSCache(scp);
4743 cm_ReleaseUser(userp);
4744 if ( WANTS_DFS_PATHNAMES(inp) )
4745 return CM_ERROR_PATH_NOT_COVERED;
4747 return CM_ERROR_BADSHARENAME;
4749 #endif /* DFS_SUPPORT */
4751 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4753 cm_ReleaseSCache(scp);
4754 cm_ReleaseUser(userp);
4758 /* don't need callback to check file type, since file types never
4759 * change, and namei and cm_Lookup all stat the object at least once on
4760 * a successful return.
4762 if (scp->fileType != CM_SCACHETYPE_FILE) {
4763 cm_ReleaseSCache(scp);
4764 cm_ReleaseUser(userp);
4765 return CM_ERROR_ISDIR;
4768 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4771 /* save a pointer to the vnode */
4775 fidp->userp = userp;
4777 lock_ObtainMutex(&fidp->mx);
4778 if ((share & 0xf) == 0)
4779 fidp->flags |= SMB_FID_OPENREAD;
4780 else if ((share & 0xf) == 1)
4781 fidp->flags |= SMB_FID_OPENWRITE;
4783 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4784 lock_ReleaseMutex(&fidp->mx);
4786 lock_ObtainMutex(&scp->mx);
4787 smb_SetSMBParm(outp, 0, fidp->fid);
4788 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4789 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4790 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4791 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4792 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4793 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4794 /* pass the open mode back; XXXX add access checks */
4795 smb_SetSMBParm(outp, 6, (share & 0xf));
4796 smb_SetSMBDataLength(outp, 0);
4797 lock_ReleaseMutex(&scp->mx);
4800 cm_Open(scp, 0, userp);
4802 /* send and free packet */
4803 smb_ReleaseFID(fidp);
4804 cm_ReleaseUser(userp);
4805 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4809 typedef struct smb_unlinkRock {
4814 char *maskp; /* pointer to the star pattern */
4819 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4822 smb_unlinkRock_t *rockp;
4830 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4831 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4832 caseFold |= CM_FLAG_8DOT3;
4834 matchName = dep->name;
4835 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4837 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4838 !cm_Is8Dot3(dep->name)) {
4839 cm_Gen8Dot3Name(dep, shortName, NULL);
4840 matchName = shortName;
4841 /* 8.3 matches are always case insensitive */
4842 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4845 osi_Log1(smb_logp, "Unlinking %s",
4846 osi_LogSaveString(smb_logp, matchName));
4847 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4848 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4849 smb_NotifyChange(FILE_ACTION_REMOVED,
4850 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4851 dscp, dep->name, NULL, TRUE);
4855 /* If we made a case sensitive exact match, we might as well quit now. */
4856 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4857 code = CM_ERROR_STOPNOW;
4865 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4874 smb_unlinkRock_t rock;
4883 attribute = smb_GetSMBParm(inp, 0);
4885 tp = smb_GetSMBData(inp, NULL);
4886 pathp = smb_ParseASCIIBlock(tp, &tp);
4887 if (smb_StoreAnsiFilenames)
4888 OemToChar(pathp,pathp);
4890 osi_Log1(smb_logp, "SMB receive unlink %s",
4891 osi_LogSaveString(smb_logp, pathp));
4893 spacep = inp->spacep;
4894 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4896 userp = smb_GetUserFromVCP(vcp, inp);
4898 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4900 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4902 cm_ReleaseUser(userp);
4903 return CM_ERROR_NOSUCHPATH;
4905 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4908 cm_ReleaseUser(userp);
4913 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4914 cm_ReleaseSCache(dscp);
4915 cm_ReleaseUser(userp);
4916 if ( WANTS_DFS_PATHNAMES(inp) )
4917 return CM_ERROR_PATH_NOT_COVERED;
4919 return CM_ERROR_BADSHARENAME;
4921 #endif /* DFS_SUPPORT */
4923 /* otherwise, scp points to the parent directory. */
4930 rock.maskp = smb_FindMask(pathp);
4931 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4934 thyper.HighPart = 0;
4940 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4941 * match. If that fails, we do a case insensitve match.
4943 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4944 !smb_IsStarMask(rock.maskp)) {
4945 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4948 thyper.HighPart = 0;
4949 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4954 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4956 if (code == CM_ERROR_STOPNOW)
4959 cm_ReleaseUser(userp);
4961 cm_ReleaseSCache(dscp);
4963 if (code == 0 && !rock.any)
4964 code = CM_ERROR_NOSUCHFILE;
4968 typedef struct smb_renameRock {
4969 cm_scache_t *odscp; /* old dir */
4970 cm_scache_t *ndscp; /* new dir */
4971 cm_user_t *userp; /* user */
4972 cm_req_t *reqp; /* request struct */
4973 smb_vc_t *vcp; /* virtual circuit */
4974 char *maskp; /* pointer to star pattern of old file name */
4975 int flags; /* tilde, casefold, etc */
4976 char *newNamep; /* ptr to the new file's name */
4979 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4982 smb_renameRock_t *rockp;
4987 rockp = (smb_renameRock_t *) vrockp;
4989 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4990 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4991 caseFold |= CM_FLAG_8DOT3;
4993 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4995 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4996 !cm_Is8Dot3(dep->name)) {
4997 cm_Gen8Dot3Name(dep, shortName, NULL);
4998 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5001 code = cm_Rename(rockp->odscp, dep->name,
5002 rockp->ndscp, rockp->newNamep, rockp->userp,
5004 /* if the call worked, stop doing the search now, since we
5005 * really only want to rename one file.
5008 code = CM_ERROR_STOPNOW;
5017 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5020 cm_space_t *spacep = NULL;
5021 smb_renameRock_t rock;
5022 cm_scache_t *oldDscp = NULL;
5023 cm_scache_t *newDscp = NULL;
5024 cm_scache_t *tmpscp= NULL;
5025 cm_scache_t *tmpscp2 = NULL;
5035 userp = smb_GetUserFromVCP(vcp, inp);
5036 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5038 cm_ReleaseUser(userp);
5039 return CM_ERROR_NOSUCHPATH;
5043 spacep = inp->spacep;
5044 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5046 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5047 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5048 userp, tidPathp, &req, &oldDscp);
5050 cm_ReleaseUser(userp);
5055 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5056 cm_ReleaseSCache(oldDscp);
5057 cm_ReleaseUser(userp);
5058 if ( WANTS_DFS_PATHNAMES(inp) )
5059 return CM_ERROR_PATH_NOT_COVERED;
5061 return CM_ERROR_BADSHARENAME;
5063 #endif /* DFS_SUPPORT */
5065 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5066 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5067 userp, tidPathp, &req, &newDscp);
5070 cm_ReleaseSCache(oldDscp);
5071 cm_ReleaseUser(userp);
5076 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5077 cm_ReleaseSCache(oldDscp);
5078 cm_ReleaseSCache(newDscp);
5079 cm_ReleaseUser(userp);
5080 if ( WANTS_DFS_PATHNAMES(inp) )
5081 return CM_ERROR_PATH_NOT_COVERED;
5083 return CM_ERROR_BADSHARENAME;
5085 #endif /* DFS_SUPPORT */
5088 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5089 * next, get the component names, and lower case them.
5092 /* handle the old name first */
5094 oldLastNamep = oldPathp;
5098 /* and handle the new name, too */
5100 newLastNamep = newPathp;
5104 /* TODO: The old name could be a wildcard. The new name must not be */
5106 /* do the vnode call */
5107 rock.odscp = oldDscp;
5108 rock.ndscp = newDscp;
5112 rock.maskp = oldLastNamep;
5113 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5114 rock.newNamep = newLastNamep;
5116 /* Check if the file already exists; if so return error */
5117 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5118 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5119 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5120 osi_LogSaveString(afsd_logp, newLastNamep));
5122 /* Check if the old and the new names differ only in case. If so return
5123 * success, else return CM_ERROR_EXISTS
5125 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5127 /* This would be a success only if the old file is *as same as* the new file */
5128 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5130 if (tmpscp == tmpscp2)
5133 code = CM_ERROR_EXISTS;
5134 cm_ReleaseSCache(tmpscp2);
5137 code = CM_ERROR_NOSUCHFILE;
5140 /* file exist, do not rename, also fixes move */
5141 osi_Log0(smb_logp, "Can't rename. Target already exists");
5142 code = CM_ERROR_EXISTS;
5146 cm_ReleaseSCache(tmpscp);
5147 cm_ReleaseSCache(newDscp);
5148 cm_ReleaseSCache(oldDscp);
5149 cm_ReleaseUser(userp);
5153 /* Now search the directory for the pattern, and do the appropriate rename when found */
5154 thyper.LowPart = 0; /* search dir from here */
5155 thyper.HighPart = 0;
5157 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5158 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5160 if (code == CM_ERROR_STOPNOW)
5163 code = CM_ERROR_NOSUCHFILE;
5165 /* Handle Change Notification */
5167 * Being lazy, not distinguishing between files and dirs in this
5168 * filter, since we'd have to do a lookup.
5170 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5171 if (oldDscp == newDscp) {
5172 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5173 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5174 filter, oldDscp, oldLastNamep,
5175 newLastNamep, TRUE);
5177 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5178 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5179 filter, oldDscp, oldLastNamep,
5181 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5182 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5183 filter, newDscp, newLastNamep,
5188 cm_ReleaseSCache(tmpscp);
5189 cm_ReleaseUser(userp);
5190 cm_ReleaseSCache(oldDscp);
5191 cm_ReleaseSCache(newDscp);
5196 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5199 cm_space_t *spacep = NULL;
5200 cm_scache_t *oldDscp = NULL;
5201 cm_scache_t *newDscp = NULL;
5202 cm_scache_t *tmpscp= NULL;
5203 cm_scache_t *tmpscp2 = NULL;
5204 cm_scache_t *sscp = NULL;
5213 userp = smb_GetUserFromVCP(vcp, inp);
5215 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5217 cm_ReleaseUser(userp);
5218 return CM_ERROR_NOSUCHPATH;
5223 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5225 spacep = inp->spacep;
5226 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5228 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5229 userp, tidPathp, &req, &oldDscp);
5231 cm_ReleaseUser(userp);
5236 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5237 cm_ReleaseSCache(oldDscp);
5238 cm_ReleaseUser(userp);
5239 if ( WANTS_DFS_PATHNAMES(inp) )
5240 return CM_ERROR_PATH_NOT_COVERED;
5242 return CM_ERROR_BADSHARENAME;
5244 #endif /* DFS_SUPPORT */
5246 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5247 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5248 userp, tidPathp, &req, &newDscp);
5250 cm_ReleaseSCache(oldDscp);
5251 cm_ReleaseUser(userp);
5256 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5257 cm_ReleaseSCache(newDscp);
5258 cm_ReleaseSCache(oldDscp);
5259 cm_ReleaseUser(userp);
5260 if ( WANTS_DFS_PATHNAMES(inp) )
5261 return CM_ERROR_PATH_NOT_COVERED;
5263 return CM_ERROR_BADSHARENAME;
5265 #endif /* DFS_SUPPORT */
5267 /* Now, although we did two lookups for the two directories (because the same
5268 * directory can be referenced through different paths), we only allow hard links
5269 * within the same directory. */
5270 if (oldDscp != newDscp) {
5271 cm_ReleaseSCache(oldDscp);
5272 cm_ReleaseSCache(newDscp);
5273 cm_ReleaseUser(userp);
5274 return CM_ERROR_CROSSDEVLINK;
5277 /* handle the old name first */
5279 oldLastNamep = oldPathp;
5283 /* and handle the new name, too */
5285 newLastNamep = newPathp;
5289 /* now lookup the old name */
5290 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5291 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5293 cm_ReleaseSCache(oldDscp);
5294 cm_ReleaseSCache(newDscp);
5295 cm_ReleaseUser(userp);
5299 /* Check if the file already exists; if so return error */
5300 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5301 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5302 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5303 osi_LogSaveString(afsd_logp, newLastNamep));
5305 /* if the existing link is to the same file, then we return success */
5307 if(sscp == tmpscp) {
5310 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5311 code = CM_ERROR_EXISTS;
5316 cm_ReleaseSCache(tmpscp);
5317 cm_ReleaseSCache(sscp);
5318 cm_ReleaseSCache(newDscp);
5319 cm_ReleaseSCache(oldDscp);
5320 cm_ReleaseUser(userp);
5324 /* now create the hardlink */
5325 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5326 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5327 osi_Log1(smb_logp," Link returns 0x%x", code);
5329 /* Handle Change Notification */
5331 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5332 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5333 smb_NotifyChange(FILE_ACTION_ADDED,
5334 filter, newDscp, newLastNamep,
5339 cm_ReleaseSCache(tmpscp);
5340 cm_ReleaseUser(userp);
5341 cm_ReleaseSCache(sscp);
5342 cm_ReleaseSCache(oldDscp);
5343 cm_ReleaseSCache(newDscp);
5348 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5354 tp = smb_GetSMBData(inp, NULL);
5355 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5356 if (smb_StoreAnsiFilenames)
5357 OemToChar(oldPathp,oldPathp);
5358 newPathp = smb_ParseASCIIBlock(tp, &tp);
5359 if (smb_StoreAnsiFilenames)
5360 OemToChar(newPathp,newPathp);
5362 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5363 osi_LogSaveString(smb_logp, oldPathp),
5364 osi_LogSaveString(smb_logp, newPathp));
5366 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5371 typedef struct smb_rmdirRock {
5375 char *maskp; /* pointer to the star pattern */
5380 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5383 smb_rmdirRock_t *rockp;
5388 rockp = (smb_rmdirRock_t *) vrockp;
5390 matchName = dep->name;
5391 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5392 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5394 match = (strcmp(matchName, rockp->maskp) == 0);
5396 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5397 !cm_Is8Dot3(dep->name)) {
5398 cm_Gen8Dot3Name(dep, shortName, NULL);
5399 matchName = shortName;
5400 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5403 osi_Log1(smb_logp, "Removing directory %s",
5404 osi_LogSaveString(smb_logp, matchName));
5405 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5406 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5407 smb_NotifyChange(FILE_ACTION_REMOVED,
5408 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5409 dscp, dep->name, NULL, TRUE);
5418 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5426 smb_rmdirRock_t rock;
5435 tp = smb_GetSMBData(inp, NULL);
5436 pathp = smb_ParseASCIIBlock(tp, &tp);
5437 if (smb_StoreAnsiFilenames)
5438 OemToChar(pathp,pathp);
5440 spacep = inp->spacep;
5441 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5443 userp = smb_GetUserFromVCP(vcp, inp);
5445 caseFold = CM_FLAG_CASEFOLD;
5447 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5449 cm_ReleaseUser(userp);
5450 return CM_ERROR_NOSUCHPATH;
5452 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5453 userp, tidPathp, &req, &dscp);
5456 cm_ReleaseUser(userp);
5461 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5462 cm_ReleaseSCache(dscp);
5463 cm_ReleaseUser(userp);
5464 if ( WANTS_DFS_PATHNAMES(inp) )
5465 return CM_ERROR_PATH_NOT_COVERED;
5467 return CM_ERROR_BADSHARENAME;
5469 #endif /* DFS_SUPPORT */
5471 /* otherwise, scp points to the parent directory. */
5478 rock.maskp = lastNamep;
5479 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5482 thyper.HighPart = 0;
5486 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5487 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5488 if (code == 0 && !rock.any) {
5490 thyper.HighPart = 0;
5491 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5492 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5495 cm_ReleaseUser(userp);
5497 cm_ReleaseSCache(dscp);
5499 if (code == 0 && !rock.any)
5500 code = CM_ERROR_NOSUCHFILE;
5504 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5514 fid = smb_GetSMBParm(inp, 0);
5516 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5518 fid = smb_ChainFID(fid, inp);
5519 fidp = smb_FindFID(vcp, fid, 0);
5521 return CM_ERROR_BADFD;
5523 lock_ObtainMutex(&fidp->mx);
5524 if (fidp->flags & SMB_FID_IOCTL) {
5525 lock_ReleaseMutex(&fidp->mx);
5526 smb_ReleaseFID(fidp);
5527 return CM_ERROR_BADFD;
5529 lock_ReleaseMutex(&fidp->mx);
5531 userp = smb_GetUserFromVCP(vcp, inp);
5533 lock_ObtainMutex(&fidp->mx);
5534 if (fidp->flags & SMB_FID_OPENWRITE) {
5535 cm_scache_t * scp = fidp->scp;
5537 lock_ReleaseMutex(&fidp->mx);
5538 code = cm_FSync(scp, userp, &req);
5539 cm_ReleaseSCache(scp);
5542 lock_ReleaseMutex(&fidp->mx);
5545 smb_ReleaseFID(fidp);
5547 cm_ReleaseUser(userp);
5552 struct smb_FullNameRock {
5558 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5562 struct smb_FullNameRock *vrockp;
5564 vrockp = (struct smb_FullNameRock *)rockp;
5566 if (!cm_Is8Dot3(dep->name)) {
5567 cm_Gen8Dot3Name(dep, shortName, NULL);
5569 if (cm_stricmp(shortName, vrockp->name) == 0) {
5570 vrockp->fullName = strdup(dep->name);
5571 return CM_ERROR_STOPNOW;
5574 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5575 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5576 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5577 vrockp->fullName = strdup(dep->name);
5578 return CM_ERROR_STOPNOW;
5583 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5584 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5586 struct smb_FullNameRock rock;
5592 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5593 if (code == CM_ERROR_STOPNOW)
5594 *newPathp = rock.fullName;
5596 *newPathp = strdup(pathp);
5599 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5600 afs_uint32 dosTime) {
5603 cm_scache_t *dscp = fidp->NTopen_dscp;
5604 char *pathp = fidp->NTopen_pathp;
5605 cm_scache_t * scp = fidp->scp;
5607 int nullcreator = 0;
5609 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5610 fidp, fidp->fid, vcp);
5613 lock_ObtainMutex(&fidp->mx);
5614 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5615 lock_ReleaseMutex(&fidp->mx);
5616 osi_Log0(smb_logp, " No user specified. Not closing fid");
5617 return CM_ERROR_BADFD;
5620 userp = fidp->userp; /* no hold required since fidp is held
5621 throughout the function */
5622 lock_ReleaseMutex(&fidp->mx);
5627 lock_ObtainWrite(&smb_rctLock);
5629 osi_Log0(smb_logp, " Fid already closed.");
5630 lock_ReleaseWrite(&smb_rctLock);
5631 return CM_ERROR_BADFD;
5634 lock_ReleaseWrite(&smb_rctLock);
5636 lock_ObtainMutex(&fidp->mx);
5637 /* Don't jump the gun on an async raw write */
5638 while (fidp->raw_writers) {
5639 lock_ReleaseMutex(&fidp->mx);
5640 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5641 lock_ObtainMutex(&fidp->mx);
5644 /* watch for ioctl closes, and read-only opens */
5646 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5647 == SMB_FID_OPENWRITE) {
5648 if (dosTime != 0 && dosTime != -1) {
5649 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5650 /* This fixes defect 10958 */
5651 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5652 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5654 lock_ReleaseMutex(&fidp->mx);
5655 code = cm_FSync(scp, userp, &req);
5656 lock_ObtainMutex(&fidp->mx);
5661 /* unlock any pending locks */
5662 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5663 scp->fileType == CM_SCACHETYPE_FILE) {
5667 lock_ReleaseMutex(&fidp->mx);
5669 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5671 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5672 lock_ObtainMutex(&scp->mx);
5674 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5675 CM_SCACHESYNC_NEEDCALLBACK
5676 | CM_SCACHESYNC_GETSTATUS
5677 | CM_SCACHESYNC_LOCK);
5681 "smb CoreClose SyncOp failure code 0x%x", tcode);
5682 goto post_syncopdone;
5685 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5687 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5691 lock_ReleaseMutex(&scp->mx);
5692 lock_ObtainMutex(&fidp->mx);
5695 if (fidp->flags & SMB_FID_DELONCLOSE) {
5698 lock_ReleaseMutex(&fidp->mx);
5699 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5700 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5701 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5704 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5705 smb_NotifyChange(FILE_ACTION_REMOVED,
5706 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5707 dscp, fullPathp, NULL, TRUE);
5710 code = cm_Unlink(dscp, fullPathp, userp, &req);
5713 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5714 smb_NotifyChange(FILE_ACTION_REMOVED,
5715 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5716 dscp, fullPathp, NULL, TRUE);
5720 lock_ObtainMutex(&fidp->mx);
5721 fidp->flags &= ~SMB_FID_DELONCLOSE;
5724 /* if this was a newly created file, then clear the creator
5725 * in the stat cache entry. */
5726 if (fidp->flags & SMB_FID_CREATED) {
5728 fidp->flags &= ~SMB_FID_CREATED;
5731 if (fidp->flags & SMB_FID_NTOPEN) {
5732 fidp->NTopen_dscp = NULL;
5733 fidp->NTopen_pathp = NULL;
5734 fidp->flags &= ~SMB_FID_NTOPEN;
5736 if (fidp->NTopen_wholepathp) {
5737 free(fidp->NTopen_wholepathp);
5738 fidp->NTopen_wholepathp = NULL;
5741 lock_ReleaseMutex(&fidp->mx);
5744 cm_ReleaseSCache(dscp);
5747 if (deleted || nullcreator) {
5748 lock_ObtainMutex(&scp->mx);
5749 if (nullcreator && scp->creator == userp)
5750 scp->creator = NULL;
5752 scp->flags |= CM_SCACHEFLAG_DELETED;
5753 lock_ReleaseMutex(&scp->mx);
5755 cm_ReleaseSCache(scp);
5764 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5772 fid = smb_GetSMBParm(inp, 0);
5773 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5775 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5777 fid = smb_ChainFID(fid, inp);
5778 fidp = smb_FindFID(vcp, fid, 0);
5780 return CM_ERROR_BADFD;
5783 userp = smb_GetUserFromVCP(vcp, inp);
5785 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5787 smb_ReleaseFID(fidp);
5788 cm_ReleaseUser(userp);
5793 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5795 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5796 cm_user_t *userp, long *readp)
5802 osi_hyper_t fileLength;
5804 osi_hyper_t lastByte;
5805 osi_hyper_t bufferOffset;
5806 long bufIndex, nbytes;
5808 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5816 lock_ObtainMutex(&fidp->mx);
5818 lock_ObtainMutex(&scp->mx);
5820 if (offset.HighPart == 0) {
5821 chunk = offset.LowPart >> cm_logChunkSize;
5822 if (chunk != fidp->curr_chunk) {
5823 fidp->prev_chunk = fidp->curr_chunk;
5824 fidp->curr_chunk = chunk;
5826 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5829 lock_ReleaseMutex(&fidp->mx);
5831 /* start by looking up the file's end */
5832 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5833 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5837 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5839 /* now we have the entry locked, look up the length */
5840 fileLength = scp->length;
5842 /* adjust count down so that it won't go past EOF */
5843 thyper.LowPart = count;
5844 thyper.HighPart = 0;
5845 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5847 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5848 /* we'd read past EOF, so just stop at fileLength bytes.
5849 * Start by computing how many bytes remain in the file.
5851 thyper = LargeIntegerSubtract(fileLength, offset);
5853 /* if we are past EOF, read 0 bytes */
5854 if (LargeIntegerLessThanZero(thyper))
5857 count = thyper.LowPart;
5862 /* now, copy the data one buffer at a time,
5863 * until we've filled the request packet
5866 /* if we've copied all the data requested, we're done */
5867 if (count <= 0) break;
5869 /* otherwise, load up a buffer of data */
5870 thyper.HighPart = offset.HighPart;
5871 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5872 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5875 buf_Release(bufferp);
5878 lock_ReleaseMutex(&scp->mx);
5880 lock_ObtainRead(&scp->bufCreateLock);
5881 code = buf_Get(scp, &thyper, &bufferp);
5882 lock_ReleaseRead(&scp->bufCreateLock);
5884 lock_ObtainMutex(&scp->mx);
5885 if (code) goto done;
5886 bufferOffset = thyper;
5888 /* now get the data in the cache */
5890 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5891 CM_SCACHESYNC_NEEDCALLBACK |
5892 CM_SCACHESYNC_READ);
5896 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5898 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5900 /* otherwise, load the buffer and try again */
5901 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5905 buf_Release(bufferp);
5909 } /* if (wrong buffer) ... */
5911 /* now we have the right buffer loaded. Copy out the
5912 * data from here to the user's buffer.
5914 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5916 /* and figure out how many bytes we want from this buffer */
5917 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5918 if (nbytes > count) nbytes = count; /* don't go past EOF */
5920 /* now copy the data */
5921 memcpy(op, bufferp->datap + bufIndex, nbytes);
5923 /* adjust counters, pointers, etc. */
5926 thyper.LowPart = nbytes;
5927 thyper.HighPart = 0;
5928 offset = LargeIntegerAdd(thyper, offset);
5932 lock_ReleaseMutex(&scp->mx);
5934 buf_Release(bufferp);
5936 if (code == 0 && sequential)
5937 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5943 * smb_WriteData -- common code for Write and Raw Write
5945 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5946 cm_user_t *userp, long *writtenp)
5952 osi_hyper_t fileLength; /* file's length at start of write */
5953 osi_hyper_t minLength; /* don't read past this */
5954 long nbytes; /* # of bytes to transfer this iteration */
5956 osi_hyper_t thyper; /* hyper tmp variable */
5957 osi_hyper_t bufferOffset;
5958 long bufIndex; /* index in buffer where our data is */
5960 osi_hyper_t writeBackOffset;/* offset of region to write back when
5965 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5966 fidp->fid, offsetp->LowPart, count);
5976 lock_ObtainMutex(&fidp->mx);
5977 /* make sure we have a writable FD */
5978 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5979 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
5980 fidp->fid, fidp->flags);
5981 lock_ReleaseMutex(&fidp->mx);
5982 code = CM_ERROR_BADFDOP;
5988 lock_ReleaseMutex(&fidp->mx);
5990 lock_ObtainMutex(&scp->mx);
5991 /* start by looking up the file's end */
5992 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5993 CM_SCACHESYNC_NEEDCALLBACK
5994 | CM_SCACHESYNC_SETSTATUS
5995 | CM_SCACHESYNC_GETSTATUS);
5999 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6001 /* now we have the entry locked, look up the length */
6002 fileLength = scp->length;
6003 minLength = fileLength;
6004 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6005 minLength = scp->serverLength;
6007 /* adjust file length if we extend past EOF */
6008 thyper.LowPart = count;
6009 thyper.HighPart = 0;
6010 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6011 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6012 /* we'd write past EOF, so extend the file */
6013 scp->mask |= CM_SCACHEMASK_LENGTH;
6014 scp->length = thyper;
6015 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6017 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6019 /* now, if the new position (thyper) and the old (offset) are in
6020 * different storeback windows, remember to store back the previous
6021 * storeback window when we're done with the write.
6023 if ((thyper.LowPart & (-cm_chunkSize)) !=
6024 (offset.LowPart & (-cm_chunkSize))) {
6025 /* they're different */
6027 writeBackOffset.HighPart = offset.HighPart;
6028 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6033 /* now, copy the data one buffer at a time, until we've filled the
6036 /* if we've copied all the data requested, we're done */
6040 /* handle over quota or out of space */
6041 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6042 *writtenp = written;
6043 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6047 /* otherwise, load up a buffer of data */
6048 thyper.HighPart = offset.HighPart;
6049 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6050 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6053 lock_ReleaseMutex(&bufferp->mx);
6054 buf_Release(bufferp);
6057 lock_ReleaseMutex(&scp->mx);
6059 lock_ObtainRead(&scp->bufCreateLock);
6060 code = buf_Get(scp, &thyper, &bufferp);
6061 lock_ReleaseRead(&scp->bufCreateLock);
6063 lock_ObtainMutex(&bufferp->mx);
6064 lock_ObtainMutex(&scp->mx);
6065 if (code) goto done;
6067 bufferOffset = thyper;
6069 /* now get the data in the cache */
6071 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6072 CM_SCACHESYNC_NEEDCALLBACK
6073 | CM_SCACHESYNC_WRITE
6074 | CM_SCACHESYNC_BUFLOCKED);
6078 cm_SyncOpDone(scp, bufferp,
6079 CM_SCACHESYNC_NEEDCALLBACK
6080 | CM_SCACHESYNC_WRITE
6081 | CM_SCACHESYNC_BUFLOCKED);
6083 /* If we're overwriting the entire buffer, or
6084 * if we're writing at or past EOF, mark the
6085 * buffer as current so we don't call
6086 * cm_GetBuffer. This skips the fetch from the
6087 * server in those cases where we're going to
6088 * obliterate all the data in the buffer anyway,
6089 * or in those cases where there is no useful
6090 * data at the server to start with.
6092 * Use minLength instead of scp->length, since
6093 * the latter has already been updated by this
6096 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6097 || LargeIntegerEqualTo(offset, bufferp->offset)
6098 && (count >= cm_data.buf_blockSize
6099 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6100 ConvertLongToLargeInteger(count)),
6102 if (count < cm_data.buf_blockSize
6103 && bufferp->dataVersion == -1)
6104 memset(bufferp->datap, 0,
6105 cm_data.buf_blockSize);
6106 bufferp->dataVersion = scp->dataVersion;
6109 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6111 /* otherwise, load the buffer and try again */
6112 lock_ReleaseMutex(&bufferp->mx);
6113 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6115 lock_ReleaseMutex(&scp->mx);
6116 lock_ObtainMutex(&bufferp->mx);
6117 lock_ObtainMutex(&scp->mx);
6121 lock_ReleaseMutex(&bufferp->mx);
6122 buf_Release(bufferp);
6126 } /* if (wrong buffer) ... */
6128 /* now we have the right buffer loaded. Copy out the
6129 * data from here to the user's buffer.
6131 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6133 /* and figure out how many bytes we want from this buffer */
6134 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6136 nbytes = count; /* don't go past end of request */
6138 /* now copy the data */
6139 memcpy(bufferp->datap + bufIndex, op, nbytes);
6140 buf_SetDirty(bufferp);
6142 /* and record the last writer */
6143 if (bufferp->userp != userp) {
6146 cm_ReleaseUser(bufferp->userp);
6147 bufferp->userp = userp;
6150 /* adjust counters, pointers, etc. */
6154 thyper.LowPart = nbytes;
6155 thyper.HighPart = 0;
6156 offset = LargeIntegerAdd(thyper, offset);
6160 lock_ReleaseMutex(&scp->mx);
6163 lock_ReleaseMutex(&bufferp->mx);
6164 buf_Release(bufferp);
6167 lock_ObtainMutex(&fidp->mx);
6168 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6169 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6170 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6171 fidp->NTopen_dscp, fidp->NTopen_pathp,
6174 lock_ReleaseMutex(&fidp->mx);
6176 if (code == 0 && doWriteBack) {
6178 lock_ObtainMutex(&scp->mx);
6179 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6181 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6182 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6184 lock_ReleaseMutex(&scp->mx);
6185 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6186 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6187 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6190 cm_ReleaseSCache(scp);
6192 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6193 fidp->fid, code, *writtenp);
6197 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6200 unsigned short count;
6202 unsigned short hint;
6203 long written = 0, total_written = 0;
6208 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6210 int inDataBlockCount;
6212 fd = smb_GetSMBParm(inp, 0);
6213 count = smb_GetSMBParm(inp, 1);
6214 offset.HighPart = 0; /* too bad */
6215 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6216 hint = smb_GetSMBParm(inp, 4);
6218 op = smb_GetSMBData(inp, NULL);
6219 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6221 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6222 fd, offset.LowPart, count);
6224 fd = smb_ChainFID(fd, inp);
6225 fidp = smb_FindFID(vcp, fd, 0);
6227 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6228 return CM_ERROR_BADFD;
6231 lock_ObtainMutex(&fidp->mx);
6232 if (fidp->flags & SMB_FID_IOCTL) {
6233 lock_ReleaseMutex(&fidp->mx);
6234 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6235 smb_ReleaseFID(fidp);
6236 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6239 lock_ReleaseMutex(&fidp->mx);
6240 userp = smb_GetUserFromVCP(vcp, inp);
6244 LARGE_INTEGER LOffset;
6245 LARGE_INTEGER LLength;
6247 pid = ((smb_t *) inp)->pid;
6248 key = cm_GenerateKey(vcp->vcID, pid, fd);
6250 LOffset.HighPart = offset.HighPart;
6251 LOffset.LowPart = offset.LowPart;
6252 LLength.HighPart = 0;
6253 LLength.LowPart = count;
6255 lock_ObtainMutex(&fidp->scp->mx);
6256 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6257 lock_ReleaseMutex(&fidp->scp->mx);
6260 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6265 /* special case: 0 bytes transferred means truncate to this position */
6269 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6273 truncAttr.mask = CM_ATTRMASK_LENGTH;
6274 truncAttr.length.LowPart = offset.LowPart;
6275 truncAttr.length.HighPart = 0;
6276 lock_ObtainMutex(&fidp->mx);
6277 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6278 fidp->flags |= SMB_FID_LENGTHSETDONE;
6279 lock_ReleaseMutex(&fidp->mx);
6280 smb_SetSMBParm(outp, 0, 0 /* count */);
6281 smb_SetSMBDataLength(outp, 0);
6286 * Work around bug in NT client
6288 * When copying a file, the NT client should first copy the data,
6289 * then copy the last write time. But sometimes the NT client does
6290 * these in the wrong order, so the data copies would inadvertently
6291 * cause the last write time to be overwritten. We try to detect this,
6292 * and don't set client mod time if we think that would go against the
6295 lock_ObtainMutex(&fidp->mx);
6296 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6297 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6298 fidp->scp->clientModTime = time(NULL);
6300 lock_ReleaseMutex(&fidp->mx);
6303 while ( code == 0 && count > 0 ) {
6304 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6305 if (code == 0 && written == 0)
6306 code = CM_ERROR_PARTIALWRITE;
6308 offset = LargeIntegerAdd(offset,
6309 ConvertLongToLargeInteger(written));
6311 total_written += written;
6315 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6316 total_written, code);
6318 /* set the packet data length to 3 bytes for the data block header,
6319 * plus the size of the data.
6321 smb_SetSMBParm(outp, 0, total_written);
6322 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6323 smb_SetSMBParm(outp, 3, hint);
6324 smb_SetSMBDataLength(outp, 0);
6327 smb_ReleaseFID(fidp);
6328 cm_ReleaseUser(userp);
6333 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6334 NCB *ncbp, raw_write_cont_t *rwcp)
6343 fd = smb_GetSMBParm(inp, 0);
6344 fidp = smb_FindFID(vcp, fd, 0);
6346 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6347 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6349 userp = smb_GetUserFromVCP(vcp, inp);
6352 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6354 if (rwcp->writeMode & 0x1) { /* synchronous */
6357 smb_FormatResponsePacket(vcp, inp, outp);
6358 op = (smb_t *) outp;
6359 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6360 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6361 smb_SetSMBDataLength(outp, 0);
6362 smb_SendPacket(vcp, outp);
6363 smb_FreePacket(outp);
6365 else { /* asynchronous */
6366 lock_ObtainMutex(&fidp->mx);
6367 fidp->raw_writers--;
6368 if (fidp->raw_writers == 0)
6369 thrd_SetEvent(fidp->raw_write_event);
6370 lock_ReleaseMutex(&fidp->mx);
6373 /* Give back raw buffer */
6374 lock_ObtainMutex(&smb_RawBufLock);
6375 *((char **)rawBuf) = smb_RawBufs;
6376 smb_RawBufs = rawBuf;
6377 lock_ReleaseMutex(&smb_RawBufLock);
6379 smb_ReleaseFID(fidp);
6380 cm_ReleaseUser(userp);
6383 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6388 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6391 long count, written = 0, total_written = 0;
6398 unsigned short writeMode;
6400 fd = smb_GetSMBParm(inp, 0);
6401 totalCount = smb_GetSMBParm(inp, 1);
6402 count = smb_GetSMBParm(inp, 10);
6403 writeMode = smb_GetSMBParm(inp, 7);
6405 op = (char *) inp->data;
6406 op += smb_GetSMBParm(inp, 11);
6408 offset.HighPart = 0;
6409 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6411 if (*inp->wctp == 14) {
6412 /* we received a 64-bit file offset */
6413 #ifdef AFS_LARGEFILES
6414 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6416 if (LargeIntegerLessThanZero(offset)) {
6418 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6419 offset.HighPart, offset.LowPart);
6420 return CM_ERROR_BADSMB;
6423 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6425 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6426 return CM_ERROR_BADSMB;
6429 offset.HighPart = 0;
6432 offset.HighPart = 0; /* 32-bit file offset */
6436 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6437 fd, offset.HighPart, offset.LowPart, count);
6439 " WriteRaw WriteMode 0x%x",
6442 fd = smb_ChainFID(fd, inp);
6443 fidp = smb_FindFID(vcp, fd, 0);
6445 return CM_ERROR_BADFD;
6451 LARGE_INTEGER LOffset;
6452 LARGE_INTEGER LLength;
6454 pid = ((smb_t *) inp)->pid;
6455 key = cm_GenerateKey(vcp->vcID, pid, fd);
6457 LOffset.HighPart = offset.HighPart;
6458 LOffset.LowPart = offset.LowPart;
6459 LLength.HighPart = 0;
6460 LLength.LowPart = count;
6462 lock_ObtainMutex(&fidp->scp->mx);
6463 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6464 lock_ReleaseMutex(&fidp->scp->mx);
6467 smb_ReleaseFID(fidp);
6472 userp = smb_GetUserFromVCP(vcp, inp);
6475 * Work around bug in NT client
6477 * When copying a file, the NT client should first copy the data,
6478 * then copy the last write time. But sometimes the NT client does
6479 * these in the wrong order, so the data copies would inadvertently
6480 * cause the last write time to be overwritten. We try to detect this,
6481 * and don't set client mod time if we think that would go against the
6484 lock_ObtainMutex(&fidp->mx);
6485 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6486 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6487 fidp->scp->clientModTime = time(NULL);
6489 lock_ReleaseMutex(&fidp->mx);
6492 while ( code == 0 && count > 0 ) {
6493 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6494 if (code == 0 && written == 0)
6495 code = CM_ERROR_PARTIALWRITE;
6497 offset = LargeIntegerAdd(offset,
6498 ConvertLongToLargeInteger(written));
6501 total_written += written;
6505 /* Get a raw buffer */
6508 lock_ObtainMutex(&smb_RawBufLock);
6510 /* Get a raw buf, from head of list */
6511 rawBuf = smb_RawBufs;
6512 smb_RawBufs = *(char **)smb_RawBufs;
6515 code = CM_ERROR_USESTD;
6517 lock_ReleaseMutex(&smb_RawBufLock);
6520 /* Don't allow a premature Close */
6521 if (code == 0 && (writeMode & 1) == 0) {
6522 lock_ObtainMutex(&fidp->mx);
6523 fidp->raw_writers++;
6524 thrd_ResetEvent(fidp->raw_write_event);
6525 lock_ReleaseMutex(&fidp->mx);
6528 smb_ReleaseFID(fidp);
6529 cm_ReleaseUser(userp);
6532 smb_SetSMBParm(outp, 0, total_written);
6533 smb_SetSMBDataLength(outp, 0);
6534 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6539 offset = LargeIntegerAdd(offset,
6540 ConvertLongToLargeInteger(count));
6544 rwcp->offset.HighPart = offset.HighPart;
6545 rwcp->offset.LowPart = offset.LowPart;
6546 rwcp->count = totalCount - count;
6547 rwcp->writeMode = writeMode;
6548 rwcp->alreadyWritten = total_written;
6550 /* set the packet data length to 3 bytes for the data block header,
6551 * plus the size of the data.
6553 smb_SetSMBParm(outp, 0, 0xffff);
6554 smb_SetSMBDataLength(outp, 0);
6559 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6562 long count, finalCount;
6570 fd = smb_GetSMBParm(inp, 0);
6571 count = smb_GetSMBParm(inp, 1);
6572 offset.HighPart = 0; /* too bad */
6573 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6575 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6576 fd, offset.LowPart, count);
6578 fd = smb_ChainFID(fd, inp);
6579 fidp = smb_FindFID(vcp, fd, 0);
6581 return CM_ERROR_BADFD;
6583 lock_ObtainMutex(&fidp->mx);
6584 if (fidp->flags & SMB_FID_IOCTL) {
6585 lock_ReleaseMutex(&fidp->mx);
6586 code = smb_IoctlRead(fidp, vcp, inp, outp);
6587 smb_ReleaseFID(fidp);
6590 lock_ReleaseMutex(&fidp->mx);
6593 LARGE_INTEGER LOffset, LLength;
6596 pid = ((smb_t *) inp)->pid;
6597 key = cm_GenerateKey(vcp->vcID, pid, fd);
6599 LOffset.HighPart = 0;
6600 LOffset.LowPart = offset.LowPart;
6601 LLength.HighPart = 0;
6602 LLength.LowPart = count;
6604 lock_ObtainMutex(&fidp->scp->mx);
6605 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6606 lock_ReleaseMutex(&fidp->scp->mx);
6609 smb_ReleaseFID(fidp);
6613 userp = smb_GetUserFromVCP(vcp, inp);
6615 /* remember this for final results */
6616 smb_SetSMBParm(outp, 0, count);
6617 smb_SetSMBParm(outp, 1, 0);
6618 smb_SetSMBParm(outp, 2, 0);
6619 smb_SetSMBParm(outp, 3, 0);
6620 smb_SetSMBParm(outp, 4, 0);
6622 /* set the packet data length to 3 bytes for the data block header,
6623 * plus the size of the data.
6625 smb_SetSMBDataLength(outp, count+3);
6627 /* get op ptr after putting in the parms, since otherwise we don't
6628 * know where the data really is.
6630 op = smb_GetSMBData(outp, NULL);
6632 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6633 *op++ = 1; /* data block marker */
6634 *op++ = (unsigned char) (count & 0xff);
6635 *op++ = (unsigned char) ((count >> 8) & 0xff);
6637 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6639 /* fix some things up */
6640 smb_SetSMBParm(outp, 0, finalCount);
6641 smb_SetSMBDataLength(outp, finalCount+3);
6643 smb_ReleaseFID(fidp);
6645 cm_ReleaseUser(userp);
6649 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6656 cm_scache_t *dscp; /* dir we're dealing with */
6657 cm_scache_t *scp; /* file we're creating */
6659 int initialModeBits;
6669 /* compute initial mode bits based on read-only flag in attributes */
6670 initialModeBits = 0777;
6672 tp = smb_GetSMBData(inp, NULL);
6673 pathp = smb_ParseASCIIBlock(tp, &tp);
6674 if (smb_StoreAnsiFilenames)
6675 OemToChar(pathp,pathp);
6677 if (strcmp(pathp, "\\") == 0)
6678 return CM_ERROR_EXISTS;
6680 spacep = inp->spacep;
6681 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6683 userp = smb_GetUserFromVCP(vcp, inp);
6685 caseFold = CM_FLAG_CASEFOLD;
6687 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6689 cm_ReleaseUser(userp);
6690 return CM_ERROR_NOSUCHPATH;
6693 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6694 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6695 userp, tidPathp, &req, &dscp);
6698 cm_ReleaseUser(userp);
6703 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6704 cm_ReleaseSCache(dscp);
6705 cm_ReleaseUser(userp);
6706 if ( WANTS_DFS_PATHNAMES(inp) )
6707 return CM_ERROR_PATH_NOT_COVERED;
6709 return CM_ERROR_BADSHARENAME;
6711 #endif /* DFS_SUPPORT */
6713 /* otherwise, scp points to the parent directory. Do a lookup, and
6714 * fail if we find it. Otherwise, we do the create.
6720 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6721 if (scp) cm_ReleaseSCache(scp);
6722 if (code != CM_ERROR_NOSUCHFILE) {
6723 if (code == 0) code = CM_ERROR_EXISTS;
6724 cm_ReleaseSCache(dscp);
6725 cm_ReleaseUser(userp);
6729 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6730 setAttr.clientModTime = time(NULL);
6731 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6732 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6733 smb_NotifyChange(FILE_ACTION_ADDED,
6734 FILE_NOTIFY_CHANGE_DIR_NAME,
6735 dscp, lastNamep, NULL, TRUE);
6737 /* we don't need this any longer */
6738 cm_ReleaseSCache(dscp);
6741 /* something went wrong creating or truncating the file */
6742 cm_ReleaseUser(userp);
6746 /* otherwise we succeeded */
6747 smb_SetSMBDataLength(outp, 0);
6748 cm_ReleaseUser(userp);
6753 BOOL smb_IsLegalFilename(char *filename)
6756 * Find the longest substring of filename that does not contain
6757 * any of the chars in illegalChars. If that substring is less
6758 * than the length of the whole string, then one or more of the
6759 * illegal chars is in filename.
6761 if (strcspn(filename, illegalChars) < strlen(filename))
6767 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6775 cm_scache_t *dscp; /* dir we're dealing with */
6776 cm_scache_t *scp; /* file we're creating */
6778 int initialModeBits;
6786 int created = 0; /* the file was new */
6791 excl = (inp->inCom == 0x03)? 0 : 1;
6793 attributes = smb_GetSMBParm(inp, 0);
6794 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6796 /* compute initial mode bits based on read-only flag in attributes */
6797 initialModeBits = 0666;
6798 if (attributes & SMB_ATTR_READONLY)
6799 initialModeBits &= ~0222;
6801 tp = smb_GetSMBData(inp, NULL);
6802 pathp = smb_ParseASCIIBlock(tp, &tp);
6803 if (smb_StoreAnsiFilenames)
6804 OemToChar(pathp,pathp);
6806 spacep = inp->spacep;
6807 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6809 userp = smb_GetUserFromVCP(vcp, inp);
6811 caseFold = CM_FLAG_CASEFOLD;
6813 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6815 cm_ReleaseUser(userp);
6816 return CM_ERROR_NOSUCHPATH;
6818 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6819 userp, tidPathp, &req, &dscp);
6822 cm_ReleaseUser(userp);
6827 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6828 cm_ReleaseSCache(dscp);
6829 cm_ReleaseUser(userp);
6830 if ( WANTS_DFS_PATHNAMES(inp) )
6831 return CM_ERROR_PATH_NOT_COVERED;
6833 return CM_ERROR_BADSHARENAME;
6835 #endif /* DFS_SUPPORT */
6837 /* otherwise, scp points to the parent directory. Do a lookup, and
6838 * truncate the file if we find it, otherwise we create the file.
6845 if (!smb_IsLegalFilename(lastNamep))
6846 return CM_ERROR_BADNTFILENAME;
6848 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6849 #ifdef DEBUG_VERBOSE
6852 hexp = osi_HexifyString( lastNamep );
6853 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6858 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6859 if (code && code != CM_ERROR_NOSUCHFILE) {
6860 cm_ReleaseSCache(dscp);
6861 cm_ReleaseUser(userp);
6865 /* if we get here, if code is 0, the file exists and is represented by
6866 * scp. Otherwise, we have to create it.
6870 /* oops, file shouldn't be there */
6871 cm_ReleaseSCache(dscp);
6872 cm_ReleaseSCache(scp);
6873 cm_ReleaseUser(userp);
6874 return CM_ERROR_EXISTS;
6877 setAttr.mask = CM_ATTRMASK_LENGTH;
6878 setAttr.length.LowPart = 0;
6879 setAttr.length.HighPart = 0;
6880 code = cm_SetAttr(scp, &setAttr, userp, &req);
6883 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6884 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6885 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6889 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6890 smb_NotifyChange(FILE_ACTION_ADDED,
6891 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6892 dscp, lastNamep, NULL, TRUE);
6893 } else if (!excl && code == CM_ERROR_EXISTS) {
6894 /* not an exclusive create, and someone else tried
6895 * creating it already, then we open it anyway. We
6896 * don't bother retrying after this, since if this next
6897 * fails, that means that the file was deleted after
6898 * we started this call.
6900 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6903 setAttr.mask = CM_ATTRMASK_LENGTH;
6904 setAttr.length.LowPart = 0;
6905 setAttr.length.HighPart = 0;
6906 code = cm_SetAttr(scp, &setAttr, userp, &req);
6911 /* we don't need this any longer */
6912 cm_ReleaseSCache(dscp);
6915 /* something went wrong creating or truncating the file */
6916 if (scp) cm_ReleaseSCache(scp);
6917 cm_ReleaseUser(userp);
6921 /* make sure we only open files */
6922 if (scp->fileType != CM_SCACHETYPE_FILE) {
6923 cm_ReleaseSCache(scp);
6924 cm_ReleaseUser(userp);
6925 return CM_ERROR_ISDIR;
6928 /* now all we have to do is open the file itself */
6929 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6934 lock_ObtainMutex(&fidp->mx);
6935 /* always create it open for read/write */
6936 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6938 /* remember that the file was newly created */
6940 fidp->flags |= SMB_FID_CREATED;
6942 /* save a pointer to the vnode */
6945 fidp->userp = userp;
6946 lock_ReleaseMutex(&fidp->mx);
6948 smb_SetSMBParm(outp, 0, fidp->fid);
6949 smb_SetSMBDataLength(outp, 0);
6951 cm_Open(scp, 0, userp);
6953 smb_ReleaseFID(fidp);
6954 cm_ReleaseUser(userp);
6955 /* leave scp held since we put it in fidp->scp */
6959 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6962 osi_hyper_t new_offset;
6973 fd = smb_GetSMBParm(inp, 0);
6974 whence = smb_GetSMBParm(inp, 1);
6975 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6977 /* try to find the file descriptor */
6978 fd = smb_ChainFID(fd, inp);
6979 fidp = smb_FindFID(vcp, fd, 0);
6982 return CM_ERROR_BADFD;
6984 lock_ObtainMutex(&fidp->mx);
6985 if (fidp->flags & SMB_FID_IOCTL) {
6986 lock_ReleaseMutex(&fidp->mx);
6987 smb_ReleaseFID(fidp);
6988 return CM_ERROR_BADFD;
6990 lock_ReleaseMutex(&fidp->mx);
6992 userp = smb_GetUserFromVCP(vcp, inp);
6994 lock_ObtainMutex(&fidp->mx);
6997 lock_ReleaseMutex(&fidp->mx);
6998 lock_ObtainMutex(&scp->mx);
6999 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7000 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7002 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7004 /* offset from current offset */
7005 new_offset = LargeIntegerAdd(fidp->offset,
7006 ConvertLongToLargeInteger(offset));
7008 else if (whence == 2) {
7009 /* offset from current EOF */
7010 new_offset = LargeIntegerAdd(scp->length,
7011 ConvertLongToLargeInteger(offset));
7013 new_offset = ConvertLongToLargeInteger(offset);
7016 fidp->offset = new_offset;
7017 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7018 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7019 smb_SetSMBDataLength(outp, 0);
7021 lock_ReleaseMutex(&scp->mx);
7022 smb_ReleaseFID(fidp);
7023 cm_ReleaseSCache(scp);
7024 cm_ReleaseUser(userp);
7028 /* dispatch all of the requests received in a packet. Due to chaining, this may
7029 * be more than one request.
7031 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7032 NCB *ncbp, raw_write_cont_t *rwcp)
7036 unsigned long code = 0;
7037 unsigned char *outWctp;
7038 int nparms; /* # of bytes of parameters */
7040 int nbytes; /* bytes of data, excluding count */
7043 unsigned short errCode;
7044 unsigned long NTStatus;
7046 unsigned char errClass;
7047 unsigned int oldGen;
7048 DWORD oldTime, newTime;
7050 /* get easy pointer to the data */
7051 smbp = (smb_t *) inp->data;
7053 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7054 /* setup the basic parms for the initial request in the packet */
7055 inp->inCom = smbp->com;
7056 inp->wctp = &smbp->wct;
7058 inp->ncb_length = ncbp->ncb_length;
7063 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7064 /* log it and discard it */
7065 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7066 __FILE__, __LINE__, ncbp->ncb_length);
7067 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7071 /* We are an ongoing op */
7072 thrd_Increment(&ongoingOps);
7074 /* set up response packet for receiving output */
7075 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7076 smb_FormatResponsePacket(vcp, inp, outp);
7077 outWctp = outp->wctp;
7079 /* Remember session generation number and time */
7080 oldGen = sessionGen;
7081 oldTime = GetTickCount();
7083 while (inp->inCom != 0xff) {
7084 dp = &smb_dispatchTable[inp->inCom];
7086 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7087 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7088 code = outp->resumeCode;
7092 /* process each request in the packet; inCom, wctp and inCount
7093 * are already set up.
7095 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7098 /* now do the dispatch */
7099 /* start by formatting the response record a little, as a default */
7100 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7102 outWctp[1] = 0xff; /* no operation */
7103 outWctp[2] = 0; /* padding */
7108 /* not a chained request, this is a more reasonable default */
7109 outWctp[0] = 0; /* wct of zero */
7110 outWctp[1] = 0; /* and bcc (word) of zero */
7114 /* once set, stays set. Doesn't matter, since we never chain
7115 * "no response" calls.
7117 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7121 /* we have a recognized operation */
7123 if (inp->inCom == 0x1d)
7125 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7127 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7128 code = (*(dp->procp)) (vcp, inp, outp);
7129 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7131 if ( code == CM_ERROR_BADSMB ||
7132 code == CM_ERROR_BADOP )
7134 #endif /* LOG_PACKET */
7137 if (oldGen != sessionGen) {
7138 newTime = GetTickCount();
7139 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7140 newTime - oldTime, ncbp->ncb_length);
7141 osi_Log2(smb_logp, "Pkt straddled session startup, "
7142 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7146 /* bad opcode, fail the request, after displaying it */
7147 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7150 #endif /* LOG_PACKET */
7153 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7154 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7155 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7156 if (code == IDCANCEL)
7159 code = CM_ERROR_BADOP;
7162 /* catastrophic failure: log as much as possible */
7163 if (code == CM_ERROR_BADSMB) {
7164 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7168 #endif /* LOG_PACKET */
7169 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7172 code = CM_ERROR_INVAL;
7175 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7176 thrd_Decrement(&ongoingOps);
7181 /* now, if we failed, turn the current response into an empty
7182 * one, and fill in the response packet's error code.
7185 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7186 smb_MapNTError(code, &NTStatus);
7187 outWctp = outp->wctp;
7188 smbp = (smb_t *) &outp->data;
7189 if (code != CM_ERROR_PARTIALWRITE
7190 && code != CM_ERROR_BUFFERTOOSMALL
7191 && code != CM_ERROR_GSSCONTINUE) {
7192 /* nuke wct and bcc. For a partial
7193 * write or an in-process authentication handshake,
7194 * assume they're OK.
7200 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7201 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7202 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7203 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7204 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7208 smb_MapCoreError(code, vcp, &errCode, &errClass);
7209 outWctp = outp->wctp;
7210 smbp = (smb_t *) &outp->data;
7211 if (code != CM_ERROR_PARTIALWRITE) {
7212 /* nuke wct and bcc. For a partial
7213 * write, assume they're OK.
7219 smbp->errLow = (unsigned char) (errCode & 0xff);
7220 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7221 smbp->rcls = errClass;
7224 } /* error occurred */
7226 /* if we're here, we've finished one request. Look to see if
7227 * this is a chained opcode. If it is, setup things to process
7228 * the chained request, and setup the output buffer to hold the
7229 * chained response. Start by finding the next input record.
7231 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7232 break; /* not a chained req */
7233 tp = inp->wctp; /* points to start of last request */
7234 /* in a chained request, the first two
7235 * parm fields are required, and are
7236 * AndXCommand/AndXReserved and
7238 if (tp[0] < 2) break;
7239 if (tp[1] == 0xff) break; /* no more chained opcodes */
7241 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7244 /* and now append the next output request to the end of this
7245 * last request. Begin by finding out where the last response
7246 * ends, since that's where we'll put our new response.
7248 outWctp = outp->wctp; /* ptr to out parameters */
7249 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7250 nparms = outWctp[0] << 1;
7251 tp = outWctp + nparms + 1; /* now points to bcc field */
7252 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7253 tp += 2 /* for the count itself */ + nbytes;
7254 /* tp now points to the new output record; go back and patch the
7255 * second parameter (off2) to point to the new record.
7257 temp = (unsigned int)(tp - outp->data);
7258 outWctp[3] = (unsigned char) (temp & 0xff);
7259 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7260 outWctp[2] = 0; /* padding */
7261 outWctp[1] = inp->inCom; /* next opcode */
7263 /* finally, setup for the next iteration */
7266 } /* while loop over all requests in the packet */
7268 /* now send the output packet, and return */
7270 smb_SendPacket(vcp, outp);
7271 thrd_Decrement(&ongoingOps);
7276 /* Wait for Netbios() calls to return, and make the results available to server
7277 * threads. Note that server threads can't wait on the NCBevents array
7278 * themselves, because NCB events are manual-reset, and the servers would race
7279 * each other to reset them.
7281 void smb_ClientWaiter(void *parmp)
7286 while (smbShutdownFlag == 0) {
7287 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7289 if (code == WAIT_OBJECT_0)
7292 /* error checking */
7293 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7295 int abandonIdx = code - WAIT_ABANDONED_0;
7296 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7299 if (code == WAIT_IO_COMPLETION)
7301 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7305 if (code == WAIT_TIMEOUT)
7307 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7310 if (code == WAIT_FAILED)
7312 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7315 idx = code - WAIT_OBJECT_0;
7317 /* check idx range! */
7318 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7320 /* this is fatal - log as much as possible */
7321 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7325 thrd_ResetEvent(NCBevents[idx]);
7326 thrd_SetEvent(NCBreturns[0][idx]);
7331 * Try to have one NCBRECV request waiting for every live session. Not more
7332 * than one, because if there is more than one, it's hard to handle Write Raw.
7334 void smb_ServerWaiter(void *parmp)
7337 int idx_session, idx_NCB;
7340 while (smbShutdownFlag == 0) {
7342 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7344 if (code == WAIT_OBJECT_0)
7347 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7349 int abandonIdx = code - WAIT_ABANDONED_0;
7350 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7353 if (code == WAIT_IO_COMPLETION)
7355 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7359 if (code == WAIT_TIMEOUT)
7361 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7364 if (code == WAIT_FAILED)
7366 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7369 idx_session = code - WAIT_OBJECT_0;
7371 /* check idx range! */
7372 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7374 /* this is fatal - log as much as possible */
7375 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7381 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7383 if (code == WAIT_OBJECT_0) {
7384 if (smbShutdownFlag == 1)
7390 /* error checking */
7391 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7393 int abandonIdx = code - WAIT_ABANDONED_0;
7394 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7397 if (code == WAIT_IO_COMPLETION)
7399 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7403 if (code == WAIT_TIMEOUT)
7405 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7408 if (code == WAIT_FAILED)
7410 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7413 idx_NCB = code - WAIT_OBJECT_0;
7415 /* check idx range! */
7416 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7418 /* this is fatal - log as much as possible */
7419 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7423 /* Link them together */
7424 NCBsessions[idx_NCB] = idx_session;
7427 ncbp = NCBs[idx_NCB];
7428 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7429 ncbp->ncb_command = NCBRECV | ASYNCH;
7430 ncbp->ncb_lana_num = lanas[idx_session];
7431 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7432 ncbp->ncb_event = NCBevents[idx_NCB];
7433 ncbp->ncb_length = SMB_PACKETSIZE;
7439 * The top level loop for handling SMB request messages. Each server thread
7440 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7441 * NCB and buffer for the incoming request are loaned to us.
7443 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7444 * to immediately send a request for the rest of the data. This must come
7445 * before any other traffic for that session, so we delay setting the session
7446 * event until that data has come in.
7448 void smb_Server(VOID *parmp)
7450 INT_PTR myIdx = (INT_PTR) parmp;
7454 smb_packet_t *outbufp;
7456 int idx_NCB, idx_session;
7458 smb_vc_t *vcp = NULL;
7461 rx_StartClientThread();
7464 outbufp = GetPacket();
7465 outbufp->ncbp = outncbp;
7473 smb_ResetServerPriority();
7475 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7478 /* terminate silently if shutdown flag is set */
7479 if (code == WAIT_OBJECT_0) {
7480 if (smbShutdownFlag == 1) {
7481 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7487 /* error checking */
7488 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7490 int abandonIdx = code - WAIT_ABANDONED_0;
7491 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7494 if (code == WAIT_IO_COMPLETION)
7496 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7500 if (code == WAIT_TIMEOUT)
7502 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7505 if (code == WAIT_FAILED)
7507 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7510 idx_NCB = code - WAIT_OBJECT_0;
7512 /* check idx range! */
7513 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7515 /* this is fatal - log as much as possible */
7516 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7520 ncbp = NCBs[idx_NCB];
7521 idx_session = NCBsessions[idx_NCB];
7522 rc = ncbp->ncb_retcode;
7524 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7525 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7529 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7533 /* Can this happen? Or is it just my UNIX paranoia? */
7534 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7539 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7542 /* Client closed session */
7543 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7545 lock_ObtainMutex(&vcp->mx);
7546 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7547 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7549 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7550 lock_ReleaseMutex(&vcp->mx);
7551 lock_ObtainWrite(&smb_globalLock);
7552 dead_sessions[vcp->session] = TRUE;
7553 lock_ReleaseWrite(&smb_globalLock);
7554 smb_CleanupDeadVC(vcp);
7558 lock_ReleaseMutex(&vcp->mx);
7564 /* Treat as transient error */
7565 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7568 "dispatch smb recv failed, message incomplete, ncb_length %d",
7571 "SMB message incomplete, "
7572 "length %d", ncbp->ncb_length);
7575 * We used to discard the packet.
7576 * Instead, try handling it normally.
7580 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7584 /* A weird error code. Log it, sleep, and continue. */
7585 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7587 lock_ObtainMutex(&vcp->mx);
7588 if (vcp && vcp->errorCount++ > 3) {
7589 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7590 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7591 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7593 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7594 lock_ReleaseMutex(&vcp->mx);
7595 lock_ObtainWrite(&smb_globalLock);
7596 dead_sessions[vcp->session] = TRUE;
7597 lock_ReleaseWrite(&smb_globalLock);
7598 smb_CleanupDeadVC(vcp);
7602 lock_ReleaseMutex(&vcp->mx);
7608 lock_ReleaseMutex(&vcp->mx);
7610 thrd_SetEvent(SessionEvents[idx_session]);
7615 /* Success, so now dispatch on all the data in the packet */
7617 smb_concurrentCalls++;
7618 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7619 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7622 * If at this point vcp is NULL (implies that packet was invalid)
7623 * then we are in big trouble. This means either :
7624 * a) we have the wrong NCB.
7625 * b) Netbios screwed up the call.
7626 * c) The VC was already marked dead before we were able to
7628 * Obviously this implies that
7629 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7630 * lanas[idx_session] != ncbp->ncb_lana_num )
7631 * Either way, we can't do anything with this packet.
7632 * Log, sleep and resume.
7635 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7639 ncbp->ncb_lana_num);
7641 /* Also log in the trace log. */
7642 osi_Log4(smb_logp, "Server: VCP does not exist!"
7643 "LSNs[idx_session]=[%d],"
7644 "lanas[idx_session]=[%d],"
7645 "ncbp->ncb_lsn=[%d],"
7646 "ncbp->ncb_lana_num=[%d]",
7650 ncbp->ncb_lana_num);
7652 /* thrd_Sleep(1000); Don't bother sleeping */
7653 thrd_SetEvent(SessionEvents[idx_session]);
7654 smb_concurrentCalls--;
7658 smb_SetRequestStartTime();
7660 vcp->errorCount = 0;
7661 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7662 smbp = (smb_t *)bufp->data;
7667 if (smbp->com == 0x1d) {
7668 /* Special handling for Write Raw */
7669 raw_write_cont_t rwc;
7670 EVENT_HANDLE rwevent;
7671 char eventName[MAX_PATH];
7673 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7674 if (rwc.code == 0) {
7675 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7676 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7677 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7678 ncbp->ncb_command = NCBRECV | ASYNCH;
7679 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7680 ncbp->ncb_lana_num = vcp->lana;
7681 ncbp->ncb_buffer = rwc.buf;
7682 ncbp->ncb_length = 65535;
7683 ncbp->ncb_event = rwevent;
7685 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7686 thrd_CloseHandle(rwevent);
7688 thrd_SetEvent(SessionEvents[idx_session]);
7690 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7692 else if (smbp->com == 0xa0) {
7694 * Serialize the handling for NT Transact
7697 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7698 thrd_SetEvent(SessionEvents[idx_session]);
7700 thrd_SetEvent(SessionEvents[idx_session]);
7701 /* TODO: what else needs to be serialized? */
7702 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7705 __except( smb_ServerExceptionFilter() ) {
7708 smb_concurrentCalls--;
7711 thrd_SetEvent(NCBavails[idx_NCB]);
7718 * Exception filter for the server threads. If an exception occurs in the
7719 * dispatch routines, which is where exceptions are most common, then do a
7720 * force trace and give control to upstream exception handlers. Useful for
7723 DWORD smb_ServerExceptionFilter(void) {
7724 /* While this is not the best time to do a trace, if it succeeds, then
7725 * we have a trace (assuming tracing was enabled). Otherwise, this should
7726 * throw a second exception.
7728 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7729 afsd_ForceTrace(TRUE);
7730 buf_ForceTrace(TRUE);
7731 return EXCEPTION_CONTINUE_SEARCH;
7735 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7736 * If the number of server threads is M, and the number of live sessions is
7737 * N, then the number of NCB's in use at any time either waiting for, or
7738 * holding, received messages is M + N, so that is how many NCB's get created.
7740 void InitNCBslot(int idx)
7742 struct smb_packet *bufp;
7743 EVENT_HANDLE retHandle;
7745 char eventName[MAX_PATH];
7747 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7749 NCBs[idx] = GetNCB();
7750 sprintf(eventName,"NCBavails[%d]", idx);
7751 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7752 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7753 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7754 sprintf(eventName,"NCBevents[%d]", idx);
7755 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7756 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7757 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7758 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7759 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7760 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7761 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7762 for (i=0; i<smb_NumServerThreads; i++)
7763 NCBreturns[i][idx] = retHandle;
7765 bufp->spacep = cm_GetSpace();
7769 /* listen for new connections */
7770 void smb_Listener(void *parmp)
7776 int session, thread;
7777 smb_vc_t *vcp = NULL;
7779 char rname[NCBNAMSZ+1];
7780 char cname[MAX_COMPUTERNAME_LENGTH+1];
7781 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7782 INT_PTR lana = (INT_PTR) parmp;
7786 /* retrieve computer name */
7787 GetComputerName(cname, &cnamelen);
7791 memset(ncbp, 0, sizeof(NCB));
7794 ncbp->ncb_command = NCBLISTEN;
7795 ncbp->ncb_rto = 0; /* No receive timeout */
7796 ncbp->ncb_sto = 0; /* No send timeout */
7798 /* pad out with spaces instead of null termination */
7799 len = (long)strlen(smb_localNamep);
7800 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7801 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7803 strcpy(ncbp->ncb_callname, "*");
7804 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7806 ncbp->ncb_lana_num = (UCHAR)lana;
7808 code = Netbios(ncbp);
7814 /* terminate silently if shutdown flag is set */
7815 if (smbShutdownFlag == 1) {
7820 "NCBLISTEN lana=%d failed with code %d",
7821 ncbp->ncb_lana_num, code);
7823 "Client exiting due to network failure. Please restart client.\n");
7826 "Client exiting due to network failure. Please restart client.\n"
7827 "NCBLISTEN lana=%d failed with code %d",
7828 ncbp->ncb_lana_num, code);
7830 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7831 MB_OK|MB_SERVICE_NOTIFICATION);
7832 osi_panic(tbuffer, __FILE__, __LINE__);
7835 /* check for remote conns */
7836 /* first get remote name and insert null terminator */
7837 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7838 for (i=NCBNAMSZ; i>0; i--) {
7839 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7845 /* compare with local name */
7847 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7848 flags |= SMB_VCFLAG_REMOTECONN;
7851 lock_ObtainMutex(&smb_ListenerLock);
7853 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7854 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7856 /* now ncbp->ncb_lsn is the connection ID */
7857 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7858 if (vcp->session == 0) {
7859 /* New generation */
7860 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7863 /* Log session startup */
7865 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7866 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7867 #endif /* NOTSERVICE */
7868 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7869 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7871 if (reportSessionStartups) {
7872 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7875 lock_ObtainMutex(&vcp->mx);
7876 strcpy(vcp->rname, rname);
7877 vcp->flags |= flags;
7878 lock_ReleaseMutex(&vcp->mx);
7880 /* Allocate slot in session arrays */
7881 /* Re-use dead session if possible, otherwise add one more */
7882 /* But don't look at session[0], it is reserved */
7883 lock_ObtainWrite(&smb_globalLock);
7884 for (session = 1; session < numSessions; session++) {
7885 if (dead_sessions[session]) {
7886 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
7887 dead_sessions[session] = FALSE;
7891 lock_ReleaseWrite(&smb_globalLock);
7893 /* We are re-using an existing VC because the lsn and lana
7895 session = vcp->session;
7897 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
7899 /* Log session startup */
7901 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7902 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7903 #endif /* NOTSERVICE */
7904 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7905 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7907 if (reportSessionStartups) {
7908 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7912 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
7913 unsigned long code = CM_ERROR_ALLBUSY;
7914 smb_packet_t * outp = GetPacket();
7915 unsigned char *outWctp;
7918 smb_FormatResponsePacket(vcp, NULL, outp);
7921 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7922 unsigned long NTStatus;
7923 smb_MapNTError(code, &NTStatus);
7924 outWctp = outp->wctp;
7925 smbp = (smb_t *) &outp->data;
7929 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7930 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7931 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7932 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7933 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7935 unsigned short errCode;
7936 unsigned char errClass;
7937 smb_MapCoreError(code, vcp, &errCode, &errClass);
7938 outWctp = outp->wctp;
7939 smbp = (smb_t *) &outp->data;
7943 smbp->errLow = (unsigned char) (errCode & 0xff);
7944 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7945 smbp->rcls = errClass;
7947 smb_SendPacket(vcp, outp);
7948 smb_FreePacket(outp);
7950 lock_ObtainMutex(&vcp->mx);
7951 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7952 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7954 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7955 lock_ReleaseMutex(&vcp->mx);
7956 lock_ObtainWrite(&smb_globalLock);
7957 dead_sessions[vcp->session] = TRUE;
7958 lock_ReleaseWrite(&smb_globalLock);
7959 smb_CleanupDeadVC(vcp);
7961 lock_ReleaseMutex(&vcp->mx);
7964 /* assert that we do not exceed the maximum number of sessions or NCBs.
7965 * we should probably want to wait for a session to be freed in case
7968 osi_assert(session < SESSION_MAX - 1);
7969 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
7971 lock_ObtainMutex(&vcp->mx);
7972 vcp->session = session;
7973 lock_ReleaseMutex(&vcp->mx);
7974 lock_ObtainWrite(&smb_globalLock);
7975 LSNs[session] = ncbp->ncb_lsn;
7976 lanas[session] = ncbp->ncb_lana_num;
7977 lock_ReleaseWrite(&smb_globalLock);
7979 if (session == numSessions) {
7980 /* Add new NCB for new session */
7981 char eventName[MAX_PATH];
7983 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7985 InitNCBslot(numNCBs);
7986 lock_ObtainWrite(&smb_globalLock);
7988 lock_ReleaseWrite(&smb_globalLock);
7989 thrd_SetEvent(NCBavails[0]);
7990 thrd_SetEvent(NCBevents[0]);
7991 for (thread = 0; thread < smb_NumServerThreads; thread++)
7992 thrd_SetEvent(NCBreturns[thread][0]);
7993 /* Also add new session event */
7994 sprintf(eventName, "SessionEvents[%d]", session);
7995 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7996 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7997 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7998 lock_ObtainWrite(&smb_globalLock);
8000 lock_ReleaseWrite(&smb_globalLock);
8001 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8002 thrd_SetEvent(SessionEvents[0]);
8004 thrd_SetEvent(SessionEvents[session]);
8010 lock_ReleaseMutex(&smb_ListenerLock);
8011 } /* dispatch while loop */
8014 /* initialize Netbios */
8015 void smb_NetbiosInit()
8018 int i, lana, code, l;
8020 int delname_tried=0;
8023 OSVERSIONINFO Version;
8025 /* Get the version of Windows */
8026 memset(&Version, 0x00, sizeof(Version));
8027 Version.dwOSVersionInfoSize = sizeof(Version);
8028 GetVersionEx(&Version);
8030 /* setup the NCB system */
8033 if (smb_LANadapter == -1) {
8034 ncbp->ncb_command = NCBENUM;
8035 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8036 ncbp->ncb_length = sizeof(lana_list);
8037 code = Netbios(ncbp);
8039 afsi_log("Netbios NCBENUM error code %d", code);
8040 osi_panic(s, __FILE__, __LINE__);
8044 lana_list.length = 1;
8045 lana_list.lana[0] = smb_LANadapter;
8048 for (i = 0; i < lana_list.length; i++) {
8049 /* reset the adaptor: in Win32, this is required for every process, and
8050 * acts as an init call, not as a real hardware reset.
8052 ncbp->ncb_command = NCBRESET;
8053 ncbp->ncb_callname[0] = 100;
8054 ncbp->ncb_callname[2] = 100;
8055 ncbp->ncb_lana_num = lana_list.lana[i];
8056 code = Netbios(ncbp);
8058 code = ncbp->ncb_retcode;
8060 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8061 lana_list.lana[i] = 255; /* invalid lana */
8063 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8067 /* and declare our name so we can receive connections */
8068 memset(ncbp, 0, sizeof(*ncbp));
8069 len=lstrlen(smb_localNamep);
8070 memset(smb_sharename,' ',NCBNAMSZ);
8071 memcpy(smb_sharename,smb_localNamep,len);
8072 afsi_log("lana_list.length %d", lana_list.length);
8074 /* Keep the name so we can unregister it later */
8075 for (l = 0; l < lana_list.length; l++) {
8076 lana = lana_list.lana[l];
8078 ncbp->ncb_command = NCBADDNAME;
8079 ncbp->ncb_lana_num = lana;
8080 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8081 code = Netbios(ncbp);
8083 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8084 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8086 char name[NCBNAMSZ+1];
8088 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8089 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8092 if (code == 0) code = ncbp->ncb_retcode;
8094 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8097 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8098 if (code == NRC_BRIDGE) { /* invalid LANA num */
8099 lana_list.lana[l] = 255;
8102 else if (code == NRC_DUPNAME) {
8103 afsi_log("Name already exists; try to delete it");
8104 memset(ncbp, 0, sizeof(*ncbp));
8105 ncbp->ncb_command = NCBDELNAME;
8106 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8107 ncbp->ncb_lana_num = lana;
8108 code = Netbios(ncbp);
8110 code = ncbp->ncb_retcode;
8112 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8114 if (code != 0 || delname_tried) {
8115 lana_list.lana[l] = 255;
8117 else if (code == 0) {
8118 if (!delname_tried) {
8126 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8127 lana_list.lana[l] = 255; /* invalid lana */
8128 osi_panic(s, __FILE__, __LINE__);
8132 lana_found = 1; /* at least one worked */
8136 osi_assert(lana_list.length >= 0);
8138 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8141 /* we're done with the NCB now */
8145 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8156 EVENT_HANDLE retHandle;
8157 char eventName[MAX_PATH];
8159 smb_TlsRequestSlot = TlsAlloc();
8161 smb_MBfunc = aMBfunc;
8164 smb_LANadapter = LANadapt;
8166 /* Initialize smb_localZero */
8167 myTime.tm_isdst = -1; /* compute whether on DST or not */
8168 myTime.tm_year = 70;
8174 smb_localZero = mktime(&myTime);
8176 #ifndef USE_NUMERIC_TIME_CONV
8177 /* Initialize kludge-GMT */
8178 smb_CalculateNowTZ();
8179 #endif /* USE_NUMERIC_TIME_CONV */
8180 #ifdef AFS_FREELANCE_CLIENT
8181 /* Make sure the root.afs volume has the correct time */
8182 cm_noteLocalMountPointChange();
8185 /* initialize the remote debugging log */
8188 /* remember the name */
8189 len = (int)strlen(snamep);
8190 smb_localNamep = malloc(len+1);
8191 strcpy(smb_localNamep, snamep);
8192 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8194 /* and the global lock */
8195 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8196 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8198 /* Raw I/O data structures */
8199 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8201 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8203 /* 4 Raw I/O buffers */
8204 smb_RawBufs = calloc(65536,1);
8205 *((char **)smb_RawBufs) = NULL;
8206 for (i=0; i<3; i++) {
8207 char *rawBuf = calloc(65536,1);
8208 *((char **)rawBuf) = smb_RawBufs;
8209 smb_RawBufs = rawBuf;
8212 /* global free lists */
8213 smb_ncbFreeListp = NULL;
8214 smb_packetFreeListp = NULL;
8218 /* Initialize listener and server structures */
8220 memset(dead_sessions, 0, sizeof(dead_sessions));
8221 sprintf(eventName, "SessionEvents[0]");
8222 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8223 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8224 afsi_log("Event Object Already Exists: %s", eventName);
8226 smb_NumServerThreads = nThreads;
8227 sprintf(eventName, "NCBavails[0]");
8228 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8229 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8230 afsi_log("Event Object Already Exists: %s", eventName);
8231 sprintf(eventName, "NCBevents[0]");
8232 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8233 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8234 afsi_log("Event Object Already Exists: %s", eventName);
8235 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8236 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8237 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8238 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8239 afsi_log("Event Object Already Exists: %s", eventName);
8240 for (i = 0; i < smb_NumServerThreads; i++) {
8241 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8242 NCBreturns[i][0] = retHandle;
8245 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8246 for (i = 0; i < smb_NumServerThreads; i++) {
8247 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8248 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8249 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8250 afsi_log("Event Object Already Exists: %s", eventName);
8251 InitNCBslot((int)(i+1));
8253 numNCBs = smb_NumServerThreads + 1;
8255 /* Initialize dispatch table */
8256 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8257 /* Prepare the table for unknown operations */
8258 for(i=0; i<= SMB_NOPCODES; i++) {
8259 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8261 /* Fill in the ones we do know */
8262 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8263 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8264 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8265 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8266 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8267 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8268 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8269 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8270 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8271 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8272 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8273 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8274 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8275 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8276 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8277 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8278 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8279 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8280 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8281 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8282 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8283 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8284 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8285 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8286 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8287 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8288 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8289 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8290 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8291 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8292 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8293 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8294 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8295 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8296 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8297 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8298 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8299 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8300 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8301 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8302 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8303 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8304 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8305 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8306 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8307 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8308 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8309 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8310 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8311 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8312 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8313 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8314 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8315 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8316 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8317 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8318 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8319 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8320 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8321 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8322 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8323 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8324 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8325 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8326 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8327 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8328 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8329 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8330 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8331 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8332 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8333 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8334 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8335 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8337 /* setup tran 2 dispatch table */
8338 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8339 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8340 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8341 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8342 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8343 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8344 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8345 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8346 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8347 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8348 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8349 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8350 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8351 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8352 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8353 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8354 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8355 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8357 /* setup the rap dispatch table */
8358 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8359 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8360 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8361 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8362 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8366 /* if we are doing SMB authentication we have register outselves as a logon process */
8367 if (smb_authType != SMB_AUTH_NONE) {
8368 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8369 LSA_STRING afsProcessName;
8370 LSA_OPERATIONAL_MODE dummy; /*junk*/
8372 afsProcessName.Buffer = "OpenAFSClientDaemon";
8373 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8374 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8376 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8378 if (nts == STATUS_SUCCESS) {
8379 LSA_STRING packageName;
8380 /* we are registered. Find out the security package id */
8381 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8382 packageName.Length = (USHORT)strlen(packageName.Buffer);
8383 packageName.MaximumLength = packageName.Length + 1;
8384 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8385 if (nts == STATUS_SUCCESS) {
8387 * This code forces Windows to authenticate against the Logon Cache
8388 * first instead of attempting to authenticate against the Domain
8389 * Controller. When the Windows logon cache is enabled this improves
8390 * performance by removing the network access and works around a bug
8391 * seen at sites which are using a MIT Kerberos principal to login
8392 * to machines joined to a non-root domain in a multi-domain forest.
8394 PVOID pResponse = NULL;
8395 ULONG cbResponse = 0;
8396 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8398 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8399 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8400 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8401 OptionsRequest.DisableOptions = FALSE;
8403 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8406 sizeof(OptionsRequest),
8412 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8414 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8416 OutputDebugString(message);
8419 OutputDebugString("MsV1_0SetProcessOption success");
8420 afsi_log("MsV1_0SetProcessOption success");
8422 /* END - code from Larry */
8424 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8425 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8426 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8428 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8430 /* something went wrong. We report the error and revert back to no authentication
8431 because we can't perform any auth requests without a successful lsa handle
8432 or sec package id. */
8433 afsi_log("Reverting to NO SMB AUTH");
8434 smb_authType = SMB_AUTH_NONE;
8437 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8439 /* something went wrong. We report the error and revert back to no authentication
8440 because we can't perform any auth requests without a successful lsa handle
8441 or sec package id. */
8442 afsi_log("Reverting to NO SMB AUTH");
8443 smb_authType = SMB_AUTH_NONE;
8447 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8448 * time prevents the failure of authentication when logged into Windows with an
8449 * external Kerberos principal mapped to a local account.
8451 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8452 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8453 * then the only option is NTLMSSP anyway; so just fallback.
8458 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8459 if (secBlobLength == 0) {
8460 smb_authType = SMB_AUTH_NTLM;
8461 afsi_log("Reverting to SMB AUTH NTLM");
8470 /* Now get ourselves a domain name. */
8471 /* For now we are using the local computer name as the domain name.
8472 * It is actually the domain for local logins, and we are acting as
8473 * a local SMB server.
8475 bufsize = sizeof(smb_ServerDomainName) - 1;
8476 GetComputerName(smb_ServerDomainName, &bufsize);
8477 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8478 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8481 /* Start listeners, waiters, servers, and daemons */
8483 for (i = 0; i < lana_list.length; i++) {
8484 if (lana_list.lana[i] == 255)
8486 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8487 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8488 osi_assert(phandle != NULL);
8489 thrd_CloseHandle(phandle);
8492 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8493 NULL, 0, &lpid, "smb_ClientWaiter");
8494 osi_assert(phandle != NULL);
8495 thrd_CloseHandle(phandle);
8497 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8498 NULL, 0, &lpid, "smb_ServerWaiter");
8499 osi_assert(phandle != NULL);
8500 thrd_CloseHandle(phandle);
8502 for (i=0; i<smb_NumServerThreads; i++) {
8503 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8504 (void *) i, 0, &lpid, "smb_Server");
8505 osi_assert(phandle != NULL);
8506 thrd_CloseHandle(phandle);
8509 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8510 NULL, 0, &lpid, "smb_Daemon");
8511 osi_assert(phandle != NULL);
8512 thrd_CloseHandle(phandle);
8514 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8515 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8516 osi_assert(phandle != NULL);
8517 thrd_CloseHandle(phandle);
8522 void smb_Shutdown(void)
8529 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8531 /* setup the NCB system */
8534 /* Block new sessions by setting shutdown flag */
8535 smbShutdownFlag = 1;
8537 /* Hang up all sessions */
8538 memset((char *)ncbp, 0, sizeof(NCB));
8539 for (i = 1; i < numSessions; i++)
8541 if (dead_sessions[i])
8544 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8545 ncbp->ncb_command = NCBHANGUP;
8546 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8547 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8548 code = Netbios(ncbp);
8549 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8550 if (code == 0) code = ncbp->ncb_retcode;
8552 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8553 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8557 /* Trigger the shutdown of all SMB threads */
8558 for (i = 0; i < smb_NumServerThreads; i++)
8559 thrd_SetEvent(NCBreturns[i][0]);
8561 thrd_SetEvent(NCBevents[0]);
8562 thrd_SetEvent(SessionEvents[0]);
8563 thrd_SetEvent(NCBavails[0]);
8565 for (i = 0;i < smb_NumServerThreads; i++) {
8566 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8567 if (code == WAIT_OBJECT_0) {
8570 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8571 thrd_SetEvent(NCBreturns[i--][0]);
8575 /* Delete Netbios name */
8576 memset((char *)ncbp, 0, sizeof(NCB));
8577 for (i = 0; i < lana_list.length; i++) {
8578 if (lana_list.lana[i] == 255) continue;
8579 ncbp->ncb_command = NCBDELNAME;
8580 ncbp->ncb_lana_num = lana_list.lana[i];
8581 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8582 code = Netbios(ncbp);
8584 code = ncbp->ncb_retcode;
8586 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8587 ncbp->ncb_lana_num, code);
8592 /* Release the reference counts held by the VCs */
8593 lock_ObtainWrite(&smb_rctLock);
8594 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8599 if (vcp->magic != SMB_VC_MAGIC)
8600 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8601 __FILE__, __LINE__);
8603 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8605 if (fidp->scp != NULL) {
8608 lock_ObtainMutex(&fidp->mx);
8609 if (fidp->scp != NULL) {
8612 cm_ReleaseSCache(scp);
8614 lock_ReleaseMutex(&fidp->mx);
8618 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8620 smb_ReleaseVCNoLock(tidp->vcp);
8622 cm_user_t *userp = tidp->userp;
8624 lock_ReleaseWrite(&smb_rctLock);
8625 cm_ReleaseUser(userp);
8626 lock_ObtainWrite(&smb_rctLock);
8630 lock_ReleaseWrite(&smb_rctLock);
8632 TlsFree(smb_TlsRequestSlot);
8635 /* Get the UNC \\<servername>\<sharename> prefix. */
8636 char *smb_GetSharename()
8640 /* Make sure we have been properly initialized. */
8641 if (smb_localNamep == NULL)
8644 /* Allocate space for \\<servername>\<sharename>, plus the
8647 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8648 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8654 void smb_LogPacket(smb_packet_t *packet)
8657 unsigned length, paramlen, datalen, i, j;
8659 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8661 if (!packet) return;
8663 osi_Log0(smb_logp, "*** SMB packet dump ***");
8665 vp = (BYTE *) packet->data;
8667 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8668 length = paramlen + 2 + datalen;
8671 for (i=0;i < length; i+=16)
8673 memset( buf, ' ', 80 );
8678 buf[strlen(buf)] = ' ';
8680 cp = (BYTE*) buf + 7;
8682 for (j=0;j < 16 && (i+j)<length; j++)
8684 *(cp++) = hex[vp[i+j] >> 4];
8685 *(cp++) = hex[vp[i+j] & 0xf];
8695 for (j=0;j < 16 && (i+j)<length;j++)
8697 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8708 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8711 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8713 #endif /* LOG_PACKET */
8716 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8724 lock_ObtainRead(&smb_rctLock);
8726 sprintf(output, "begin dumping smb_vc_t\n");
8727 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8729 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8733 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8734 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8735 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8737 sprintf(output, "begin dumping smb_fid_t\n");
8738 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8740 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8742 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8743 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8744 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8745 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8746 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8749 sprintf(output, "done dumping smb_fid_t\n");
8750 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8753 sprintf(output, "done dumping smb_vc_t\n");
8754 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8756 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8757 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8759 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8763 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8764 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8765 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8767 sprintf(output, "begin dumping smb_fid_t\n");
8768 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8770 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8772 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8773 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8774 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8775 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8776 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8779 sprintf(output, "done dumping smb_fid_t\n");
8780 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8783 sprintf(output, "done dumping DEAD smb_vc_t\n");
8784 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8786 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8787 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8789 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8793 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8794 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8795 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8797 sprintf(output, "begin dumping smb_fid_t\n");
8798 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8800 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8802 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8803 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8804 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8805 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8806 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8809 sprintf(output, "done dumping smb_fid_t\n");
8810 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8813 sprintf(output, "done dumping DEAD smb_vc_t\n");
8814 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8817 lock_ReleaseRead(&smb_rctLock);