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)
1455 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1456 /* the sm_fid_t->mx and smb_rctLock must not be held */
1457 void smb_ReleaseFID(smb_fid_t *fidp)
1459 cm_scache_t *scp = NULL;
1460 cm_user_t *userp = NULL;
1461 smb_vc_t *vcp = NULL;
1462 smb_ioctl_t *ioctlp;
1464 lock_ObtainMutex(&fidp->mx);
1465 lock_ObtainWrite(&smb_rctLock);
1466 osi_assert(fidp->refCount-- > 0);
1467 if (fidp->refCount == 0 && (fidp->delete)) {
1470 scp = fidp->scp; /* release after lock is released */
1472 lock_ObtainMutex(&scp->mx);
1473 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1474 lock_ReleaseMutex(&scp->mx);
1475 osi_Log2(afsd_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1478 userp = fidp->userp;
1482 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1483 thrd_CloseHandle(fidp->raw_write_event);
1485 /* and see if there is ioctl stuff to free */
1486 ioctlp = fidp->ioctlp;
1489 cm_FreeSpace(ioctlp->prefix);
1490 if (ioctlp->inAllocp)
1491 free(ioctlp->inAllocp);
1492 if (ioctlp->outAllocp)
1493 free(ioctlp->outAllocp);
1496 lock_ReleaseMutex(&fidp->mx);
1497 lock_FinalizeMutex(&fidp->mx);
1501 smb_ReleaseVCNoLock(vcp);
1503 lock_ReleaseMutex(&fidp->mx);
1505 lock_ReleaseWrite(&smb_rctLock);
1507 /* now release the scache structure */
1509 cm_ReleaseSCache(scp);
1512 cm_ReleaseUser(userp);
1516 * Case-insensitive search for one string in another;
1517 * used to find variable names in submount pathnames.
1519 static char *smb_stristr(char *str1, char *str2)
1523 for (cursor = str1; *cursor; cursor++)
1524 if (stricmp(cursor, str2) == 0)
1531 * Substitute a variable value for its name in a submount pathname. Variable
1532 * name has been identified by smb_stristr() and is in substr. Variable name
1533 * length (plus one) is in substr_size. Variable value is in newstr.
1535 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1540 strcpy(temp, substr + substr_size - 1);
1541 strcpy(substr, newstr);
1545 char VNUserName[] = "%USERNAME%";
1546 char VNLCUserName[] = "%LCUSERNAME%";
1547 char VNComputerName[] = "%COMPUTERNAME%";
1548 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1551 typedef struct smb_findShare_rock {
1555 } smb_findShare_rock_t;
1557 #define SMB_FINDSHARE_EXACT_MATCH 1
1558 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1560 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1564 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1565 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1566 if(!stricmp(dep->name, vrock->shareName))
1567 matchType = SMB_FINDSHARE_EXACT_MATCH;
1569 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1570 if(vrock->match) free(vrock->match);
1571 vrock->match = strdup(dep->name);
1572 vrock->matchType = matchType;
1574 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1575 return CM_ERROR_STOPNOW;
1581 /* find a shareName in the table of submounts */
1582 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1586 char pathName[1024];
1593 DWORD allSubmount = 1;
1595 /* if allSubmounts == 0, only return the //mountRoot/all share
1596 * if in fact it has been been created in the subMounts table.
1597 * This is to allow sites that want to restrict access to the
1600 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1601 0, KEY_QUERY_VALUE, &parmKey);
1602 if (code == ERROR_SUCCESS) {
1603 len = sizeof(allSubmount);
1604 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1605 (BYTE *) &allSubmount, &len);
1606 if (code != ERROR_SUCCESS) {
1609 RegCloseKey (parmKey);
1612 if (allSubmount && _stricmp(shareName, "all") == 0) {
1617 /* In case, the all share is disabled we need to still be able
1618 * to handle ioctl requests
1620 if (_stricmp(shareName, "ioctl$") == 0) {
1621 *pathNamep = strdup("/.__ioctl__");
1625 if (_stricmp(shareName, "IPC$") == 0 ||
1626 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1627 _stricmp(shareName, "DESKTOP.INI") == 0
1633 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1634 0, KEY_QUERY_VALUE, &parmKey);
1635 if (code == ERROR_SUCCESS) {
1636 len = sizeof(pathName);
1637 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1638 (BYTE *) pathName, &len);
1639 if (code != ERROR_SUCCESS)
1641 RegCloseKey (parmKey);
1645 if (len != 0 && len != sizeof(pathName) - 1) {
1646 /* We can accept either unix or PC style AFS pathnames. Convert
1647 * Unix-style to PC style here for internal use.
1650 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1651 p += strlen(cm_mountRoot); /* skip mount path */
1654 if (*q == '/') *q = '\\'; /* change to \ */
1660 if (var = smb_stristr(p, VNUserName)) {
1661 if (uidp && uidp->unp)
1662 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1664 smb_subst(p, var, sizeof(VNUserName)," ");
1666 else if (var = smb_stristr(p, VNLCUserName))
1668 if (uidp && uidp->unp)
1669 strcpy(temp, uidp->unp->name);
1673 smb_subst(p, var, sizeof(VNLCUserName), temp);
1675 else if (var = smb_stristr(p, VNComputerName))
1677 sizeTemp = sizeof(temp);
1678 GetComputerName((LPTSTR)temp, &sizeTemp);
1679 smb_subst(p, var, sizeof(VNComputerName), temp);
1681 else if (var = smb_stristr(p, VNLCComputerName))
1683 sizeTemp = sizeof(temp);
1684 GetComputerName((LPTSTR)temp, &sizeTemp);
1686 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1691 *pathNamep = strdup(p);
1696 /* First lookup shareName in root.afs */
1698 smb_findShare_rock_t vrock;
1700 char * p = shareName;
1703 /* attempt to locate a partial match in root.afs. This is because
1704 when using the ANSI RAP calls, the share name is limited to 13 chars
1705 and hence is truncated. Of course we prefer exact matches. */
1707 thyper.HighPart = 0;
1710 vrock.shareName = shareName;
1712 vrock.matchType = 0;
1714 cm_HoldSCache(cm_data.rootSCachep);
1715 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1716 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1717 cm_ReleaseSCache(cm_data.rootSCachep);
1719 if (vrock.matchType) {
1720 sprintf(pathName,"/%s/",vrock.match);
1721 *pathNamep = strdup(strlwr(pathName));
1726 /* if we get here, there was no match for the share in root.afs */
1727 /* so try to create \\<netbiosName>\<cellname> */
1732 /* Get the full name for this cell */
1733 code = cm_SearchCellFile(p, temp, 0, 0);
1734 #ifdef AFS_AFSDB_ENV
1735 if (code && cm_dnsEnabled) {
1737 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1740 /* construct the path */
1742 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1743 *pathNamep = strdup(strlwr(pathName));
1752 /* Client-side offline caching policy types */
1753 #define CSC_POLICY_MANUAL 0
1754 #define CSC_POLICY_DOCUMENTS 1
1755 #define CSC_POLICY_PROGRAMS 2
1756 #define CSC_POLICY_DISABLE 3
1758 int smb_FindShareCSCPolicy(char *shareName)
1764 int retval = CSC_POLICY_MANUAL;
1766 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1767 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1770 REG_OPTION_NON_VOLATILE,
1776 len = sizeof(policy);
1777 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1779 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1781 else if (stricmp(policy, "documents") == 0)
1783 retval = CSC_POLICY_DOCUMENTS;
1785 else if (stricmp(policy, "programs") == 0)
1787 retval = CSC_POLICY_PROGRAMS;
1789 else if (stricmp(policy, "disable") == 0)
1791 retval = CSC_POLICY_DISABLE;
1794 RegCloseKey(hkCSCPolicy);
1798 /* find a dir search structure by cookie value, and return it held.
1799 * Must be called with smb_globalLock held.
1801 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1803 smb_dirSearch_t *dsp;
1805 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1806 if (dsp->cookie == cookie) {
1807 if (dsp != smb_firstDirSearchp) {
1808 /* move to head of LRU queue, too, if we're not already there */
1809 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1810 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1811 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1812 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1813 if (!smb_lastDirSearchp)
1814 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1816 lock_ObtainMutex(&dsp->mx);
1818 lock_ReleaseMutex(&dsp->mx);
1824 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1825 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1826 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1832 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1834 lock_ObtainWrite(&smb_globalLock);
1835 lock_ObtainMutex(&dsp->mx);
1836 dsp->flags |= SMB_DIRSEARCH_DELETE;
1837 if (dsp->scp != NULL) {
1838 lock_ObtainMutex(&dsp->scp->mx);
1839 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1840 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1841 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1842 dsp->scp->bulkStatProgress = hzero;
1844 lock_ReleaseMutex(&dsp->scp->mx);
1846 lock_ReleaseMutex(&dsp->mx);
1847 lock_ReleaseWrite(&smb_globalLock);
1850 /* Must be called with the smb_globalLock held */
1851 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1853 cm_scache_t *scp = NULL;
1855 lock_ObtainMutex(&dsp->mx);
1856 osi_assert(dsp->refCount-- > 0);
1857 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1858 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 lock_ReleaseMutex(&dsp->mx);
1862 lock_FinalizeMutex(&dsp->mx);
1864 osi_Log2(afsd_logp,"smb_ReleaseDirSearch dsp 0x%p scp 0x%p", dsp, scp);
1867 lock_ReleaseMutex(&dsp->mx);
1869 /* do this now to avoid spurious locking hierarchy creation */
1871 cm_ReleaseSCache(scp);
1874 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1876 lock_ObtainWrite(&smb_globalLock);
1877 smb_ReleaseDirSearchNoLock(dsp);
1878 lock_ReleaseWrite(&smb_globalLock);
1881 /* find a dir search structure by cookie value, and return it held */
1882 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1884 smb_dirSearch_t *dsp;
1886 lock_ObtainWrite(&smb_globalLock);
1887 dsp = smb_FindDirSearchNoLock(cookie);
1888 lock_ReleaseWrite(&smb_globalLock);
1892 /* GC some dir search entries, in the address space expected by the specific protocol.
1893 * Must be called with smb_globalLock held; release the lock temporarily.
1895 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1896 void smb_GCDirSearches(int isV3)
1898 smb_dirSearch_t *prevp;
1899 smb_dirSearch_t *tp;
1900 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1904 victimCount = 0; /* how many have we got so far */
1905 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1906 /* we'll move tp from queue, so
1909 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1910 /* if no one is using this guy, and we're either in the new protocol,
1911 * or we're in the old one and this is a small enough ID to be useful
1912 * to the old protocol, GC this guy.
1914 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1915 /* hold and delete */
1916 lock_ObtainMutex(&tp->mx);
1917 tp->flags |= SMB_DIRSEARCH_DELETE;
1918 lock_ReleaseMutex(&tp->mx);
1919 victimsp[victimCount++] = tp;
1923 /* don't do more than this */
1924 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1928 /* now release them */
1929 for (i = 0; i < victimCount; i++) {
1930 smb_ReleaseDirSearchNoLock(victimsp[i]);
1934 /* function for allocating a dir search entry. We need these to remember enough context
1935 * since we don't get passed the path from call to call during a directory search.
1937 * Returns a held dir search structure, and bumps the reference count on the vnode,
1938 * since it saves a pointer to the vnode.
1940 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1942 smb_dirSearch_t *dsp;
1948 lock_ObtainWrite(&smb_globalLock);
1951 /* what's the biggest ID allowed in this version of the protocol */
1952 maxAllowed = isV3 ? 65535 : 255;
1953 if (smb_dirSearchCounter > maxAllowed)
1954 smb_dirSearchCounter = 1;
1956 start = smb_dirSearchCounter;
1959 /* twice so we have enough tries to find guys we GC after one pass;
1960 * 10 extra is just in case I mis-counted.
1962 if (++counter > 2*maxAllowed+10)
1963 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1965 if (smb_dirSearchCounter > maxAllowed) {
1966 smb_dirSearchCounter = 1;
1968 if (smb_dirSearchCounter == start) {
1970 smb_GCDirSearches(isV3);
1973 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1975 /* don't need to watch for refcount zero and deleted, since
1976 * we haven't dropped the global lock.
1978 lock_ObtainMutex(&dsp->mx);
1980 lock_ReleaseMutex(&dsp->mx);
1981 ++smb_dirSearchCounter;
1985 dsp = malloc(sizeof(*dsp));
1986 memset(dsp, 0, sizeof(*dsp));
1987 dsp->cookie = smb_dirSearchCounter;
1988 ++smb_dirSearchCounter;
1990 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1991 dsp->lastTime = osi_Time();
1992 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1993 if (!smb_lastDirSearchp)
1994 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1997 lock_ReleaseWrite(&smb_globalLock);
2001 static smb_packet_t *GetPacket(void)
2005 lock_ObtainWrite(&smb_globalLock);
2006 tbp = smb_packetFreeListp;
2008 smb_packetFreeListp = tbp->nextp;
2009 lock_ReleaseWrite(&smb_globalLock);
2011 tbp = calloc(65540,1);
2012 tbp->magic = SMB_PACKETMAGIC;
2015 tbp->resumeCode = 0;
2021 tbp->ncb_length = 0;
2026 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2031 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2035 memcpy(tbp, pkt, sizeof(smb_packet_t));
2036 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2038 smb_HoldVC(tbp->vcp);
2042 static NCB *GetNCB(void)
2047 lock_ObtainWrite(&smb_globalLock);
2048 tbp = smb_ncbFreeListp;
2050 smb_ncbFreeListp = tbp->nextp;
2051 lock_ReleaseWrite(&smb_globalLock);
2053 tbp = calloc(sizeof(*tbp),1);
2054 tbp->magic = SMB_NCBMAGIC;
2057 osi_assert(tbp->magic == SMB_NCBMAGIC);
2059 memset(&tbp->ncb, 0, sizeof(NCB));
2064 void smb_FreePacket(smb_packet_t *tbp)
2066 smb_vc_t * vcp = NULL;
2067 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2069 lock_ObtainWrite(&smb_globalLock);
2070 tbp->nextp = smb_packetFreeListp;
2071 smb_packetFreeListp = tbp;
2072 tbp->magic = SMB_PACKETMAGIC;
2076 tbp->resumeCode = 0;
2082 tbp->ncb_length = 0;
2084 lock_ReleaseWrite(&smb_globalLock);
2090 static void FreeNCB(NCB *bufferp)
2094 tbp = (smb_ncb_t *) bufferp;
2095 osi_assert(tbp->magic == SMB_NCBMAGIC);
2097 lock_ObtainWrite(&smb_globalLock);
2098 tbp->nextp = smb_ncbFreeListp;
2099 smb_ncbFreeListp = tbp;
2100 lock_ReleaseWrite(&smb_globalLock);
2103 /* get a ptr to the data part of a packet, and its count */
2104 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2108 unsigned char *afterParmsp;
2110 parmBytes = *smbp->wctp << 1;
2111 afterParmsp = smbp->wctp + parmBytes + 1;
2113 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2114 if (nbytesp) *nbytesp = dataBytes;
2116 /* don't forget to skip the data byte count, since it follows
2117 * the parameters; that's where the "2" comes from below.
2119 return (unsigned char *) (afterParmsp + 2);
2122 /* must set all the returned parameters before playing around with the
2123 * data region, since the data region is located past the end of the
2124 * variable number of parameters.
2126 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2128 unsigned char *afterParmsp;
2130 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2132 *afterParmsp++ = dsize & 0xff;
2133 *afterParmsp = (dsize>>8) & 0xff;
2136 /* return the parm'th parameter in the smbp packet */
2137 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2140 unsigned char *parmDatap;
2142 parmCount = *smbp->wctp;
2144 if (parm >= parmCount) {
2147 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2148 parm, parmCount, smbp->ncb_length);
2149 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2150 parm, parmCount, smbp->ncb_length);
2151 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2152 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2153 osi_panic(s, __FILE__, __LINE__);
2155 parmDatap = smbp->wctp + (2*parm) + 1;
2157 return parmDatap[0] + (parmDatap[1] << 8);
2160 /* return the parm'th parameter in the smbp packet */
2161 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2164 unsigned char *parmDatap;
2166 parmCount = *smbp->wctp;
2168 if (parm + 1 >= parmCount) {
2171 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2172 parm, parmCount, smbp->ncb_length);
2173 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2174 parm, parmCount, smbp->ncb_length);
2175 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2176 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2177 osi_panic(s, __FILE__, __LINE__);
2179 parmDatap = smbp->wctp + (2*parm) + 1;
2181 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2184 /* return the parm'th parameter in the smbp packet */
2185 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2188 unsigned char *parmDatap;
2190 parmCount = *smbp->wctp;
2192 if (parm * 2 + offset >= parmCount * 2) {
2195 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2196 parm, offset, parmCount, smbp->ncb_length);
2197 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2198 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2199 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2200 parm, offset, parmCount, smbp->ncb_length);
2201 osi_panic(s, __FILE__, __LINE__);
2203 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2205 return parmDatap[0] + (parmDatap[1] << 8);
2208 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2212 /* make sure we have enough slots */
2213 if (*smbp->wctp <= slot)
2214 *smbp->wctp = slot+1;
2216 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2217 *parmDatap++ = parmValue & 0xff;
2218 *parmDatap = (parmValue>>8) & 0xff;
2221 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2225 /* make sure we have enough slots */
2226 if (*smbp->wctp <= slot)
2227 *smbp->wctp = slot+2;
2229 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2230 *parmDatap++ = parmValue & 0xff;
2231 *parmDatap++ = (parmValue>>8) & 0xff;
2232 *parmDatap++ = (parmValue>>16) & 0xff;
2233 *parmDatap = (parmValue>>24) & 0xff;
2236 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2241 /* make sure we have enough slots */
2242 if (*smbp->wctp <= slot)
2243 *smbp->wctp = slot+4;
2245 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2247 *parmDatap++ = *parmValuep++;
2250 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2254 /* make sure we have enough slots */
2255 if (*smbp->wctp <= slot) {
2256 if (smbp->oddByte) {
2258 *smbp->wctp = slot+1;
2263 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2264 *parmDatap++ = parmValue & 0xff;
2267 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2271 lastSlashp = strrchr(inPathp, '\\');
2273 *lastComponentp = lastSlashp;
2276 if (inPathp == lastSlashp)
2278 *outPathp++ = *inPathp++;
2287 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2292 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2297 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2303 tlen = inp[0] + (inp[1]<<8);
2304 inp += 2; /* skip length field */
2307 *chainpp = inp + tlen;
2316 /* format a packet as a response */
2317 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2322 outp = (smb_t *) op;
2324 /* zero the basic structure through the smb_wct field, and zero the data
2325 * size field, assuming that wct stays zero; otherwise, you have to
2326 * explicitly set the data size field, too.
2328 inSmbp = (smb_t *) inp;
2329 memset(outp, 0, sizeof(smb_t)+2);
2335 outp->com = inSmbp->com;
2336 outp->tid = inSmbp->tid;
2337 outp->pid = inSmbp->pid;
2338 outp->uid = inSmbp->uid;
2339 outp->mid = inSmbp->mid;
2340 outp->res[0] = inSmbp->res[0];
2341 outp->res[1] = inSmbp->res[1];
2342 op->inCom = inSmbp->com;
2344 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2345 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2347 /* copy fields in generic packet area */
2348 op->wctp = &outp->wct;
2351 /* send a (probably response) packet; vcp tells us to whom to send it.
2352 * we compute the length by looking at wct and bcc fields.
2354 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2368 memset((char *)ncbp, 0, sizeof(NCB));
2370 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2371 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2372 extra += tp[0] + (tp[1]<<8);
2373 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2374 extra += 3; /* wct and length fields */
2376 ncbp->ncb_length = extra; /* bytes to send */
2377 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2378 ncbp->ncb_lana_num = vcp->lana;
2379 ncbp->ncb_command = NCBSEND; /* op means send data */
2380 ncbp->ncb_buffer = (char *) inp;/* packet */
2381 code = Netbios(ncbp);
2384 const char * s = ncb_error_string(code);
2385 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2386 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2388 lock_ObtainMutex(&vcp->mx);
2389 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2390 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2392 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2393 lock_ReleaseMutex(&vcp->mx);
2394 lock_ObtainWrite(&smb_globalLock);
2395 dead_sessions[vcp->session] = TRUE;
2396 lock_ReleaseWrite(&smb_globalLock);
2397 smb_CleanupDeadVC(vcp);
2399 lock_ReleaseMutex(&vcp->mx);
2407 void smb_MapNTError(long code, unsigned long *NTStatusp)
2409 unsigned long NTStatus;
2411 /* map CM_ERROR_* errors to NT 32-bit status codes */
2412 /* NT Status codes are listed in ntstatus.h not winerror.h */
2413 if (code == CM_ERROR_NOSUCHCELL) {
2414 NTStatus = 0xC000000FL; /* No such file */
2416 else if (code == CM_ERROR_NOSUCHVOLUME) {
2417 NTStatus = 0xC000000FL; /* No such file */
2419 else if (code == CM_ERROR_TIMEDOUT) {
2421 NTStatus = 0xC00000CFL; /* Sharing Paused */
2423 NTStatus = 0x00000102L; /* Timeout */
2426 else if (code == CM_ERROR_RETRY) {
2427 NTStatus = 0xC000022DL; /* Retry */
2429 else if (code == CM_ERROR_NOACCESS) {
2430 NTStatus = 0xC0000022L; /* Access denied */
2432 else if (code == CM_ERROR_READONLY) {
2433 NTStatus = 0xC00000A2L; /* Write protected */
2435 else if (code == CM_ERROR_NOSUCHFILE) {
2436 NTStatus = 0xC000000FL; /* No such file */
2438 else if (code == CM_ERROR_NOSUCHPATH) {
2439 NTStatus = 0xC000003AL; /* Object path not found */
2441 else if (code == CM_ERROR_TOOBIG) {
2442 NTStatus = 0xC000007BL; /* Invalid image format */
2444 else if (code == CM_ERROR_INVAL) {
2445 NTStatus = 0xC000000DL; /* Invalid parameter */
2447 else if (code == CM_ERROR_BADFD) {
2448 NTStatus = 0xC0000008L; /* Invalid handle */
2450 else if (code == CM_ERROR_BADFDOP) {
2451 NTStatus = 0xC0000022L; /* Access denied */
2453 else if (code == CM_ERROR_EXISTS) {
2454 NTStatus = 0xC0000035L; /* Object name collision */
2456 else if (code == CM_ERROR_NOTEMPTY) {
2457 NTStatus = 0xC0000101L; /* Directory not empty */
2459 else if (code == CM_ERROR_CROSSDEVLINK) {
2460 NTStatus = 0xC00000D4L; /* Not same device */
2462 else if (code == CM_ERROR_NOTDIR) {
2463 NTStatus = 0xC0000103L; /* Not a directory */
2465 else if (code == CM_ERROR_ISDIR) {
2466 NTStatus = 0xC00000BAL; /* File is a directory */
2468 else if (code == CM_ERROR_BADOP) {
2470 /* I have no idea where this comes from */
2471 NTStatus = 0xC09820FFL; /* SMB no support */
2473 NTStatus = 0xC00000BBL; /* Not supported */
2474 #endif /* COMMENT */
2476 else if (code == CM_ERROR_BADSHARENAME) {
2477 NTStatus = 0xC00000CCL; /* Bad network name */
2479 else if (code == CM_ERROR_NOIPC) {
2481 NTStatus = 0xC0000022L; /* Access Denied */
2483 NTStatus = 0xC000013DL; /* Remote Resources */
2486 else if (code == CM_ERROR_CLOCKSKEW) {
2487 NTStatus = 0xC0000133L; /* Time difference at DC */
2489 else if (code == CM_ERROR_BADTID) {
2490 NTStatus = 0xC0982005L; /* SMB bad TID */
2492 else if (code == CM_ERROR_USESTD) {
2493 NTStatus = 0xC09820FBL; /* SMB use standard */
2495 else if (code == CM_ERROR_QUOTA) {
2497 NTStatus = 0xC0000044L; /* Quota exceeded */
2499 NTStatus = 0xC000007FL; /* Disk full */
2502 else if (code == CM_ERROR_SPACE) {
2503 NTStatus = 0xC000007FL; /* Disk full */
2505 else if (code == CM_ERROR_ATSYS) {
2506 NTStatus = 0xC0000033L; /* Object name invalid */
2508 else if (code == CM_ERROR_BADNTFILENAME) {
2509 NTStatus = 0xC0000033L; /* Object name invalid */
2511 else if (code == CM_ERROR_WOULDBLOCK) {
2512 NTStatus = 0xC0000055L; /* Lock not granted */
2514 else if (code == CM_ERROR_SHARING_VIOLATION) {
2515 NTStatus = 0xC0000043L; /* Sharing violation */
2517 else if (code == CM_ERROR_LOCK_CONFLICT) {
2518 NTStatus = 0xC0000054L; /* Lock conflict */
2520 else if (code == CM_ERROR_PARTIALWRITE) {
2521 NTStatus = 0xC000007FL; /* Disk full */
2523 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2524 NTStatus = 0xC0000023L; /* Buffer too small */
2526 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2527 NTStatus = 0xC0000035L; /* Object name collision */
2529 else if (code == CM_ERROR_BADPASSWORD) {
2530 NTStatus = 0xC000006DL; /* unknown username or bad password */
2532 else if (code == CM_ERROR_BADLOGONTYPE) {
2533 NTStatus = 0xC000015BL; /* logon type not granted */
2535 else if (code == CM_ERROR_GSSCONTINUE) {
2536 NTStatus = 0xC0000016L; /* more processing required */
2538 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2540 NTStatus = 0xC0000280L; /* reparse point not resolved */
2542 NTStatus = 0xC0000022L; /* Access Denied */
2545 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2546 NTStatus = 0xC0000257L; /* Path Not Covered */
2549 else if (code == CM_ERROR_ALLBUSY) {
2550 NTStatus = 0xC00000BFL; /* Network Busy */
2552 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2553 NTStatus = 0xC0000350L; /* Remote Host Down */
2556 /* we do not want to be telling the SMB/CIFS client that
2557 * the AFS Client Service is busy or down.
2559 else if (code == CM_ERROR_ALLBUSY ||
2560 code == CM_ERROR_ALLOFFLINE ||
2561 code == CM_ERROR_ALLDOWN) {
2562 NTStatus = 0xC00000BEL; /* Bad Network Path */
2565 else if (code == RXKADUNKNOWNKEY) {
2566 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2568 NTStatus = 0xC0982001L; /* SMB non-specific error */
2571 *NTStatusp = NTStatus;
2572 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2575 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2576 unsigned char *classp)
2578 unsigned char class;
2579 unsigned short error;
2581 /* map CM_ERROR_* errors to SMB errors */
2582 if (code == CM_ERROR_NOSUCHCELL) {
2584 error = 3; /* bad path */
2586 else if (code == CM_ERROR_NOSUCHVOLUME) {
2588 error = 3; /* bad path */
2590 else if (code == CM_ERROR_TIMEDOUT) {
2592 error = 81; /* server is paused */
2594 else if (code == CM_ERROR_RETRY) {
2595 class = 2; /* shouldn't happen */
2598 else if (code == CM_ERROR_NOACCESS) {
2600 error = 4; /* bad access */
2602 else if (code == CM_ERROR_READONLY) {
2604 error = 19; /* read only */
2606 else if (code == CM_ERROR_NOSUCHFILE) {
2608 error = 2; /* ENOENT! */
2610 else if (code == CM_ERROR_NOSUCHPATH) {
2612 error = 3; /* Bad path */
2614 else if (code == CM_ERROR_TOOBIG) {
2616 error = 11; /* bad format */
2618 else if (code == CM_ERROR_INVAL) {
2619 class = 2; /* server non-specific error code */
2622 else if (code == CM_ERROR_BADFD) {
2624 error = 6; /* invalid file handle */
2626 else if (code == CM_ERROR_BADFDOP) {
2627 class = 1; /* invalid op on FD */
2630 else if (code == CM_ERROR_EXISTS) {
2632 error = 80; /* file already exists */
2634 else if (code == CM_ERROR_NOTEMPTY) {
2636 error = 5; /* delete directory not empty */
2638 else if (code == CM_ERROR_CROSSDEVLINK) {
2640 error = 17; /* EXDEV */
2642 else if (code == CM_ERROR_NOTDIR) {
2643 class = 1; /* bad path */
2646 else if (code == CM_ERROR_ISDIR) {
2647 class = 1; /* access denied; DOS doesn't have a good match */
2650 else if (code == CM_ERROR_BADOP) {
2654 else if (code == CM_ERROR_BADSHARENAME) {
2658 else if (code == CM_ERROR_NOIPC) {
2660 error = 4; /* bad access */
2662 else if (code == CM_ERROR_CLOCKSKEW) {
2663 class = 1; /* invalid function */
2666 else if (code == CM_ERROR_BADTID) {
2670 else if (code == CM_ERROR_USESTD) {
2674 else if (code == CM_ERROR_REMOTECONN) {
2678 else if (code == CM_ERROR_QUOTA) {
2679 if (vcp->flags & SMB_VCFLAG_USEV3) {
2681 error = 39; /* disk full */
2685 error = 5; /* access denied */
2688 else if (code == CM_ERROR_SPACE) {
2689 if (vcp->flags & SMB_VCFLAG_USEV3) {
2691 error = 39; /* disk full */
2695 error = 5; /* access denied */
2698 else if (code == CM_ERROR_PARTIALWRITE) {
2700 error = 39; /* disk full */
2702 else if (code == CM_ERROR_ATSYS) {
2704 error = 2; /* ENOENT */
2706 else if (code == CM_ERROR_WOULDBLOCK) {
2708 error = 33; /* lock conflict */
2710 else if (code == CM_ERROR_LOCK_CONFLICT) {
2712 error = 33; /* lock conflict */
2714 else if (code == CM_ERROR_SHARING_VIOLATION) {
2716 error = 33; /* lock conflict */
2718 else if (code == CM_ERROR_NOFILES) {
2720 error = 18; /* no files in search */
2722 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2724 error = 183; /* Samba uses this */
2726 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2727 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2729 error = 2; /* bad password */
2731 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2733 error = 3; /* bad path */
2742 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2745 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2747 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2748 return CM_ERROR_BADOP;
2751 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2753 unsigned short EchoCount, i;
2754 char *data, *outdata;
2757 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2759 for (i=1; i<=EchoCount; i++) {
2760 data = smb_GetSMBData(inp, &dataSize);
2761 smb_SetSMBParm(outp, 0, i);
2762 smb_SetSMBDataLength(outp, dataSize);
2763 outdata = smb_GetSMBData(outp, NULL);
2764 memcpy(outdata, data, dataSize);
2765 smb_SendPacket(vcp, outp);
2771 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2774 long count, minCount, finalCount;
2779 cm_user_t *userp = NULL;
2782 char *rawBuf = NULL;
2787 fd = smb_GetSMBParm(inp, 0);
2788 count = smb_GetSMBParm(inp, 3);
2789 minCount = smb_GetSMBParm(inp, 4);
2790 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2792 if (*inp->wctp == 10) {
2793 /* we were sent a request with 64-bit file offsets */
2794 #ifdef AFS_LARGEFILES
2795 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2797 if (LargeIntegerLessThanZero(offset)) {
2798 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2802 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2803 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2806 offset.HighPart = 0;
2810 /* we were sent a request with 32-bit file offsets */
2811 offset.HighPart = 0;
2814 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2815 fd, offset.HighPart, offset.LowPart, count);
2817 fidp = smb_FindFID(vcp, fd, 0);
2821 pid = ((smb_t *) inp)->pid;
2823 LARGE_INTEGER LOffset, LLength;
2826 key = cm_GenerateKey(vcp->vcID, pid, fd);
2828 LOffset.HighPart = offset.HighPart;
2829 LOffset.LowPart = offset.LowPart;
2830 LLength.HighPart = 0;
2831 LLength.LowPart = count;
2833 lock_ObtainMutex(&fidp->scp->mx);
2834 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2835 lock_ReleaseMutex(&fidp->scp->mx);
2841 lock_ObtainMutex(&smb_RawBufLock);
2843 /* Get a raw buf, from head of list */
2844 rawBuf = smb_RawBufs;
2845 smb_RawBufs = *(char **)smb_RawBufs;
2847 lock_ReleaseMutex(&smb_RawBufLock);
2851 lock_ObtainMutex(&fidp->mx);
2852 if (fidp->flags & SMB_FID_IOCTL)
2854 lock_ReleaseMutex(&fidp->mx);
2855 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2857 /* Give back raw buffer */
2858 lock_ObtainMutex(&smb_RawBufLock);
2859 *((char **) rawBuf) = smb_RawBufs;
2861 smb_RawBufs = rawBuf;
2862 lock_ReleaseMutex(&smb_RawBufLock);
2865 smb_ReleaseFID(fidp);
2868 lock_ReleaseMutex(&fidp->mx);
2870 userp = smb_GetUserFromVCP(vcp, inp);
2872 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2878 cm_ReleaseUser(userp);
2881 smb_ReleaseFID(fidp);
2885 memset((char *)ncbp, 0, sizeof(NCB));
2887 ncbp->ncb_length = (unsigned short) finalCount;
2888 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2889 ncbp->ncb_lana_num = vcp->lana;
2890 ncbp->ncb_command = NCBSEND;
2891 ncbp->ncb_buffer = rawBuf;
2893 code = Netbios(ncbp);
2895 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2898 /* Give back raw buffer */
2899 lock_ObtainMutex(&smb_RawBufLock);
2900 *((char **) rawBuf) = smb_RawBufs;
2902 smb_RawBufs = rawBuf;
2903 lock_ReleaseMutex(&smb_RawBufLock);
2909 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2911 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2916 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2918 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2923 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2930 int VistaProtoIndex;
2931 int protoIndex; /* index we're using */
2936 char protocol_array[10][1024]; /* protocol signature of the client */
2937 int caps; /* capabilities */
2940 TIME_ZONE_INFORMATION tzi;
2942 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2945 namep = smb_GetSMBData(inp, &dbytes);
2948 coreProtoIndex = -1; /* not found */
2951 VistaProtoIndex = -1;
2952 while(namex < dbytes) {
2953 osi_Log1(smb_logp, "Protocol %s",
2954 osi_LogSaveString(smb_logp, namep+1));
2955 strcpy(protocol_array[tcounter], namep+1);
2957 /* namep points at the first protocol, or really, a 0x02
2958 * byte preceding the null-terminated ASCII name.
2960 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2961 coreProtoIndex = tcounter;
2963 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2964 v3ProtoIndex = tcounter;
2966 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2967 NTProtoIndex = tcounter;
2969 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
2970 VistaProtoIndex = tcounter;
2973 /* compute size of protocol entry */
2974 entryLength = (int)strlen(namep+1);
2975 entryLength += 2; /* 0x02 bytes and null termination */
2977 /* advance over this protocol entry */
2978 namex += entryLength;
2979 namep += entryLength;
2980 tcounter++; /* which proto entry we're looking at */
2983 lock_ObtainMutex(&vcp->mx);
2985 if (VistaProtoIndex != -1) {
2986 protoIndex = VistaProtoIndex;
2987 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2990 if (NTProtoIndex != -1) {
2991 protoIndex = NTProtoIndex;
2992 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2994 else if (v3ProtoIndex != -1) {
2995 protoIndex = v3ProtoIndex;
2996 vcp->flags |= SMB_VCFLAG_USEV3;
2998 else if (coreProtoIndex != -1) {
2999 protoIndex = coreProtoIndex;
3000 vcp->flags |= SMB_VCFLAG_USECORE;
3002 else protoIndex = -1;
3003 lock_ReleaseMutex(&vcp->mx);
3005 if (protoIndex == -1)
3006 return CM_ERROR_INVAL;
3007 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3008 smb_SetSMBParm(outp, 0, protoIndex);
3009 if (smb_authType != SMB_AUTH_NONE) {
3010 smb_SetSMBParmByte(outp, 1,
3011 NEGOTIATE_SECURITY_USER_LEVEL |
3012 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3014 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3016 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3017 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3018 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3019 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3020 /* The session key is not a well documented field however most clients
3021 * will echo back the session key to the server. Currently we are using
3022 * the same value for all sessions. We should generate a random value
3023 * and store it into the vcp
3025 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3026 smb_SetSMBParm(outp, 8, 1);
3028 * Tried changing the capabilities to support for W2K - defect 117695
3029 * Maybe something else needs to be changed here?
3033 smb_SetSMBParmLong(outp, 9, 0x43fd);
3035 smb_SetSMBParmLong(outp, 9, 0x251);
3038 * 32-bit error codes *
3043 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3045 NTNEGOTIATE_CAPABILITY_DFS |
3047 #ifdef AFS_LARGEFILES
3048 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3050 NTNEGOTIATE_CAPABILITY_NTFIND |
3051 NTNEGOTIATE_CAPABILITY_RAWMODE |
3052 NTNEGOTIATE_CAPABILITY_NTSMB;
3054 if ( smb_authType == SMB_AUTH_EXTENDED )
3055 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3057 smb_SetSMBParmLong(outp, 9, caps);
3059 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3060 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3061 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3063 GetTimeZoneInformation(&tzi);
3064 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3066 if (smb_authType == SMB_AUTH_NTLM) {
3067 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3068 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3069 /* paste in encryption key */
3070 datap = smb_GetSMBData(outp, NULL);
3071 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3072 /* and the faux domain name */
3073 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3074 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3078 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3080 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3082 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3084 datap = smb_GetSMBData(outp, NULL);
3085 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3088 datap += sizeof(smb_ServerGUID);
3089 memcpy(datap, secBlob, secBlobLength);
3093 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3094 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3097 else if (v3ProtoIndex != -1) {
3098 smb_SetSMBParm(outp, 0, protoIndex);
3100 /* NOTE: Extended authentication cannot be negotiated with v3
3101 * therefore we fail over to NTLM
3103 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3104 smb_SetSMBParm(outp, 1,
3105 NEGOTIATE_SECURITY_USER_LEVEL |
3106 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3108 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3110 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3111 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3112 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3113 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3114 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3115 smb_SetSMBParm(outp, 7, 1);
3117 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3118 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3119 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3121 GetTimeZoneInformation(&tzi);
3122 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3124 /* NOTE: Extended authentication cannot be negotiated with v3
3125 * therefore we fail over to NTLM
3127 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3128 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3129 smb_SetSMBParm(outp, 12, 0); /* resvd */
3130 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3131 datap = smb_GetSMBData(outp, NULL);
3132 /* paste in a new encryption key */
3133 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3134 /* and the faux domain name */
3135 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3137 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3138 smb_SetSMBParm(outp, 12, 0); /* resvd */
3139 smb_SetSMBDataLength(outp, 0);
3142 else if (coreProtoIndex != -1) { /* not really supported anymore */
3143 smb_SetSMBParm(outp, 0, protoIndex);
3144 smb_SetSMBDataLength(outp, 0);
3149 void smb_CheckVCs(void)
3151 smb_vc_t * vcp, *nextp;
3152 smb_packet_t * outp = GetPacket();
3155 lock_ObtainWrite(&smb_rctLock);
3156 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3158 if (vcp->magic != SMB_VC_MAGIC)
3159 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3160 __FILE__, __LINE__);
3164 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3167 smb_HoldVCNoLock(vcp);
3169 smb_HoldVCNoLock(nextp);
3170 smb_FormatResponsePacket(vcp, NULL, outp);
3171 smbp = (smb_t *)outp;
3172 outp->inCom = smbp->com = 0x2b /* Echo */;
3180 smb_SetSMBParm(outp, 0, 0);
3181 smb_SetSMBDataLength(outp, 0);
3182 lock_ReleaseWrite(&smb_rctLock);
3184 smb_SendPacket(vcp, outp);
3186 lock_ObtainWrite(&smb_rctLock);
3187 smb_ReleaseVCNoLock(vcp);
3189 smb_ReleaseVCNoLock(nextp);
3191 lock_ReleaseWrite(&smb_rctLock);
3192 smb_FreePacket(outp);
3195 void smb_Daemon(void *parmp)
3197 afs_uint32 count = 0;
3198 smb_username_t **unpp;
3201 while(smbShutdownFlag == 0) {
3205 if (smbShutdownFlag == 1)
3208 if ((count % 72) == 0) { /* every five minutes */
3210 time_t old_localZero = smb_localZero;
3212 /* Initialize smb_localZero */
3213 myTime.tm_isdst = -1; /* compute whether on DST or not */
3214 myTime.tm_year = 70;
3220 smb_localZero = mktime(&myTime);
3222 #ifndef USE_NUMERIC_TIME_CONV
3223 smb_CalculateNowTZ();
3224 #endif /* USE_NUMERIC_TIME_CONV */
3225 #ifdef AFS_FREELANCE
3226 if ( smb_localZero != old_localZero )
3227 cm_noteLocalMountPointChange();
3233 /* GC smb_username_t objects that will no longer be used */
3235 lock_ObtainWrite(&smb_rctLock);
3236 for ( unpp=&usernamesp; *unpp; ) {
3238 smb_username_t *unp;
3240 lock_ObtainMutex(&(*unpp)->mx);
3241 if ( (*unpp)->refCount > 0 ||
3242 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3243 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3245 else if (!smb_LogoffTokenTransfer ||
3246 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3248 lock_ReleaseMutex(&(*unpp)->mx);
3256 lock_FinalizeMutex(&unp->mx);
3262 lock_ReleaseWrite(&smb_rctLock);
3263 cm_ReleaseUser(userp);
3264 lock_ObtainWrite(&smb_rctLock);
3267 unpp = &(*unpp)->nextp;
3270 lock_ReleaseWrite(&smb_rctLock);
3272 /* XXX GC dir search entries */
3276 void smb_WaitingLocksDaemon()
3278 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3279 smb_waitingLock_t *wl, *wlNext;
3282 smb_packet_t *inp, *outp;
3286 while (smbShutdownFlag == 0) {
3287 lock_ObtainWrite(&smb_globalLock);
3288 nwlRequest = smb_allWaitingLocks;
3289 if (nwlRequest == NULL) {
3290 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3295 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3302 lock_ObtainWrite(&smb_globalLock);
3304 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3306 wlRequest = nwlRequest;
3307 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3308 lock_ReleaseWrite(&smb_globalLock);
3312 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3313 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3316 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3318 /* wl->state is either _DONE or _WAITING. _ERROR
3319 would no longer be on the queue. */
3320 code = cm_RetryLock( wl->lockp,
3321 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3324 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3325 } else if (code != CM_ERROR_WOULDBLOCK) {
3326 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3331 if (code == CM_ERROR_WOULDBLOCK) {
3334 if (wlRequest->timeRemaining != 0xffffffff
3335 && (wlRequest->timeRemaining -= 1000) < 0)
3347 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3350 scp = wlRequest->scp;
3351 osi_Log2(afsd_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3355 lock_ObtainMutex(&scp->mx);
3357 for (wl = wlRequest->locks; wl; wl = wlNext) {
3358 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3360 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3361 wl->LLength, wl->key, NULL, &req);
3363 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3368 lock_ReleaseMutex(&scp->mx);
3372 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3375 for (wl = wlRequest->locks; wl; wl = wlNext) {
3376 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3377 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3382 vcp = wlRequest->vcp;
3383 inp = wlRequest->inp;
3384 outp = wlRequest->outp;
3386 ncbp->ncb_length = inp->ncb_length;
3387 inp->spacep = cm_GetSpace();
3389 /* Remove waitingLock from list */
3390 lock_ObtainWrite(&smb_globalLock);
3391 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3393 lock_ReleaseWrite(&smb_globalLock);
3395 /* Resume packet processing */
3397 smb_SetSMBDataLength(outp, 0);
3398 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3399 outp->resumeCode = code;
3401 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3404 cm_FreeSpace(inp->spacep);
3405 smb_FreePacket(inp);
3406 smb_FreePacket(outp);
3408 cm_ReleaseSCache(wlRequest->scp);
3411 } while (nwlRequest && smbShutdownFlag == 0);
3416 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3418 osi_Log0(smb_logp, "SMB receive get disk attributes");
3420 smb_SetSMBParm(outp, 0, 32000);
3421 smb_SetSMBParm(outp, 1, 64);
3422 smb_SetSMBParm(outp, 2, 1024);
3423 smb_SetSMBParm(outp, 3, 30000);
3424 smb_SetSMBParm(outp, 4, 0);
3425 smb_SetSMBDataLength(outp, 0);
3429 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3433 unsigned short newTid;
3434 char shareName[256];
3442 osi_Log0(smb_logp, "SMB receive tree connect");
3444 /* parse input parameters */
3445 tp = smb_GetSMBData(inp, NULL);
3446 pathp = smb_ParseASCIIBlock(tp, &tp);
3447 if (smb_StoreAnsiFilenames)
3448 OemToChar(pathp,pathp);
3449 passwordp = smb_ParseASCIIBlock(tp, &tp);
3450 tp = strrchr(pathp, '\\');
3452 return CM_ERROR_BADSMB;
3453 strcpy(shareName, tp+1);
3455 lock_ObtainMutex(&vcp->mx);
3456 newTid = vcp->tidCounter++;
3457 lock_ReleaseMutex(&vcp->mx);
3459 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3460 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3461 userp = smb_GetUserFromUID(uidp);
3462 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3464 smb_ReleaseUID(uidp);
3466 smb_ReleaseTID(tidp);
3467 return CM_ERROR_BADSHARENAME;
3469 lock_ObtainMutex(&tidp->mx);
3470 tidp->userp = userp;
3471 tidp->pathname = sharePath;
3472 lock_ReleaseMutex(&tidp->mx);
3473 smb_ReleaseTID(tidp);
3475 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3476 smb_SetSMBParm(rsp, 1, newTid);
3477 smb_SetSMBDataLength(rsp, 0);
3479 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3483 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3487 if (*inp++ != 0x1) return NULL;
3488 tlen = inp[0] + (inp[1]<<8);
3489 inp += 2; /* skip length field */
3492 *chainpp = inp + tlen;
3495 if (lengthp) *lengthp = tlen;
3500 /* set maskp to the mask part of the incoming path.
3501 * Mask is 11 bytes long (8.3 with the dot elided).
3502 * Returns true if succeeds with a valid name, otherwise it does
3503 * its best, but returns false.
3505 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3513 /* starts off valid */
3516 /* mask starts out all blanks */
3517 memset(maskp, ' ', 11);
3519 /* find last backslash, or use whole thing if there is none */
3520 tp = strrchr(pathp, '\\');
3521 if (!tp) tp = pathp;
3522 else tp++; /* skip slash */
3526 /* names starting with a dot are illegal */
3527 if (*tp == '.') valid8Dot3 = 0;
3531 if (tc == 0) return valid8Dot3;
3532 if (tc == '.' || tc == '"') break;
3533 if (i < 8) *up++ = tc;
3534 else valid8Dot3 = 0;
3537 /* if we get here, tp point after the dot */
3538 up = maskp+8; /* ext goes here */
3545 if (tc == '.' || tc == '"')
3548 /* copy extension if not too long */
3558 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3568 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3570 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3574 /* otherwise, we have a valid 8.3 name; see if we have a match,
3575 * treating '?' as a wildcard in maskp (but not in the file name).
3577 tp1 = umask; /* real name, in mask format */
3578 tp2 = maskp; /* mask, in mask format */
3579 for(i=0; i<11; i++) {
3580 tc1 = *tp1++; /* char from real name */
3581 tc2 = *tp2++; /* char from mask */
3582 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3583 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3586 if (tc2 == '?' && tc1 != ' ')
3593 /* we got a match */
3597 char *smb_FindMask(char *pathp)
3601 tp = strrchr(pathp, '\\'); /* find last slash */
3604 return tp+1; /* skip the slash */
3606 return pathp; /* no slash, return the entire path */
3609 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3611 unsigned char *pathp;
3613 unsigned char mask[11];
3614 unsigned char *statBlockp;
3615 unsigned char initStatBlock[21];
3618 osi_Log0(smb_logp, "SMB receive search volume");
3620 /* pull pathname and stat block out of request */
3621 tp = smb_GetSMBData(inp, NULL);
3622 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3623 osi_assert(pathp != NULL);
3624 if (smb_StoreAnsiFilenames)
3625 OemToChar(pathp,pathp);
3626 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3627 osi_assert(statBlockp != NULL);
3629 statBlockp = initStatBlock;
3633 /* for returning to caller */
3634 smb_Get8Dot3MaskFromPath(mask, pathp);
3636 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3637 tp = smb_GetSMBData(outp, NULL);
3639 *tp++ = 43; /* bytes in a dir entry */
3640 *tp++ = 0; /* high byte in counter */
3642 /* now marshall the dir entry, starting with the search status */
3643 *tp++ = statBlockp[0]; /* Reserved */
3644 memcpy(tp, mask, 11); tp += 11; /* FileName */
3646 /* now pass back server use info, with 1st byte non-zero */
3648 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3650 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3652 *tp++ = 0x8; /* attribute: volume */
3662 /* 4 byte file size */
3668 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3669 memset(tp, ' ', 13);
3672 /* set the length of the data part of the packet to 43 + 3, for the dir
3673 * entry plus the 5 and the length fields.
3675 smb_SetSMBDataLength(outp, 46);
3679 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3680 cm_user_t *userp, cm_req_t *reqp)
3688 smb_dirListPatch_t *patchp;
3689 smb_dirListPatch_t *npatchp;
3691 for (patchp = *dirPatchespp; patchp; patchp =
3692 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3694 dptr = patchp->dptr;
3696 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3698 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3699 *dptr++ = SMB_ATTR_HIDDEN;
3702 lock_ObtainMutex(&scp->mx);
3703 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3704 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3706 lock_ReleaseMutex(&scp->mx);
3707 cm_ReleaseSCache(scp);
3708 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3709 *dptr++ = SMB_ATTR_HIDDEN;
3713 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3715 attr = smb_Attributes(scp);
3716 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3717 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3718 attr |= SMB_ATTR_HIDDEN;
3722 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3725 shortTemp = (unsigned short) (dosTime & 0xffff);
3726 *((u_short *)dptr) = shortTemp;
3729 /* and copy out date */
3730 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3731 *((u_short *)dptr) = shortTemp;
3734 /* copy out file length */
3735 *((u_long *)dptr) = scp->length.LowPart;
3737 lock_ReleaseMutex(&scp->mx);
3738 cm_ReleaseSCache(scp);
3741 /* now free the patches */
3742 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3743 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3747 /* and mark the list as empty */
3748 *dirPatchespp = NULL;
3753 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3762 smb_dirListPatch_t *dirListPatchesp;
3763 smb_dirListPatch_t *curPatchp;
3767 osi_hyper_t dirLength;
3768 osi_hyper_t bufferOffset;
3769 osi_hyper_t curOffset;
3771 unsigned char *inCookiep;
3772 smb_dirSearch_t *dsp;
3776 unsigned long clientCookie;
3777 cm_pageHeader_t *pageHeaderp;
3778 cm_user_t *userp = NULL;
3785 long nextEntryCookie;
3786 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3787 char resByte; /* reserved byte from the cookie */
3788 char *op; /* output data ptr */
3789 char *origOp; /* original value of op */
3790 cm_space_t *spacep; /* for pathname buffer */
3801 maxCount = smb_GetSMBParm(inp, 0);
3803 dirListPatchesp = NULL;
3805 caseFold = CM_FLAG_CASEFOLD;
3807 tp = smb_GetSMBData(inp, NULL);
3808 pathp = smb_ParseASCIIBlock(tp, &tp);
3809 if (smb_StoreAnsiFilenames)
3810 OemToChar(pathp,pathp);
3811 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3813 /* bail out if request looks bad */
3814 if (!tp || !pathp) {
3815 return CM_ERROR_BADSMB;
3818 /* We can handle long names */
3819 if (vcp->flags & SMB_VCFLAG_USENT)
3820 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3822 /* make sure we got a whole search status */
3823 if (dataLength < 21) {
3824 nextCookie = 0; /* start at the beginning of the dir */
3827 attribute = smb_GetSMBParm(inp, 1);
3829 /* handle volume info in another function */
3830 if (attribute & 0x8)
3831 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3833 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3834 maxCount, osi_LogSaveString(smb_logp, pathp));
3836 if (*pathp == 0) { /* null pathp, treat as root dir */
3837 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3838 return CM_ERROR_NOFILES;
3842 dsp = smb_NewDirSearch(0);
3843 dsp->attribute = attribute;
3844 smb_Get8Dot3MaskFromPath(mask, pathp);
3845 memcpy(dsp->mask, mask, 11);
3847 /* track if this is likely to match a lot of entries */
3848 if (smb_IsStarMask(mask))
3853 /* pull the next cookie value out of the search status block */
3854 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3855 + (inCookiep[16]<<24);
3856 dsp = smb_FindDirSearch(inCookiep[12]);
3858 /* can't find dir search status; fatal error */
3859 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3860 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3861 return CM_ERROR_BADFD;
3863 attribute = dsp->attribute;
3864 resByte = inCookiep[0];
3866 /* copy out client cookie, in host byte order. Don't bother
3867 * interpreting it, since we're just passing it through, anyway.
3869 memcpy(&clientCookie, &inCookiep[17], 4);
3871 memcpy(mask, dsp->mask, 11);
3873 /* assume we're doing a star match if it has continued for more
3879 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3880 nextCookie, dsp->cookie, attribute);
3882 userp = smb_GetUserFromVCP(vcp, inp);
3884 /* try to get the vnode for the path name next */
3885 lock_ObtainMutex(&dsp->mx);
3888 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3892 spacep = inp->spacep;
3893 smb_StripLastComponent(spacep->data, NULL, pathp);
3894 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3896 lock_ReleaseMutex(&dsp->mx);
3897 cm_ReleaseUser(userp);
3898 smb_DeleteDirSearch(dsp);
3899 smb_ReleaseDirSearch(dsp);
3900 return CM_ERROR_NOFILES;
3902 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3903 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3906 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3907 cm_ReleaseSCache(scp);
3908 lock_ReleaseMutex(&dsp->mx);
3909 cm_ReleaseUser(userp);
3910 smb_DeleteDirSearch(dsp);
3911 smb_ReleaseDirSearch(dsp);
3912 if ( WANTS_DFS_PATHNAMES(inp) )
3913 return CM_ERROR_PATH_NOT_COVERED;
3915 return CM_ERROR_BADSHARENAME;
3917 #endif /* DFS_SUPPORT */
3920 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
3921 /* we need one hold for the entry we just stored into,
3922 * and one for our own processing. When we're done with this
3923 * function, we'll drop the one for our own processing.
3924 * We held it once from the namei call, and so we do another hold
3928 lock_ObtainMutex(&scp->mx);
3929 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3930 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3931 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3932 dsp->flags |= SMB_DIRSEARCH_BULKST;
3933 dsp->scp->bulkStatProgress = hzero;
3935 lock_ReleaseMutex(&scp->mx);
3938 lock_ReleaseMutex(&dsp->mx);
3940 cm_ReleaseUser(userp);
3941 smb_DeleteDirSearch(dsp);
3942 smb_ReleaseDirSearch(dsp);
3946 /* reserves space for parameter; we'll adjust it again later to the
3947 * real count of the # of entries we returned once we've actually
3948 * assembled the directory listing.
3950 smb_SetSMBParm(outp, 0, 0);
3952 /* get the directory size */
3953 lock_ObtainMutex(&scp->mx);
3954 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3955 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3957 lock_ReleaseMutex(&scp->mx);
3958 cm_ReleaseSCache(scp);
3959 cm_ReleaseUser(userp);
3960 smb_DeleteDirSearch(dsp);
3961 smb_ReleaseDirSearch(dsp);
3965 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3967 dirLength = scp->length;
3969 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3970 curOffset.HighPart = 0;
3971 curOffset.LowPart = nextCookie;
3972 origOp = op = smb_GetSMBData(outp, NULL);
3973 /* and write out the basic header */
3974 *op++ = 5; /* variable block */
3975 op += 2; /* skip vbl block length; we'll fill it in later */
3979 /* make sure that curOffset.LowPart doesn't point to the first
3980 * 32 bytes in the 2nd through last dir page, and that it doesn't
3981 * point at the first 13 32-byte chunks in the first dir page,
3982 * since those are dir and page headers, and don't contain useful
3985 temp = curOffset.LowPart & (2048-1);
3986 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3987 /* we're in the first page */
3988 if (temp < 13*32) temp = 13*32;
3991 /* we're in a later dir page */
3992 if (temp < 32) temp = 32;
3995 /* make sure the low order 5 bits are zero */
3998 /* now put temp bits back ito curOffset.LowPart */
3999 curOffset.LowPart &= ~(2048-1);
4000 curOffset.LowPart |= temp;
4002 /* check if we've returned all the names that will fit in the
4005 if (returnedNames >= maxCount) {
4006 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4007 returnedNames, maxCount);
4011 /* check if we've passed the dir's EOF */
4012 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4014 /* see if we can use the bufferp we have now; compute in which page
4015 * the current offset would be, and check whether that's the offset
4016 * of the buffer we have. If not, get the buffer.
4018 thyper.HighPart = curOffset.HighPart;
4019 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4020 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4023 buf_Release(bufferp);
4026 lock_ReleaseMutex(&scp->mx);
4027 lock_ObtainRead(&scp->bufCreateLock);
4028 code = buf_Get(scp, &thyper, &bufferp);
4029 lock_ReleaseRead(&scp->bufCreateLock);
4030 lock_ObtainMutex(&dsp->mx);
4032 /* now, if we're doing a star match, do bulk fetching of all of
4033 * the status info for files in the dir.
4036 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4037 lock_ObtainMutex(&scp->mx);
4038 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4039 LargeIntegerGreaterThanOrEqualTo(thyper,
4040 scp->bulkStatProgress)) {
4041 /* Don't bulk stat if risking timeout */
4042 int now = GetTickCount();
4043 if (now - req.startTime > RDRtimeout) {
4044 scp->bulkStatProgress = thyper;
4045 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4046 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4047 dsp->scp->bulkStatProgress = hzero;
4049 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4052 lock_ObtainMutex(&scp->mx);
4054 lock_ReleaseMutex(&dsp->mx);
4056 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4060 bufferOffset = thyper;
4062 /* now get the data in the cache */
4064 code = cm_SyncOp(scp, bufferp, userp, &req,
4066 CM_SCACHESYNC_NEEDCALLBACK |
4067 CM_SCACHESYNC_READ);
4069 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4073 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4075 if (cm_HaveBuffer(scp, bufferp, 0)) {
4076 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4080 /* otherwise, load the buffer and try again */
4081 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4083 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4084 scp, bufferp, code);
4089 buf_Release(bufferp);
4093 } /* if (wrong buffer) ... */
4095 /* now we have the buffer containing the entry we're interested in; copy
4096 * it out if it represents a non-deleted entry.
4098 entryInDir = curOffset.LowPart & (2048-1);
4099 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4101 /* page header will help tell us which entries are free. Page header
4102 * can change more often than once per buffer, since AFS 3 dir page size
4103 * may be less than (but not more than a buffer package buffer.
4105 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4106 temp &= ~(2048 - 1); /* turn off intra-page bits */
4107 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4109 /* now determine which entry we're looking at in the page. If it is
4110 * free (there's a free bitmap at the start of the dir), we should
4111 * skip these 32 bytes.
4113 slotInPage = (entryInDir & 0x7e0) >> 5;
4114 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4115 /* this entry is free */
4116 numDirChunks = 1; /* only skip this guy */
4120 tp = bufferp->datap + entryInBuffer;
4121 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4123 /* while we're here, compute the next entry's location, too,
4124 * since we'll need it when writing out the cookie into the dir
4127 * XXXX Probably should do more sanity checking.
4129 numDirChunks = cm_NameEntries(dep->name, NULL);
4131 /* compute the offset of the cookie representing the next entry */
4132 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4134 /* Compute 8.3 name if necessary */
4135 actualName = dep->name;
4136 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4137 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4138 actualName = shortName;
4141 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4142 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4143 osi_LogSaveString(smb_logp, actualName));
4145 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4146 /* this is one of the entries to use: it is not deleted
4147 * and it matches the star pattern we're looking for.
4150 /* Eliminate entries that don't match requested
4153 /* no hidden files */
4154 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4155 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4159 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4161 /* We have already done the cm_TryBulkStat above */
4162 fid.cell = scp->fid.cell;
4163 fid.volume = scp->fid.volume;
4164 fid.vnode = ntohl(dep->fid.vnode);
4165 fid.unique = ntohl(dep->fid.unique);
4166 fileType = cm_FindFileType(&fid);
4167 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4168 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4170 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4171 fileType == CM_SCACHETYPE_DFSLINK ||
4172 fileType == CM_SCACHETYPE_INVALID)
4173 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4178 memcpy(op, mask, 11); op += 11;
4179 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4180 *op++ = (char)(nextEntryCookie & 0xff);
4181 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4182 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4183 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4184 memcpy(op, &clientCookie, 4); op += 4;
4186 /* now we emit the attribute. This is sort of tricky,
4187 * since we need to really stat the file to find out
4188 * what type of entry we've got. Right now, we're
4189 * copying out data from a buffer, while holding the
4190 * scp locked, so it isn't really convenient to stat
4191 * something now. We'll put in a place holder now,
4192 * and make a second pass before returning this to get
4193 * the real attributes. So, we just skip the data for
4194 * now, and adjust it later. We allocate a patch
4195 * record to make it easy to find this point later.
4196 * The replay will happen at a time when it is safe to
4197 * unlock the directory.
4199 curPatchp = malloc(sizeof(*curPatchp));
4200 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4201 curPatchp->dptr = op;
4202 curPatchp->fid.cell = scp->fid.cell;
4203 curPatchp->fid.volume = scp->fid.volume;
4204 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4205 curPatchp->fid.unique = ntohl(dep->fid.unique);
4207 /* do hidden attribute here since name won't be around when applying
4211 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4212 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4214 curPatchp->flags = 0;
4216 op += 9; /* skip attr, time, date and size */
4218 /* zero out name area. The spec says to pad with
4219 * spaces, but Samba doesn't, and neither do we.
4223 /* finally, we get to copy out the name; we know that
4224 * it fits in 8.3 or the pattern wouldn't match, but it
4225 * never hurts to be sure.
4227 strncpy(op, actualName, 13);
4228 if (smb_StoreAnsiFilenames)
4231 /* Uppercase if requested by client */
4232 if (!KNOWS_LONG_NAMES(inp))
4237 /* now, adjust the # of entries copied */
4239 } /* if we're including this name */
4242 /* and adjust curOffset to be where the new cookie is */
4243 thyper.HighPart = 0;
4244 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4245 curOffset = LargeIntegerAdd(thyper, curOffset);
4246 } /* while copying data for dir listing */
4248 /* release the mutex */
4249 lock_ReleaseMutex(&scp->mx);
4251 buf_Release(bufferp);
4255 /* apply and free last set of patches; if not doing a star match, this
4256 * will be empty, but better safe (and freeing everything) than sorry.
4258 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4260 /* special return code for unsuccessful search */
4261 if (code == 0 && dataLength < 21 && returnedNames == 0)
4262 code = CM_ERROR_NOFILES;
4264 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4265 returnedNames, code);
4268 smb_DeleteDirSearch(dsp);
4269 smb_ReleaseDirSearch(dsp);
4270 cm_ReleaseSCache(scp);
4271 cm_ReleaseUser(userp);
4275 /* finalize the output buffer */
4276 smb_SetSMBParm(outp, 0, returnedNames);
4277 temp = (long) (op - origOp);
4278 smb_SetSMBDataLength(outp, temp);
4280 /* the data area is a variable block, which has a 5 (already there)
4281 * followed by the length of the # of data bytes. We now know this to
4282 * be "temp," although that includes the 3 bytes of vbl block header.
4283 * Deduct for them and fill in the length field.
4285 temp -= 3; /* deduct vbl block info */
4286 osi_assert(temp == (43 * returnedNames));
4287 origOp[1] = (char)(temp & 0xff);
4288 origOp[2] = (char)((temp>>8) & 0xff);
4289 if (returnedNames == 0)
4290 smb_DeleteDirSearch(dsp);
4291 smb_ReleaseDirSearch(dsp);
4292 cm_ReleaseSCache(scp);
4293 cm_ReleaseUser(userp);
4297 /* verify that this is a valid path to a directory. I don't know why they
4298 * don't use the get file attributes call.
4300 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4304 cm_scache_t *rootScp;
4305 cm_scache_t *newScp;
4314 pathp = smb_GetSMBData(inp, NULL);
4315 pathp = smb_ParseASCIIBlock(pathp, NULL);
4317 return CM_ERROR_BADFD;
4318 if (smb_StoreAnsiFilenames)
4319 OemToChar(pathp,pathp);
4320 osi_Log1(smb_logp, "SMB receive check path %s",
4321 osi_LogSaveString(smb_logp, pathp));
4323 rootScp = cm_data.rootSCachep;
4325 userp = smb_GetUserFromVCP(vcp, inp);
4327 caseFold = CM_FLAG_CASEFOLD;
4329 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4331 cm_ReleaseUser(userp);
4332 return CM_ERROR_NOSUCHPATH;
4334 code = cm_NameI(rootScp, pathp,
4335 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4336 userp, tidPathp, &req, &newScp);
4339 cm_ReleaseUser(userp);
4344 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4345 cm_ReleaseSCache(newScp);
4346 cm_ReleaseUser(userp);
4347 if ( WANTS_DFS_PATHNAMES(inp) )
4348 return CM_ERROR_PATH_NOT_COVERED;
4350 return CM_ERROR_BADSHARENAME;
4352 #endif /* DFS_SUPPORT */
4354 /* now lock the vnode with a callback; returns with newScp locked */
4355 lock_ObtainMutex(&newScp->mx);
4356 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4357 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4359 if (code != CM_ERROR_NOACCESS) {
4360 lock_ReleaseMutex(&newScp->mx);
4361 cm_ReleaseSCache(newScp);
4362 cm_ReleaseUser(userp);
4366 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4369 attrs = smb_Attributes(newScp);
4371 if (!(attrs & SMB_ATTR_DIRECTORY))
4372 code = CM_ERROR_NOTDIR;
4374 lock_ReleaseMutex(&newScp->mx);
4376 cm_ReleaseSCache(newScp);
4377 cm_ReleaseUser(userp);
4381 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4385 cm_scache_t *rootScp;
4386 unsigned short attribute;
4388 cm_scache_t *newScp;
4397 /* decode basic attributes we're passed */
4398 attribute = smb_GetSMBParm(inp, 0);
4399 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4401 pathp = smb_GetSMBData(inp, NULL);
4402 pathp = smb_ParseASCIIBlock(pathp, NULL);
4404 return CM_ERROR_BADSMB;
4405 if (smb_StoreAnsiFilenames)
4406 OemToChar(pathp,pathp);
4408 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4409 dosTime, attribute);
4411 rootScp = cm_data.rootSCachep;
4413 userp = smb_GetUserFromVCP(vcp, inp);
4415 caseFold = CM_FLAG_CASEFOLD;
4417 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4419 cm_ReleaseUser(userp);
4420 return CM_ERROR_NOSUCHFILE;
4422 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4423 tidPathp, &req, &newScp);
4426 cm_ReleaseUser(userp);
4431 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4432 cm_ReleaseSCache(newScp);
4433 cm_ReleaseUser(userp);
4434 if ( WANTS_DFS_PATHNAMES(inp) )
4435 return CM_ERROR_PATH_NOT_COVERED;
4437 return CM_ERROR_BADSHARENAME;
4439 #endif /* DFS_SUPPORT */
4441 /* now lock the vnode with a callback; returns with newScp locked; we
4442 * need the current status to determine what the new status is, in some
4445 lock_ObtainMutex(&newScp->mx);
4446 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4447 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4449 lock_ReleaseMutex(&newScp->mx);
4450 cm_ReleaseSCache(newScp);
4451 cm_ReleaseUser(userp);
4455 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4457 /* Check for RO volume */
4458 if (newScp->flags & CM_SCACHEFLAG_RO) {
4459 lock_ReleaseMutex(&newScp->mx);
4460 cm_ReleaseSCache(newScp);
4461 cm_ReleaseUser(userp);
4462 return CM_ERROR_READONLY;
4465 /* prepare for setattr call */
4468 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4469 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4471 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4472 /* we're told to make a writable file read-only */
4473 attr.unixModeBits = newScp->unixModeBits & ~0222;
4474 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4476 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4477 /* we're told to make a read-only file writable */
4478 attr.unixModeBits = newScp->unixModeBits | 0222;
4479 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4481 lock_ReleaseMutex(&newScp->mx);
4483 /* now call setattr */
4485 code = cm_SetAttr(newScp, &attr, userp, &req);
4489 cm_ReleaseSCache(newScp);
4490 cm_ReleaseUser(userp);
4495 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4499 cm_scache_t *rootScp;
4500 cm_scache_t *newScp, *dscp;
4512 pathp = smb_GetSMBData(inp, NULL);
4513 pathp = smb_ParseASCIIBlock(pathp, NULL);
4515 return CM_ERROR_BADSMB;
4517 if (*pathp == 0) /* null path */
4520 if (smb_StoreAnsiFilenames)
4521 OemToChar(pathp,pathp);
4523 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4524 osi_LogSaveString(smb_logp, pathp));
4526 rootScp = cm_data.rootSCachep;
4528 userp = smb_GetUserFromVCP(vcp, inp);
4530 /* we shouldn't need this for V3 requests, but we seem to */
4531 caseFold = CM_FLAG_CASEFOLD;
4533 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4535 cm_ReleaseUser(userp);
4536 return CM_ERROR_NOSUCHFILE;
4540 * XXX Strange hack XXX
4542 * As of Patch 5 (16 July 97), we are having the following problem:
4543 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4544 * requests to look up "desktop.ini" in all the subdirectories.
4545 * This can cause zillions of timeouts looking up non-existent cells
4546 * and volumes, especially in the top-level directory.
4548 * We have not found any way to avoid this or work around it except
4549 * to explicitly ignore the requests for mount points that haven't
4550 * yet been evaluated and for directories that haven't yet been
4553 * We should modify this hack to provide a fake desktop.ini file
4554 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4556 spacep = inp->spacep;
4557 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4558 #ifndef SPECIAL_FOLDERS
4559 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4560 code = cm_NameI(rootScp, spacep->data,
4561 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4562 userp, tidPathp, &req, &dscp);
4565 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4566 if ( WANTS_DFS_PATHNAMES(inp) )
4567 return CM_ERROR_PATH_NOT_COVERED;
4569 return CM_ERROR_BADSHARENAME;
4571 #endif /* DFS_SUPPORT */
4572 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4573 code = CM_ERROR_NOSUCHFILE;
4574 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4575 cm_buf_t *bp = buf_Find(dscp, &hzero);
4580 code = CM_ERROR_NOSUCHFILE;
4582 cm_ReleaseSCache(dscp);
4584 cm_ReleaseUser(userp);
4589 #endif /* SPECIAL_FOLDERS */
4591 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4592 tidPathp, &req, &newScp);
4594 cm_ReleaseUser(userp);
4599 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4600 cm_ReleaseSCache(newScp);
4601 cm_ReleaseUser(userp);
4602 if ( WANTS_DFS_PATHNAMES(inp) )
4603 return CM_ERROR_PATH_NOT_COVERED;
4605 return CM_ERROR_BADSHARENAME;
4607 #endif /* DFS_SUPPORT */
4609 /* now lock the vnode with a callback; returns with newScp locked */
4610 lock_ObtainMutex(&newScp->mx);
4611 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4612 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4614 lock_ReleaseMutex(&newScp->mx);
4615 cm_ReleaseSCache(newScp);
4616 cm_ReleaseUser(userp);
4620 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4623 /* use smb_Attributes instead. Also the fact that a file is
4624 * in a readonly volume doesn't mean it shojuld be marked as RO
4626 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4627 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4628 newScp->fileType == CM_SCACHETYPE_INVALID)
4629 attrs = SMB_ATTR_DIRECTORY;
4632 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4633 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4635 attrs = smb_Attributes(newScp);
4638 smb_SetSMBParm(outp, 0, attrs);
4640 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4641 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4642 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4643 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4644 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4645 smb_SetSMBParm(outp, 5, 0);
4646 smb_SetSMBParm(outp, 6, 0);
4647 smb_SetSMBParm(outp, 7, 0);
4648 smb_SetSMBParm(outp, 8, 0);
4649 smb_SetSMBParm(outp, 9, 0);
4650 smb_SetSMBDataLength(outp, 0);
4651 lock_ReleaseMutex(&newScp->mx);
4653 cm_ReleaseSCache(newScp);
4654 cm_ReleaseUser(userp);
4659 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4663 osi_Log0(smb_logp, "SMB receive tree disconnect");
4665 /* find the tree and free it */
4666 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4668 lock_ObtainWrite(&smb_rctLock);
4670 lock_ReleaseWrite(&smb_rctLock);
4671 smb_ReleaseTID(tidp);
4677 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4695 pathp = smb_GetSMBData(inp, NULL);
4696 pathp = smb_ParseASCIIBlock(pathp, NULL);
4697 if (smb_StoreAnsiFilenames)
4698 OemToChar(pathp,pathp);
4700 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4702 #ifdef DEBUG_VERBOSE
4706 hexpath = osi_HexifyString( pathp );
4707 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4712 share = smb_GetSMBParm(inp, 0);
4713 attribute = smb_GetSMBParm(inp, 1);
4715 spacep = inp->spacep;
4716 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4717 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4718 /* special case magic file name for receiving IOCTL requests
4719 * (since IOCTL calls themselves aren't getting through).
4721 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4722 smb_SetupIoctlFid(fidp, spacep);
4723 smb_SetSMBParm(outp, 0, fidp->fid);
4724 smb_SetSMBParm(outp, 1, 0); /* attrs */
4725 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4726 smb_SetSMBParm(outp, 3, 0);
4727 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4728 smb_SetSMBParm(outp, 5, 0x7fff);
4729 /* pass the open mode back */
4730 smb_SetSMBParm(outp, 6, (share & 0xf));
4731 smb_SetSMBDataLength(outp, 0);
4732 smb_ReleaseFID(fidp);
4736 userp = smb_GetUserFromVCP(vcp, inp);
4738 caseFold = CM_FLAG_CASEFOLD;
4740 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4742 cm_ReleaseUser(userp);
4743 return CM_ERROR_NOSUCHPATH;
4745 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4746 tidPathp, &req, &scp);
4749 cm_ReleaseUser(userp);
4754 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4755 cm_ReleaseSCache(scp);
4756 cm_ReleaseUser(userp);
4757 if ( WANTS_DFS_PATHNAMES(inp) )
4758 return CM_ERROR_PATH_NOT_COVERED;
4760 return CM_ERROR_BADSHARENAME;
4762 #endif /* DFS_SUPPORT */
4764 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4766 cm_ReleaseSCache(scp);
4767 cm_ReleaseUser(userp);
4771 /* don't need callback to check file type, since file types never
4772 * change, and namei and cm_Lookup all stat the object at least once on
4773 * a successful return.
4775 if (scp->fileType != CM_SCACHETYPE_FILE) {
4776 cm_ReleaseSCache(scp);
4777 cm_ReleaseUser(userp);
4778 return CM_ERROR_ISDIR;
4781 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4784 /* save a pointer to the vnode */
4786 osi_Log2(afsd_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4787 lock_ObtainMutex(&scp->mx);
4788 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4789 lock_ReleaseMutex(&scp->mx);
4793 fidp->userp = userp;
4795 lock_ObtainMutex(&fidp->mx);
4796 if ((share & 0xf) == 0)
4797 fidp->flags |= SMB_FID_OPENREAD;
4798 else if ((share & 0xf) == 1)
4799 fidp->flags |= SMB_FID_OPENWRITE;
4801 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4802 lock_ReleaseMutex(&fidp->mx);
4804 lock_ObtainMutex(&scp->mx);
4805 smb_SetSMBParm(outp, 0, fidp->fid);
4806 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4807 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4808 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4809 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4810 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4811 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4812 /* pass the open mode back; XXXX add access checks */
4813 smb_SetSMBParm(outp, 6, (share & 0xf));
4814 smb_SetSMBDataLength(outp, 0);
4815 lock_ReleaseMutex(&scp->mx);
4818 cm_Open(scp, 0, userp);
4820 /* send and free packet */
4821 smb_ReleaseFID(fidp);
4822 cm_ReleaseUser(userp);
4823 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4827 typedef struct smb_unlinkRock {
4832 char *maskp; /* pointer to the star pattern */
4837 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4840 smb_unlinkRock_t *rockp;
4848 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4849 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4850 caseFold |= CM_FLAG_8DOT3;
4852 matchName = dep->name;
4853 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4855 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4856 !cm_Is8Dot3(dep->name)) {
4857 cm_Gen8Dot3Name(dep, shortName, NULL);
4858 matchName = shortName;
4859 /* 8.3 matches are always case insensitive */
4860 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4863 osi_Log1(smb_logp, "Unlinking %s",
4864 osi_LogSaveString(smb_logp, matchName));
4865 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4866 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4867 smb_NotifyChange(FILE_ACTION_REMOVED,
4868 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4869 dscp, dep->name, NULL, TRUE);
4873 /* If we made a case sensitive exact match, we might as well quit now. */
4874 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4875 code = CM_ERROR_STOPNOW;
4883 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4892 smb_unlinkRock_t rock;
4901 attribute = smb_GetSMBParm(inp, 0);
4903 tp = smb_GetSMBData(inp, NULL);
4904 pathp = smb_ParseASCIIBlock(tp, &tp);
4905 if (smb_StoreAnsiFilenames)
4906 OemToChar(pathp,pathp);
4908 osi_Log1(smb_logp, "SMB receive unlink %s",
4909 osi_LogSaveString(smb_logp, pathp));
4911 spacep = inp->spacep;
4912 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4914 userp = smb_GetUserFromVCP(vcp, inp);
4916 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4918 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4920 cm_ReleaseUser(userp);
4921 return CM_ERROR_NOSUCHPATH;
4923 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4926 cm_ReleaseUser(userp);
4931 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4932 cm_ReleaseSCache(dscp);
4933 cm_ReleaseUser(userp);
4934 if ( WANTS_DFS_PATHNAMES(inp) )
4935 return CM_ERROR_PATH_NOT_COVERED;
4937 return CM_ERROR_BADSHARENAME;
4939 #endif /* DFS_SUPPORT */
4941 /* otherwise, scp points to the parent directory. */
4948 rock.maskp = smb_FindMask(pathp);
4949 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4952 thyper.HighPart = 0;
4958 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4959 * match. If that fails, we do a case insensitve match.
4961 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4962 !smb_IsStarMask(rock.maskp)) {
4963 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4966 thyper.HighPart = 0;
4967 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4972 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4974 if (code == CM_ERROR_STOPNOW)
4977 cm_ReleaseUser(userp);
4979 cm_ReleaseSCache(dscp);
4981 if (code == 0 && !rock.any)
4982 code = CM_ERROR_NOSUCHFILE;
4986 typedef struct smb_renameRock {
4987 cm_scache_t *odscp; /* old dir */
4988 cm_scache_t *ndscp; /* new dir */
4989 cm_user_t *userp; /* user */
4990 cm_req_t *reqp; /* request struct */
4991 smb_vc_t *vcp; /* virtual circuit */
4992 char *maskp; /* pointer to star pattern of old file name */
4993 int flags; /* tilde, casefold, etc */
4994 char *newNamep; /* ptr to the new file's name */
4997 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5000 smb_renameRock_t *rockp;
5005 rockp = (smb_renameRock_t *) vrockp;
5007 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5008 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5009 caseFold |= CM_FLAG_8DOT3;
5011 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5013 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5014 !cm_Is8Dot3(dep->name)) {
5015 cm_Gen8Dot3Name(dep, shortName, NULL);
5016 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5019 code = cm_Rename(rockp->odscp, dep->name,
5020 rockp->ndscp, rockp->newNamep, rockp->userp,
5022 /* if the call worked, stop doing the search now, since we
5023 * really only want to rename one file.
5026 code = CM_ERROR_STOPNOW;
5035 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5038 cm_space_t *spacep = NULL;
5039 smb_renameRock_t rock;
5040 cm_scache_t *oldDscp = NULL;
5041 cm_scache_t *newDscp = NULL;
5042 cm_scache_t *tmpscp= NULL;
5043 cm_scache_t *tmpscp2 = NULL;
5053 userp = smb_GetUserFromVCP(vcp, inp);
5054 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5056 cm_ReleaseUser(userp);
5057 return CM_ERROR_NOSUCHPATH;
5061 spacep = inp->spacep;
5062 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5064 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5065 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5066 userp, tidPathp, &req, &oldDscp);
5068 cm_ReleaseUser(userp);
5073 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5074 cm_ReleaseSCache(oldDscp);
5075 cm_ReleaseUser(userp);
5076 if ( WANTS_DFS_PATHNAMES(inp) )
5077 return CM_ERROR_PATH_NOT_COVERED;
5079 return CM_ERROR_BADSHARENAME;
5081 #endif /* DFS_SUPPORT */
5083 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5084 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5085 userp, tidPathp, &req, &newDscp);
5088 cm_ReleaseSCache(oldDscp);
5089 cm_ReleaseUser(userp);
5094 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5095 cm_ReleaseSCache(oldDscp);
5096 cm_ReleaseSCache(newDscp);
5097 cm_ReleaseUser(userp);
5098 if ( WANTS_DFS_PATHNAMES(inp) )
5099 return CM_ERROR_PATH_NOT_COVERED;
5101 return CM_ERROR_BADSHARENAME;
5103 #endif /* DFS_SUPPORT */
5106 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5107 * next, get the component names, and lower case them.
5110 /* handle the old name first */
5112 oldLastNamep = oldPathp;
5116 /* and handle the new name, too */
5118 newLastNamep = newPathp;
5122 /* TODO: The old name could be a wildcard. The new name must not be */
5124 /* do the vnode call */
5125 rock.odscp = oldDscp;
5126 rock.ndscp = newDscp;
5130 rock.maskp = oldLastNamep;
5131 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5132 rock.newNamep = newLastNamep;
5134 /* Check if the file already exists; if so return error */
5135 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5136 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5137 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5138 osi_LogSaveString(afsd_logp, newLastNamep));
5140 /* Check if the old and the new names differ only in case. If so return
5141 * success, else return CM_ERROR_EXISTS
5143 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5145 /* This would be a success only if the old file is *as same as* the new file */
5146 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5148 if (tmpscp == tmpscp2)
5151 code = CM_ERROR_EXISTS;
5152 cm_ReleaseSCache(tmpscp2);
5155 code = CM_ERROR_NOSUCHFILE;
5158 /* file exist, do not rename, also fixes move */
5159 osi_Log0(smb_logp, "Can't rename. Target already exists");
5160 code = CM_ERROR_EXISTS;
5164 cm_ReleaseSCache(tmpscp);
5165 cm_ReleaseSCache(newDscp);
5166 cm_ReleaseSCache(oldDscp);
5167 cm_ReleaseUser(userp);
5171 /* Now search the directory for the pattern, and do the appropriate rename when found */
5172 thyper.LowPart = 0; /* search dir from here */
5173 thyper.HighPart = 0;
5175 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5176 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5178 if (code == CM_ERROR_STOPNOW)
5181 code = CM_ERROR_NOSUCHFILE;
5183 /* Handle Change Notification */
5185 * Being lazy, not distinguishing between files and dirs in this
5186 * filter, since we'd have to do a lookup.
5188 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5189 if (oldDscp == newDscp) {
5190 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5191 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5192 filter, oldDscp, oldLastNamep,
5193 newLastNamep, TRUE);
5195 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5196 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5197 filter, oldDscp, oldLastNamep,
5199 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5200 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5201 filter, newDscp, newLastNamep,
5206 cm_ReleaseSCache(tmpscp);
5207 cm_ReleaseUser(userp);
5208 cm_ReleaseSCache(oldDscp);
5209 cm_ReleaseSCache(newDscp);
5214 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5217 cm_space_t *spacep = NULL;
5218 cm_scache_t *oldDscp = NULL;
5219 cm_scache_t *newDscp = NULL;
5220 cm_scache_t *tmpscp= NULL;
5221 cm_scache_t *tmpscp2 = NULL;
5222 cm_scache_t *sscp = NULL;
5231 userp = smb_GetUserFromVCP(vcp, inp);
5233 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5235 cm_ReleaseUser(userp);
5236 return CM_ERROR_NOSUCHPATH;
5241 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5243 spacep = inp->spacep;
5244 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5246 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5247 userp, tidPathp, &req, &oldDscp);
5249 cm_ReleaseUser(userp);
5254 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5255 cm_ReleaseSCache(oldDscp);
5256 cm_ReleaseUser(userp);
5257 if ( WANTS_DFS_PATHNAMES(inp) )
5258 return CM_ERROR_PATH_NOT_COVERED;
5260 return CM_ERROR_BADSHARENAME;
5262 #endif /* DFS_SUPPORT */
5264 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5265 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5266 userp, tidPathp, &req, &newDscp);
5268 cm_ReleaseSCache(oldDscp);
5269 cm_ReleaseUser(userp);
5274 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5275 cm_ReleaseSCache(newDscp);
5276 cm_ReleaseSCache(oldDscp);
5277 cm_ReleaseUser(userp);
5278 if ( WANTS_DFS_PATHNAMES(inp) )
5279 return CM_ERROR_PATH_NOT_COVERED;
5281 return CM_ERROR_BADSHARENAME;
5283 #endif /* DFS_SUPPORT */
5285 /* Now, although we did two lookups for the two directories (because the same
5286 * directory can be referenced through different paths), we only allow hard links
5287 * within the same directory. */
5288 if (oldDscp != newDscp) {
5289 cm_ReleaseSCache(oldDscp);
5290 cm_ReleaseSCache(newDscp);
5291 cm_ReleaseUser(userp);
5292 return CM_ERROR_CROSSDEVLINK;
5295 /* handle the old name first */
5297 oldLastNamep = oldPathp;
5301 /* and handle the new name, too */
5303 newLastNamep = newPathp;
5307 /* now lookup the old name */
5308 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5309 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5311 cm_ReleaseSCache(oldDscp);
5312 cm_ReleaseSCache(newDscp);
5313 cm_ReleaseUser(userp);
5317 /* Check if the file already exists; if so return error */
5318 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5319 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5320 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5321 osi_LogSaveString(afsd_logp, newLastNamep));
5323 /* if the existing link is to the same file, then we return success */
5325 if(sscp == tmpscp) {
5328 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5329 code = CM_ERROR_EXISTS;
5334 cm_ReleaseSCache(tmpscp);
5335 cm_ReleaseSCache(sscp);
5336 cm_ReleaseSCache(newDscp);
5337 cm_ReleaseSCache(oldDscp);
5338 cm_ReleaseUser(userp);
5342 /* now create the hardlink */
5343 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5344 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5345 osi_Log1(smb_logp," Link returns 0x%x", code);
5347 /* Handle Change Notification */
5349 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5350 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5351 smb_NotifyChange(FILE_ACTION_ADDED,
5352 filter, newDscp, newLastNamep,
5357 cm_ReleaseSCache(tmpscp);
5358 cm_ReleaseUser(userp);
5359 cm_ReleaseSCache(sscp);
5360 cm_ReleaseSCache(oldDscp);
5361 cm_ReleaseSCache(newDscp);
5366 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5372 tp = smb_GetSMBData(inp, NULL);
5373 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5374 if (smb_StoreAnsiFilenames)
5375 OemToChar(oldPathp,oldPathp);
5376 newPathp = smb_ParseASCIIBlock(tp, &tp);
5377 if (smb_StoreAnsiFilenames)
5378 OemToChar(newPathp,newPathp);
5380 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5381 osi_LogSaveString(smb_logp, oldPathp),
5382 osi_LogSaveString(smb_logp, newPathp));
5384 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5389 typedef struct smb_rmdirRock {
5393 char *maskp; /* pointer to the star pattern */
5398 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5401 smb_rmdirRock_t *rockp;
5406 rockp = (smb_rmdirRock_t *) vrockp;
5408 matchName = dep->name;
5409 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5410 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5412 match = (strcmp(matchName, rockp->maskp) == 0);
5414 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5415 !cm_Is8Dot3(dep->name)) {
5416 cm_Gen8Dot3Name(dep, shortName, NULL);
5417 matchName = shortName;
5418 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5421 osi_Log1(smb_logp, "Removing directory %s",
5422 osi_LogSaveString(smb_logp, matchName));
5423 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5424 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5425 smb_NotifyChange(FILE_ACTION_REMOVED,
5426 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5427 dscp, dep->name, NULL, TRUE);
5436 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5444 smb_rmdirRock_t rock;
5453 tp = smb_GetSMBData(inp, NULL);
5454 pathp = smb_ParseASCIIBlock(tp, &tp);
5455 if (smb_StoreAnsiFilenames)
5456 OemToChar(pathp,pathp);
5458 spacep = inp->spacep;
5459 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5461 userp = smb_GetUserFromVCP(vcp, inp);
5463 caseFold = CM_FLAG_CASEFOLD;
5465 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5467 cm_ReleaseUser(userp);
5468 return CM_ERROR_NOSUCHPATH;
5470 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5471 userp, tidPathp, &req, &dscp);
5474 cm_ReleaseUser(userp);
5479 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5480 cm_ReleaseSCache(dscp);
5481 cm_ReleaseUser(userp);
5482 if ( WANTS_DFS_PATHNAMES(inp) )
5483 return CM_ERROR_PATH_NOT_COVERED;
5485 return CM_ERROR_BADSHARENAME;
5487 #endif /* DFS_SUPPORT */
5489 /* otherwise, scp points to the parent directory. */
5496 rock.maskp = lastNamep;
5497 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5500 thyper.HighPart = 0;
5504 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5505 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5506 if (code == 0 && !rock.any) {
5508 thyper.HighPart = 0;
5509 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5510 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5513 cm_ReleaseUser(userp);
5515 cm_ReleaseSCache(dscp);
5517 if (code == 0 && !rock.any)
5518 code = CM_ERROR_NOSUCHFILE;
5522 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5532 fid = smb_GetSMBParm(inp, 0);
5534 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5536 fid = smb_ChainFID(fid, inp);
5537 fidp = smb_FindFID(vcp, fid, 0);
5539 return CM_ERROR_BADFD;
5541 lock_ObtainMutex(&fidp->mx);
5542 if (fidp->flags & SMB_FID_IOCTL) {
5543 lock_ReleaseMutex(&fidp->mx);
5544 smb_ReleaseFID(fidp);
5545 return CM_ERROR_BADFD;
5547 lock_ReleaseMutex(&fidp->mx);
5549 userp = smb_GetUserFromVCP(vcp, inp);
5551 lock_ObtainMutex(&fidp->mx);
5552 if (fidp->flags & SMB_FID_OPENWRITE) {
5553 cm_scache_t * scp = fidp->scp;
5555 lock_ReleaseMutex(&fidp->mx);
5556 code = cm_FSync(scp, userp, &req);
5557 cm_ReleaseSCache(scp);
5560 lock_ReleaseMutex(&fidp->mx);
5563 smb_ReleaseFID(fidp);
5565 cm_ReleaseUser(userp);
5570 struct smb_FullNameRock {
5576 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5580 struct smb_FullNameRock *vrockp;
5582 vrockp = (struct smb_FullNameRock *)rockp;
5584 if (!cm_Is8Dot3(dep->name)) {
5585 cm_Gen8Dot3Name(dep, shortName, NULL);
5587 if (cm_stricmp(shortName, vrockp->name) == 0) {
5588 vrockp->fullName = strdup(dep->name);
5589 return CM_ERROR_STOPNOW;
5592 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5593 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5594 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5595 vrockp->fullName = strdup(dep->name);
5596 return CM_ERROR_STOPNOW;
5601 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5602 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5604 struct smb_FullNameRock rock;
5610 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5611 if (code == CM_ERROR_STOPNOW)
5612 *newPathp = rock.fullName;
5614 *newPathp = strdup(pathp);
5617 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5618 afs_uint32 dosTime) {
5621 cm_scache_t *dscp = NULL;
5623 cm_scache_t * scp = NULL;
5625 int nullcreator = 0;
5627 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5628 fidp, fidp->fid, scp, vcp);
5631 lock_ObtainMutex(&fidp->mx);
5632 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5633 lock_ReleaseMutex(&fidp->mx);
5634 osi_Log0(smb_logp, " No user specified. Not closing fid");
5635 return CM_ERROR_BADFD;
5638 userp = fidp->userp; /* no hold required since fidp is held
5639 throughout the function */
5640 lock_ReleaseMutex(&fidp->mx);
5645 lock_ObtainWrite(&smb_rctLock);
5647 osi_Log0(smb_logp, " Fid already closed.");
5648 lock_ReleaseWrite(&smb_rctLock);
5649 return CM_ERROR_BADFD;
5652 lock_ReleaseWrite(&smb_rctLock);
5654 lock_ObtainMutex(&fidp->mx);
5655 if (fidp->NTopen_dscp) {
5656 dscp = fidp->NTopen_dscp;
5657 cm_HoldSCache(dscp);
5660 if (fidp->NTopen_pathp) {
5661 pathp = strdup(fidp->NTopen_pathp);
5669 /* Don't jump the gun on an async raw write */
5670 while (fidp->raw_writers) {
5671 lock_ReleaseMutex(&fidp->mx);
5672 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5673 lock_ObtainMutex(&fidp->mx);
5676 /* watch for ioctl closes, and read-only opens */
5678 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5679 == SMB_FID_OPENWRITE) {
5680 if (dosTime != 0 && dosTime != -1) {
5681 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5682 /* This fixes defect 10958 */
5683 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5684 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5686 lock_ReleaseMutex(&fidp->mx);
5687 code = cm_FSync(scp, userp, &req);
5688 lock_ObtainMutex(&fidp->mx);
5693 /* unlock any pending locks */
5694 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5695 scp->fileType == CM_SCACHETYPE_FILE) {
5699 lock_ReleaseMutex(&fidp->mx);
5701 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5703 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5704 lock_ObtainMutex(&scp->mx);
5706 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5707 CM_SCACHESYNC_NEEDCALLBACK
5708 | CM_SCACHESYNC_GETSTATUS
5709 | CM_SCACHESYNC_LOCK);
5713 "smb CoreClose SyncOp failure code 0x%x", tcode);
5714 goto post_syncopdone;
5717 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5719 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5723 lock_ReleaseMutex(&scp->mx);
5724 lock_ObtainMutex(&fidp->mx);
5727 if (fidp->flags & SMB_FID_DELONCLOSE) {
5730 lock_ReleaseMutex(&fidp->mx);
5731 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5732 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5733 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5736 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5737 smb_NotifyChange(FILE_ACTION_REMOVED,
5738 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5739 dscp, fullPathp, NULL, TRUE);
5742 code = cm_Unlink(dscp, fullPathp, userp, &req);
5745 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5746 smb_NotifyChange(FILE_ACTION_REMOVED,
5747 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5748 dscp, fullPathp, NULL, TRUE);
5752 lock_ObtainMutex(&fidp->mx);
5753 fidp->flags &= ~SMB_FID_DELONCLOSE;
5756 /* if this was a newly created file, then clear the creator
5757 * in the stat cache entry. */
5758 if (fidp->flags & SMB_FID_CREATED) {
5760 fidp->flags &= ~SMB_FID_CREATED;
5763 if (fidp->flags & SMB_FID_NTOPEN) {
5764 cm_ReleaseSCache(fidp->NTopen_dscp);
5765 fidp->NTopen_dscp = NULL;
5766 free(fidp->NTopen_pathp);
5767 fidp->NTopen_pathp = NULL;
5768 fidp->flags &= ~SMB_FID_NTOPEN;
5770 osi_assert(fidp->NTopen_dscp == NULL);
5771 osi_assert(fidp->NTopen_pathp == NULL);
5774 if (fidp->NTopen_wholepathp) {
5775 free(fidp->NTopen_wholepathp);
5776 fidp->NTopen_wholepathp = NULL;
5780 cm_ReleaseSCache(fidp->scp);
5783 lock_ReleaseMutex(&fidp->mx);
5786 cm_ReleaseSCache(dscp);
5789 if (deleted || nullcreator) {
5790 lock_ObtainMutex(&scp->mx);
5791 if (nullcreator && scp->creator == userp)
5792 scp->creator = NULL;
5794 scp->flags |= CM_SCACHEFLAG_DELETED;
5795 lock_ReleaseMutex(&scp->mx);
5797 lock_ObtainMutex(&scp->mx);
5798 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5799 lock_ReleaseMutex(&scp->mx);
5800 cm_ReleaseSCache(scp);
5809 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5817 fid = smb_GetSMBParm(inp, 0);
5818 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5820 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5822 fid = smb_ChainFID(fid, inp);
5823 fidp = smb_FindFID(vcp, fid, 0);
5825 return CM_ERROR_BADFD;
5828 userp = smb_GetUserFromVCP(vcp, inp);
5830 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5832 smb_ReleaseFID(fidp);
5833 cm_ReleaseUser(userp);
5838 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5840 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5841 cm_user_t *userp, long *readp)
5847 osi_hyper_t fileLength;
5849 osi_hyper_t lastByte;
5850 osi_hyper_t bufferOffset;
5851 long bufIndex, nbytes;
5853 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5861 lock_ObtainMutex(&fidp->mx);
5864 lock_ObtainMutex(&scp->mx);
5866 if (offset.HighPart == 0) {
5867 chunk = offset.LowPart >> cm_logChunkSize;
5868 if (chunk != fidp->curr_chunk) {
5869 fidp->prev_chunk = fidp->curr_chunk;
5870 fidp->curr_chunk = chunk;
5872 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5875 lock_ReleaseMutex(&fidp->mx);
5877 /* start by looking up the file's end */
5878 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5879 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5883 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5885 /* now we have the entry locked, look up the length */
5886 fileLength = scp->length;
5888 /* adjust count down so that it won't go past EOF */
5889 thyper.LowPart = count;
5890 thyper.HighPart = 0;
5891 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5893 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5894 /* we'd read past EOF, so just stop at fileLength bytes.
5895 * Start by computing how many bytes remain in the file.
5897 thyper = LargeIntegerSubtract(fileLength, offset);
5899 /* if we are past EOF, read 0 bytes */
5900 if (LargeIntegerLessThanZero(thyper))
5903 count = thyper.LowPart;
5908 /* now, copy the data one buffer at a time,
5909 * until we've filled the request packet
5912 /* if we've copied all the data requested, we're done */
5913 if (count <= 0) break;
5915 /* otherwise, load up a buffer of data */
5916 thyper.HighPart = offset.HighPart;
5917 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5918 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5921 buf_Release(bufferp);
5924 lock_ReleaseMutex(&scp->mx);
5926 lock_ObtainRead(&scp->bufCreateLock);
5927 code = buf_Get(scp, &thyper, &bufferp);
5928 lock_ReleaseRead(&scp->bufCreateLock);
5930 lock_ObtainMutex(&scp->mx);
5931 if (code) goto done;
5932 bufferOffset = thyper;
5934 /* now get the data in the cache */
5936 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5937 CM_SCACHESYNC_NEEDCALLBACK |
5938 CM_SCACHESYNC_READ);
5942 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5944 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5946 /* otherwise, load the buffer and try again */
5947 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5951 buf_Release(bufferp);
5955 } /* if (wrong buffer) ... */
5957 /* now we have the right buffer loaded. Copy out the
5958 * data from here to the user's buffer.
5960 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5962 /* and figure out how many bytes we want from this buffer */
5963 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5964 if (nbytes > count) nbytes = count; /* don't go past EOF */
5966 /* now copy the data */
5967 memcpy(op, bufferp->datap + bufIndex, nbytes);
5969 /* adjust counters, pointers, etc. */
5972 thyper.LowPart = nbytes;
5973 thyper.HighPart = 0;
5974 offset = LargeIntegerAdd(thyper, offset);
5978 lock_ReleaseMutex(&scp->mx);
5980 buf_Release(bufferp);
5982 if (code == 0 && sequential)
5983 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5985 cm_ReleaseSCache(scp);
5991 * smb_WriteData -- common code for Write and Raw Write
5993 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5994 cm_user_t *userp, long *writtenp)
6000 osi_hyper_t fileLength; /* file's length at start of write */
6001 osi_hyper_t minLength; /* don't read past this */
6002 long nbytes; /* # of bytes to transfer this iteration */
6004 osi_hyper_t thyper; /* hyper tmp variable */
6005 osi_hyper_t bufferOffset;
6006 long bufIndex; /* index in buffer where our data is */
6008 osi_hyper_t writeBackOffset;/* offset of region to write back when
6013 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6014 fidp->fid, offsetp->LowPart, count);
6024 lock_ObtainMutex(&fidp->mx);
6025 /* make sure we have a writable FD */
6026 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6027 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6028 fidp->fid, fidp->flags);
6029 lock_ReleaseMutex(&fidp->mx);
6030 code = CM_ERROR_BADFDOP;
6036 lock_ReleaseMutex(&fidp->mx);
6038 lock_ObtainMutex(&scp->mx);
6039 /* start by looking up the file's end */
6040 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6041 CM_SCACHESYNC_NEEDCALLBACK
6042 | CM_SCACHESYNC_SETSTATUS
6043 | CM_SCACHESYNC_GETSTATUS);
6047 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6049 /* now we have the entry locked, look up the length */
6050 fileLength = scp->length;
6051 minLength = fileLength;
6052 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6053 minLength = scp->serverLength;
6055 /* adjust file length if we extend past EOF */
6056 thyper.LowPart = count;
6057 thyper.HighPart = 0;
6058 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6059 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6060 /* we'd write past EOF, so extend the file */
6061 scp->mask |= CM_SCACHEMASK_LENGTH;
6062 scp->length = thyper;
6063 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6065 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6067 /* now, if the new position (thyper) and the old (offset) are in
6068 * different storeback windows, remember to store back the previous
6069 * storeback window when we're done with the write.
6071 if ((thyper.LowPart & (-cm_chunkSize)) !=
6072 (offset.LowPart & (-cm_chunkSize))) {
6073 /* they're different */
6075 writeBackOffset.HighPart = offset.HighPart;
6076 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6081 /* now, copy the data one buffer at a time, until we've filled the
6084 /* if we've copied all the data requested, we're done */
6088 /* handle over quota or out of space */
6089 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6090 *writtenp = written;
6091 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6095 /* otherwise, load up a buffer of data */
6096 thyper.HighPart = offset.HighPart;
6097 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6098 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6101 lock_ReleaseMutex(&bufferp->mx);
6102 buf_Release(bufferp);
6105 lock_ReleaseMutex(&scp->mx);
6107 lock_ObtainRead(&scp->bufCreateLock);
6108 code = buf_Get(scp, &thyper, &bufferp);
6109 lock_ReleaseRead(&scp->bufCreateLock);
6111 lock_ObtainMutex(&bufferp->mx);
6112 lock_ObtainMutex(&scp->mx);
6113 if (code) goto done;
6115 bufferOffset = thyper;
6117 /* now get the data in the cache */
6119 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6120 CM_SCACHESYNC_NEEDCALLBACK
6121 | CM_SCACHESYNC_WRITE
6122 | CM_SCACHESYNC_BUFLOCKED);
6126 cm_SyncOpDone(scp, bufferp,
6127 CM_SCACHESYNC_NEEDCALLBACK
6128 | CM_SCACHESYNC_WRITE
6129 | CM_SCACHESYNC_BUFLOCKED);
6131 /* If we're overwriting the entire buffer, or
6132 * if we're writing at or past EOF, mark the
6133 * buffer as current so we don't call
6134 * cm_GetBuffer. This skips the fetch from the
6135 * server in those cases where we're going to
6136 * obliterate all the data in the buffer anyway,
6137 * or in those cases where there is no useful
6138 * data at the server to start with.
6140 * Use minLength instead of scp->length, since
6141 * the latter has already been updated by this
6144 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6145 || LargeIntegerEqualTo(offset, bufferp->offset)
6146 && (count >= cm_data.buf_blockSize
6147 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6148 ConvertLongToLargeInteger(count)),
6150 if (count < cm_data.buf_blockSize
6151 && bufferp->dataVersion == -1)
6152 memset(bufferp->datap, 0,
6153 cm_data.buf_blockSize);
6154 bufferp->dataVersion = scp->dataVersion;
6157 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6159 /* otherwise, load the buffer and try again */
6160 lock_ReleaseMutex(&bufferp->mx);
6161 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6163 lock_ReleaseMutex(&scp->mx);
6164 lock_ObtainMutex(&bufferp->mx);
6165 lock_ObtainMutex(&scp->mx);
6169 lock_ReleaseMutex(&bufferp->mx);
6170 buf_Release(bufferp);
6174 } /* if (wrong buffer) ... */
6176 /* now we have the right buffer loaded. Copy out the
6177 * data from here to the user's buffer.
6179 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6181 /* and figure out how many bytes we want from this buffer */
6182 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6184 nbytes = count; /* don't go past end of request */
6186 /* now copy the data */
6187 memcpy(bufferp->datap + bufIndex, op, nbytes);
6188 buf_SetDirty(bufferp);
6190 /* and record the last writer */
6191 if (bufferp->userp != userp) {
6194 cm_ReleaseUser(bufferp->userp);
6195 bufferp->userp = userp;
6198 /* adjust counters, pointers, etc. */
6202 thyper.LowPart = nbytes;
6203 thyper.HighPart = 0;
6204 offset = LargeIntegerAdd(thyper, offset);
6208 lock_ReleaseMutex(&scp->mx);
6211 lock_ReleaseMutex(&bufferp->mx);
6212 buf_Release(bufferp);
6215 lock_ObtainMutex(&fidp->mx);
6216 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6217 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6218 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6219 fidp->NTopen_dscp, fidp->NTopen_pathp,
6222 lock_ReleaseMutex(&fidp->mx);
6224 if (code == 0 && doWriteBack) {
6226 lock_ObtainMutex(&scp->mx);
6227 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6229 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6230 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6232 lock_ReleaseMutex(&scp->mx);
6233 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6234 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6235 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6238 cm_ReleaseSCache(scp);
6240 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6241 fidp->fid, code, *writtenp);
6245 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6248 unsigned short count;
6250 unsigned short hint;
6251 long written = 0, total_written = 0;
6256 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6258 int inDataBlockCount;
6260 fd = smb_GetSMBParm(inp, 0);
6261 count = smb_GetSMBParm(inp, 1);
6262 offset.HighPart = 0; /* too bad */
6263 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6264 hint = smb_GetSMBParm(inp, 4);
6266 op = smb_GetSMBData(inp, NULL);
6267 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6269 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6270 fd, offset.LowPart, count);
6272 fd = smb_ChainFID(fd, inp);
6273 fidp = smb_FindFID(vcp, fd, 0);
6275 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6276 return CM_ERROR_BADFD;
6279 lock_ObtainMutex(&fidp->mx);
6280 if (fidp->flags & SMB_FID_IOCTL) {
6281 lock_ReleaseMutex(&fidp->mx);
6282 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6283 smb_ReleaseFID(fidp);
6284 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6287 lock_ReleaseMutex(&fidp->mx);
6288 userp = smb_GetUserFromVCP(vcp, inp);
6292 LARGE_INTEGER LOffset;
6293 LARGE_INTEGER LLength;
6295 pid = ((smb_t *) inp)->pid;
6296 key = cm_GenerateKey(vcp->vcID, pid, fd);
6298 LOffset.HighPart = offset.HighPart;
6299 LOffset.LowPart = offset.LowPart;
6300 LLength.HighPart = 0;
6301 LLength.LowPart = count;
6303 lock_ObtainMutex(&fidp->scp->mx);
6304 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6305 lock_ReleaseMutex(&fidp->scp->mx);
6308 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6313 /* special case: 0 bytes transferred means truncate to this position */
6317 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6321 truncAttr.mask = CM_ATTRMASK_LENGTH;
6322 truncAttr.length.LowPart = offset.LowPart;
6323 truncAttr.length.HighPart = 0;
6324 lock_ObtainMutex(&fidp->mx);
6325 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6326 fidp->flags |= SMB_FID_LENGTHSETDONE;
6327 lock_ReleaseMutex(&fidp->mx);
6328 smb_SetSMBParm(outp, 0, 0 /* count */);
6329 smb_SetSMBDataLength(outp, 0);
6334 * Work around bug in NT client
6336 * When copying a file, the NT client should first copy the data,
6337 * then copy the last write time. But sometimes the NT client does
6338 * these in the wrong order, so the data copies would inadvertently
6339 * cause the last write time to be overwritten. We try to detect this,
6340 * and don't set client mod time if we think that would go against the
6343 lock_ObtainMutex(&fidp->mx);
6344 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6345 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6346 fidp->scp->clientModTime = time(NULL);
6348 lock_ReleaseMutex(&fidp->mx);
6351 while ( code == 0 && count > 0 ) {
6352 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6353 if (code == 0 && written == 0)
6354 code = CM_ERROR_PARTIALWRITE;
6356 offset = LargeIntegerAdd(offset,
6357 ConvertLongToLargeInteger(written));
6359 total_written += written;
6363 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6364 total_written, code);
6366 /* set the packet data length to 3 bytes for the data block header,
6367 * plus the size of the data.
6369 smb_SetSMBParm(outp, 0, total_written);
6370 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6371 smb_SetSMBParm(outp, 3, hint);
6372 smb_SetSMBDataLength(outp, 0);
6375 smb_ReleaseFID(fidp);
6376 cm_ReleaseUser(userp);
6381 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6382 NCB *ncbp, raw_write_cont_t *rwcp)
6391 fd = smb_GetSMBParm(inp, 0);
6392 fidp = smb_FindFID(vcp, fd, 0);
6394 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6395 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6397 userp = smb_GetUserFromVCP(vcp, inp);
6400 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6402 if (rwcp->writeMode & 0x1) { /* synchronous */
6405 smb_FormatResponsePacket(vcp, inp, outp);
6406 op = (smb_t *) outp;
6407 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6408 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6409 smb_SetSMBDataLength(outp, 0);
6410 smb_SendPacket(vcp, outp);
6411 smb_FreePacket(outp);
6413 else { /* asynchronous */
6414 lock_ObtainMutex(&fidp->mx);
6415 fidp->raw_writers--;
6416 if (fidp->raw_writers == 0)
6417 thrd_SetEvent(fidp->raw_write_event);
6418 lock_ReleaseMutex(&fidp->mx);
6421 /* Give back raw buffer */
6422 lock_ObtainMutex(&smb_RawBufLock);
6423 *((char **)rawBuf) = smb_RawBufs;
6424 smb_RawBufs = rawBuf;
6425 lock_ReleaseMutex(&smb_RawBufLock);
6427 smb_ReleaseFID(fidp);
6428 cm_ReleaseUser(userp);
6431 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6436 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6439 long count, written = 0, total_written = 0;
6446 unsigned short writeMode;
6448 fd = smb_GetSMBParm(inp, 0);
6449 totalCount = smb_GetSMBParm(inp, 1);
6450 count = smb_GetSMBParm(inp, 10);
6451 writeMode = smb_GetSMBParm(inp, 7);
6453 op = (char *) inp->data;
6454 op += smb_GetSMBParm(inp, 11);
6456 offset.HighPart = 0;
6457 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6459 if (*inp->wctp == 14) {
6460 /* we received a 64-bit file offset */
6461 #ifdef AFS_LARGEFILES
6462 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6464 if (LargeIntegerLessThanZero(offset)) {
6466 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6467 offset.HighPart, offset.LowPart);
6468 return CM_ERROR_BADSMB;
6471 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6473 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6474 return CM_ERROR_BADSMB;
6477 offset.HighPart = 0;
6480 offset.HighPart = 0; /* 32-bit file offset */
6484 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6485 fd, offset.HighPart, offset.LowPart, count);
6487 " WriteRaw WriteMode 0x%x",
6490 fd = smb_ChainFID(fd, inp);
6491 fidp = smb_FindFID(vcp, fd, 0);
6493 return CM_ERROR_BADFD;
6499 LARGE_INTEGER LOffset;
6500 LARGE_INTEGER LLength;
6502 pid = ((smb_t *) inp)->pid;
6503 key = cm_GenerateKey(vcp->vcID, pid, fd);
6505 LOffset.HighPart = offset.HighPart;
6506 LOffset.LowPart = offset.LowPart;
6507 LLength.HighPart = 0;
6508 LLength.LowPart = count;
6510 lock_ObtainMutex(&fidp->scp->mx);
6511 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6512 lock_ReleaseMutex(&fidp->scp->mx);
6515 smb_ReleaseFID(fidp);
6520 userp = smb_GetUserFromVCP(vcp, inp);
6523 * Work around bug in NT client
6525 * When copying a file, the NT client should first copy the data,
6526 * then copy the last write time. But sometimes the NT client does
6527 * these in the wrong order, so the data copies would inadvertently
6528 * cause the last write time to be overwritten. We try to detect this,
6529 * and don't set client mod time if we think that would go against the
6532 lock_ObtainMutex(&fidp->mx);
6533 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6534 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6535 fidp->scp->clientModTime = time(NULL);
6537 lock_ReleaseMutex(&fidp->mx);
6540 while ( code == 0 && count > 0 ) {
6541 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6542 if (code == 0 && written == 0)
6543 code = CM_ERROR_PARTIALWRITE;
6545 offset = LargeIntegerAdd(offset,
6546 ConvertLongToLargeInteger(written));
6549 total_written += written;
6553 /* Get a raw buffer */
6556 lock_ObtainMutex(&smb_RawBufLock);
6558 /* Get a raw buf, from head of list */
6559 rawBuf = smb_RawBufs;
6560 smb_RawBufs = *(char **)smb_RawBufs;
6563 code = CM_ERROR_USESTD;
6565 lock_ReleaseMutex(&smb_RawBufLock);
6568 /* Don't allow a premature Close */
6569 if (code == 0 && (writeMode & 1) == 0) {
6570 lock_ObtainMutex(&fidp->mx);
6571 fidp->raw_writers++;
6572 thrd_ResetEvent(fidp->raw_write_event);
6573 lock_ReleaseMutex(&fidp->mx);
6576 smb_ReleaseFID(fidp);
6577 cm_ReleaseUser(userp);
6580 smb_SetSMBParm(outp, 0, total_written);
6581 smb_SetSMBDataLength(outp, 0);
6582 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6587 offset = LargeIntegerAdd(offset,
6588 ConvertLongToLargeInteger(count));
6592 rwcp->offset.HighPart = offset.HighPart;
6593 rwcp->offset.LowPart = offset.LowPart;
6594 rwcp->count = totalCount - count;
6595 rwcp->writeMode = writeMode;
6596 rwcp->alreadyWritten = total_written;
6598 /* set the packet data length to 3 bytes for the data block header,
6599 * plus the size of the data.
6601 smb_SetSMBParm(outp, 0, 0xffff);
6602 smb_SetSMBDataLength(outp, 0);
6607 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6610 long count, finalCount;
6618 fd = smb_GetSMBParm(inp, 0);
6619 count = smb_GetSMBParm(inp, 1);
6620 offset.HighPart = 0; /* too bad */
6621 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6623 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6624 fd, offset.LowPart, count);
6626 fd = smb_ChainFID(fd, inp);
6627 fidp = smb_FindFID(vcp, fd, 0);
6629 return CM_ERROR_BADFD;
6631 lock_ObtainMutex(&fidp->mx);
6632 if (fidp->flags & SMB_FID_IOCTL) {
6633 lock_ReleaseMutex(&fidp->mx);
6634 code = smb_IoctlRead(fidp, vcp, inp, outp);
6635 smb_ReleaseFID(fidp);
6638 lock_ReleaseMutex(&fidp->mx);
6641 LARGE_INTEGER LOffset, LLength;
6644 pid = ((smb_t *) inp)->pid;
6645 key = cm_GenerateKey(vcp->vcID, pid, fd);
6647 LOffset.HighPart = 0;
6648 LOffset.LowPart = offset.LowPart;
6649 LLength.HighPart = 0;
6650 LLength.LowPart = count;
6652 lock_ObtainMutex(&fidp->scp->mx);
6653 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6654 lock_ReleaseMutex(&fidp->scp->mx);
6657 smb_ReleaseFID(fidp);
6661 userp = smb_GetUserFromVCP(vcp, inp);
6663 /* remember this for final results */
6664 smb_SetSMBParm(outp, 0, count);
6665 smb_SetSMBParm(outp, 1, 0);
6666 smb_SetSMBParm(outp, 2, 0);
6667 smb_SetSMBParm(outp, 3, 0);
6668 smb_SetSMBParm(outp, 4, 0);
6670 /* set the packet data length to 3 bytes for the data block header,
6671 * plus the size of the data.
6673 smb_SetSMBDataLength(outp, count+3);
6675 /* get op ptr after putting in the parms, since otherwise we don't
6676 * know where the data really is.
6678 op = smb_GetSMBData(outp, NULL);
6680 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6681 *op++ = 1; /* data block marker */
6682 *op++ = (unsigned char) (count & 0xff);
6683 *op++ = (unsigned char) ((count >> 8) & 0xff);
6685 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6687 /* fix some things up */
6688 smb_SetSMBParm(outp, 0, finalCount);
6689 smb_SetSMBDataLength(outp, finalCount+3);
6691 smb_ReleaseFID(fidp);
6693 cm_ReleaseUser(userp);
6697 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6704 cm_scache_t *dscp; /* dir we're dealing with */
6705 cm_scache_t *scp; /* file we're creating */
6707 int initialModeBits;
6717 /* compute initial mode bits based on read-only flag in attributes */
6718 initialModeBits = 0777;
6720 tp = smb_GetSMBData(inp, NULL);
6721 pathp = smb_ParseASCIIBlock(tp, &tp);
6722 if (smb_StoreAnsiFilenames)
6723 OemToChar(pathp,pathp);
6725 if (strcmp(pathp, "\\") == 0)
6726 return CM_ERROR_EXISTS;
6728 spacep = inp->spacep;
6729 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6731 userp = smb_GetUserFromVCP(vcp, inp);
6733 caseFold = CM_FLAG_CASEFOLD;
6735 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6737 cm_ReleaseUser(userp);
6738 return CM_ERROR_NOSUCHPATH;
6741 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6742 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6743 userp, tidPathp, &req, &dscp);
6746 cm_ReleaseUser(userp);
6751 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6752 cm_ReleaseSCache(dscp);
6753 cm_ReleaseUser(userp);
6754 if ( WANTS_DFS_PATHNAMES(inp) )
6755 return CM_ERROR_PATH_NOT_COVERED;
6757 return CM_ERROR_BADSHARENAME;
6759 #endif /* DFS_SUPPORT */
6761 /* otherwise, scp points to the parent directory. Do a lookup, and
6762 * fail if we find it. Otherwise, we do the create.
6768 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6769 if (scp) cm_ReleaseSCache(scp);
6770 if (code != CM_ERROR_NOSUCHFILE) {
6771 if (code == 0) code = CM_ERROR_EXISTS;
6772 cm_ReleaseSCache(dscp);
6773 cm_ReleaseUser(userp);
6777 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6778 setAttr.clientModTime = time(NULL);
6779 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6780 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6781 smb_NotifyChange(FILE_ACTION_ADDED,
6782 FILE_NOTIFY_CHANGE_DIR_NAME,
6783 dscp, lastNamep, NULL, TRUE);
6785 /* we don't need this any longer */
6786 cm_ReleaseSCache(dscp);
6789 /* something went wrong creating or truncating the file */
6790 cm_ReleaseUser(userp);
6794 /* otherwise we succeeded */
6795 smb_SetSMBDataLength(outp, 0);
6796 cm_ReleaseUser(userp);
6801 BOOL smb_IsLegalFilename(char *filename)
6804 * Find the longest substring of filename that does not contain
6805 * any of the chars in illegalChars. If that substring is less
6806 * than the length of the whole string, then one or more of the
6807 * illegal chars is in filename.
6809 if (strcspn(filename, illegalChars) < strlen(filename))
6815 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6823 cm_scache_t *dscp; /* dir we're dealing with */
6824 cm_scache_t *scp; /* file we're creating */
6826 int initialModeBits;
6834 int created = 0; /* the file was new */
6839 excl = (inp->inCom == 0x03)? 0 : 1;
6841 attributes = smb_GetSMBParm(inp, 0);
6842 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6844 /* compute initial mode bits based on read-only flag in attributes */
6845 initialModeBits = 0666;
6846 if (attributes & SMB_ATTR_READONLY)
6847 initialModeBits &= ~0222;
6849 tp = smb_GetSMBData(inp, NULL);
6850 pathp = smb_ParseASCIIBlock(tp, &tp);
6851 if (smb_StoreAnsiFilenames)
6852 OemToChar(pathp,pathp);
6854 spacep = inp->spacep;
6855 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6857 userp = smb_GetUserFromVCP(vcp, inp);
6859 caseFold = CM_FLAG_CASEFOLD;
6861 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6863 cm_ReleaseUser(userp);
6864 return CM_ERROR_NOSUCHPATH;
6866 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6867 userp, tidPathp, &req, &dscp);
6870 cm_ReleaseUser(userp);
6875 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6876 cm_ReleaseSCache(dscp);
6877 cm_ReleaseUser(userp);
6878 if ( WANTS_DFS_PATHNAMES(inp) )
6879 return CM_ERROR_PATH_NOT_COVERED;
6881 return CM_ERROR_BADSHARENAME;
6883 #endif /* DFS_SUPPORT */
6885 /* otherwise, scp points to the parent directory. Do a lookup, and
6886 * truncate the file if we find it, otherwise we create the file.
6893 if (!smb_IsLegalFilename(lastNamep))
6894 return CM_ERROR_BADNTFILENAME;
6896 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6897 #ifdef DEBUG_VERBOSE
6900 hexp = osi_HexifyString( lastNamep );
6901 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6906 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6907 if (code && code != CM_ERROR_NOSUCHFILE) {
6908 cm_ReleaseSCache(dscp);
6909 cm_ReleaseUser(userp);
6913 /* if we get here, if code is 0, the file exists and is represented by
6914 * scp. Otherwise, we have to create it.
6918 /* oops, file shouldn't be there */
6919 cm_ReleaseSCache(dscp);
6920 cm_ReleaseSCache(scp);
6921 cm_ReleaseUser(userp);
6922 return CM_ERROR_EXISTS;
6925 setAttr.mask = CM_ATTRMASK_LENGTH;
6926 setAttr.length.LowPart = 0;
6927 setAttr.length.HighPart = 0;
6928 code = cm_SetAttr(scp, &setAttr, userp, &req);
6931 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6932 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6933 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6937 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6938 smb_NotifyChange(FILE_ACTION_ADDED,
6939 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6940 dscp, lastNamep, NULL, TRUE);
6941 } else if (!excl && code == CM_ERROR_EXISTS) {
6942 /* not an exclusive create, and someone else tried
6943 * creating it already, then we open it anyway. We
6944 * don't bother retrying after this, since if this next
6945 * fails, that means that the file was deleted after
6946 * we started this call.
6948 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6951 setAttr.mask = CM_ATTRMASK_LENGTH;
6952 setAttr.length.LowPart = 0;
6953 setAttr.length.HighPart = 0;
6954 code = cm_SetAttr(scp, &setAttr, userp, &req);
6959 /* we don't need this any longer */
6960 cm_ReleaseSCache(dscp);
6963 /* something went wrong creating or truncating the file */
6964 if (scp) cm_ReleaseSCache(scp);
6965 cm_ReleaseUser(userp);
6969 /* make sure we only open files */
6970 if (scp->fileType != CM_SCACHETYPE_FILE) {
6971 cm_ReleaseSCache(scp);
6972 cm_ReleaseUser(userp);
6973 return CM_ERROR_ISDIR;
6976 /* now all we have to do is open the file itself */
6977 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6982 lock_ObtainMutex(&fidp->mx);
6983 /* always create it open for read/write */
6984 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6986 /* remember that the file was newly created */
6988 fidp->flags |= SMB_FID_CREATED;
6990 osi_Log2(afsd_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
6992 /* save a pointer to the vnode */
6994 lock_ObtainMutex(&scp->mx);
6995 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6996 lock_ReleaseMutex(&scp->mx);
6999 fidp->userp = userp;
7000 lock_ReleaseMutex(&fidp->mx);
7002 smb_SetSMBParm(outp, 0, fidp->fid);
7003 smb_SetSMBDataLength(outp, 0);
7005 cm_Open(scp, 0, userp);
7007 smb_ReleaseFID(fidp);
7008 cm_ReleaseUser(userp);
7009 /* leave scp held since we put it in fidp->scp */
7013 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7016 osi_hyper_t new_offset;
7027 fd = smb_GetSMBParm(inp, 0);
7028 whence = smb_GetSMBParm(inp, 1);
7029 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7031 /* try to find the file descriptor */
7032 fd = smb_ChainFID(fd, inp);
7033 fidp = smb_FindFID(vcp, fd, 0);
7036 return CM_ERROR_BADFD;
7038 lock_ObtainMutex(&fidp->mx);
7039 if (fidp->flags & SMB_FID_IOCTL) {
7040 lock_ReleaseMutex(&fidp->mx);
7041 smb_ReleaseFID(fidp);
7042 return CM_ERROR_BADFD;
7044 lock_ReleaseMutex(&fidp->mx);
7046 userp = smb_GetUserFromVCP(vcp, inp);
7048 lock_ObtainMutex(&fidp->mx);
7051 lock_ReleaseMutex(&fidp->mx);
7052 lock_ObtainMutex(&scp->mx);
7053 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7054 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7056 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7058 /* offset from current offset */
7059 new_offset = LargeIntegerAdd(fidp->offset,
7060 ConvertLongToLargeInteger(offset));
7062 else if (whence == 2) {
7063 /* offset from current EOF */
7064 new_offset = LargeIntegerAdd(scp->length,
7065 ConvertLongToLargeInteger(offset));
7067 new_offset = ConvertLongToLargeInteger(offset);
7070 fidp->offset = new_offset;
7071 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7072 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7073 smb_SetSMBDataLength(outp, 0);
7075 lock_ReleaseMutex(&scp->mx);
7076 smb_ReleaseFID(fidp);
7077 cm_ReleaseSCache(scp);
7078 cm_ReleaseUser(userp);
7082 /* dispatch all of the requests received in a packet. Due to chaining, this may
7083 * be more than one request.
7085 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7086 NCB *ncbp, raw_write_cont_t *rwcp)
7090 unsigned long code = 0;
7091 unsigned char *outWctp;
7092 int nparms; /* # of bytes of parameters */
7094 int nbytes; /* bytes of data, excluding count */
7097 unsigned short errCode;
7098 unsigned long NTStatus;
7100 unsigned char errClass;
7101 unsigned int oldGen;
7102 DWORD oldTime, newTime;
7104 /* get easy pointer to the data */
7105 smbp = (smb_t *) inp->data;
7107 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7108 /* setup the basic parms for the initial request in the packet */
7109 inp->inCom = smbp->com;
7110 inp->wctp = &smbp->wct;
7112 inp->ncb_length = ncbp->ncb_length;
7117 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7118 /* log it and discard it */
7119 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7120 __FILE__, __LINE__, ncbp->ncb_length);
7121 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7125 /* We are an ongoing op */
7126 thrd_Increment(&ongoingOps);
7128 /* set up response packet for receiving output */
7129 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7130 smb_FormatResponsePacket(vcp, inp, outp);
7131 outWctp = outp->wctp;
7133 /* Remember session generation number and time */
7134 oldGen = sessionGen;
7135 oldTime = GetTickCount();
7137 while (inp->inCom != 0xff) {
7138 dp = &smb_dispatchTable[inp->inCom];
7140 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7141 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7142 code = outp->resumeCode;
7146 /* process each request in the packet; inCom, wctp and inCount
7147 * are already set up.
7149 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7152 /* now do the dispatch */
7153 /* start by formatting the response record a little, as a default */
7154 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7156 outWctp[1] = 0xff; /* no operation */
7157 outWctp[2] = 0; /* padding */
7162 /* not a chained request, this is a more reasonable default */
7163 outWctp[0] = 0; /* wct of zero */
7164 outWctp[1] = 0; /* and bcc (word) of zero */
7168 /* once set, stays set. Doesn't matter, since we never chain
7169 * "no response" calls.
7171 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7175 /* we have a recognized operation */
7177 if (inp->inCom == 0x1d)
7179 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7181 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7182 code = (*(dp->procp)) (vcp, inp, outp);
7183 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7185 if ( code == CM_ERROR_BADSMB ||
7186 code == CM_ERROR_BADOP )
7188 #endif /* LOG_PACKET */
7191 if (oldGen != sessionGen) {
7192 newTime = GetTickCount();
7193 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7194 newTime - oldTime, ncbp->ncb_length);
7195 osi_Log2(smb_logp, "Pkt straddled session startup, "
7196 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7200 /* bad opcode, fail the request, after displaying it */
7201 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7204 #endif /* LOG_PACKET */
7207 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7208 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7209 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7210 if (code == IDCANCEL)
7213 code = CM_ERROR_BADOP;
7216 /* catastrophic failure: log as much as possible */
7217 if (code == CM_ERROR_BADSMB) {
7218 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7222 #endif /* LOG_PACKET */
7223 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7226 code = CM_ERROR_INVAL;
7229 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7230 thrd_Decrement(&ongoingOps);
7235 /* now, if we failed, turn the current response into an empty
7236 * one, and fill in the response packet's error code.
7239 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7240 smb_MapNTError(code, &NTStatus);
7241 outWctp = outp->wctp;
7242 smbp = (smb_t *) &outp->data;
7243 if (code != CM_ERROR_PARTIALWRITE
7244 && code != CM_ERROR_BUFFERTOOSMALL
7245 && code != CM_ERROR_GSSCONTINUE) {
7246 /* nuke wct and bcc. For a partial
7247 * write or an in-process authentication handshake,
7248 * assume they're OK.
7254 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7255 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7256 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7257 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7258 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7262 smb_MapCoreError(code, vcp, &errCode, &errClass);
7263 outWctp = outp->wctp;
7264 smbp = (smb_t *) &outp->data;
7265 if (code != CM_ERROR_PARTIALWRITE) {
7266 /* nuke wct and bcc. For a partial
7267 * write, assume they're OK.
7273 smbp->errLow = (unsigned char) (errCode & 0xff);
7274 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7275 smbp->rcls = errClass;
7278 } /* error occurred */
7280 /* if we're here, we've finished one request. Look to see if
7281 * this is a chained opcode. If it is, setup things to process
7282 * the chained request, and setup the output buffer to hold the
7283 * chained response. Start by finding the next input record.
7285 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7286 break; /* not a chained req */
7287 tp = inp->wctp; /* points to start of last request */
7288 /* in a chained request, the first two
7289 * parm fields are required, and are
7290 * AndXCommand/AndXReserved and
7292 if (tp[0] < 2) break;
7293 if (tp[1] == 0xff) break; /* no more chained opcodes */
7295 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7298 /* and now append the next output request to the end of this
7299 * last request. Begin by finding out where the last response
7300 * ends, since that's where we'll put our new response.
7302 outWctp = outp->wctp; /* ptr to out parameters */
7303 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7304 nparms = outWctp[0] << 1;
7305 tp = outWctp + nparms + 1; /* now points to bcc field */
7306 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7307 tp += 2 /* for the count itself */ + nbytes;
7308 /* tp now points to the new output record; go back and patch the
7309 * second parameter (off2) to point to the new record.
7311 temp = (unsigned int)(tp - outp->data);
7312 outWctp[3] = (unsigned char) (temp & 0xff);
7313 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7314 outWctp[2] = 0; /* padding */
7315 outWctp[1] = inp->inCom; /* next opcode */
7317 /* finally, setup for the next iteration */
7320 } /* while loop over all requests in the packet */
7322 /* now send the output packet, and return */
7324 smb_SendPacket(vcp, outp);
7325 thrd_Decrement(&ongoingOps);
7330 /* Wait for Netbios() calls to return, and make the results available to server
7331 * threads. Note that server threads can't wait on the NCBevents array
7332 * themselves, because NCB events are manual-reset, and the servers would race
7333 * each other to reset them.
7335 void smb_ClientWaiter(void *parmp)
7340 while (smbShutdownFlag == 0) {
7341 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7343 if (code == WAIT_OBJECT_0)
7346 /* error checking */
7347 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7349 int abandonIdx = code - WAIT_ABANDONED_0;
7350 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7353 if (code == WAIT_IO_COMPLETION)
7355 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7359 if (code == WAIT_TIMEOUT)
7361 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7364 if (code == WAIT_FAILED)
7366 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7369 idx = code - WAIT_OBJECT_0;
7371 /* check idx range! */
7372 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7374 /* this is fatal - log as much as possible */
7375 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7379 thrd_ResetEvent(NCBevents[idx]);
7380 thrd_SetEvent(NCBreturns[0][idx]);
7385 * Try to have one NCBRECV request waiting for every live session. Not more
7386 * than one, because if there is more than one, it's hard to handle Write Raw.
7388 void smb_ServerWaiter(void *parmp)
7391 int idx_session, idx_NCB;
7394 while (smbShutdownFlag == 0) {
7396 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7398 if (code == WAIT_OBJECT_0)
7401 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7403 int abandonIdx = code - WAIT_ABANDONED_0;
7404 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7407 if (code == WAIT_IO_COMPLETION)
7409 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7413 if (code == WAIT_TIMEOUT)
7415 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7418 if (code == WAIT_FAILED)
7420 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7423 idx_session = code - WAIT_OBJECT_0;
7425 /* check idx range! */
7426 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7428 /* this is fatal - log as much as possible */
7429 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7435 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7437 if (code == WAIT_OBJECT_0) {
7438 if (smbShutdownFlag == 1)
7444 /* error checking */
7445 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7447 int abandonIdx = code - WAIT_ABANDONED_0;
7448 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7451 if (code == WAIT_IO_COMPLETION)
7453 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7457 if (code == WAIT_TIMEOUT)
7459 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7462 if (code == WAIT_FAILED)
7464 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7467 idx_NCB = code - WAIT_OBJECT_0;
7469 /* check idx range! */
7470 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7472 /* this is fatal - log as much as possible */
7473 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7477 /* Link them together */
7478 NCBsessions[idx_NCB] = idx_session;
7481 ncbp = NCBs[idx_NCB];
7482 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7483 ncbp->ncb_command = NCBRECV | ASYNCH;
7484 ncbp->ncb_lana_num = lanas[idx_session];
7485 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7486 ncbp->ncb_event = NCBevents[idx_NCB];
7487 ncbp->ncb_length = SMB_PACKETSIZE;
7493 * The top level loop for handling SMB request messages. Each server thread
7494 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7495 * NCB and buffer for the incoming request are loaned to us.
7497 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7498 * to immediately send a request for the rest of the data. This must come
7499 * before any other traffic for that session, so we delay setting the session
7500 * event until that data has come in.
7502 void smb_Server(VOID *parmp)
7504 INT_PTR myIdx = (INT_PTR) parmp;
7508 smb_packet_t *outbufp;
7510 int idx_NCB, idx_session;
7512 smb_vc_t *vcp = NULL;
7515 rx_StartClientThread();
7518 outbufp = GetPacket();
7519 outbufp->ncbp = outncbp;
7527 smb_ResetServerPriority();
7529 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7532 /* terminate silently if shutdown flag is set */
7533 if (code == WAIT_OBJECT_0) {
7534 if (smbShutdownFlag == 1) {
7535 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7541 /* error checking */
7542 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7544 int abandonIdx = code - WAIT_ABANDONED_0;
7545 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7548 if (code == WAIT_IO_COMPLETION)
7550 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7554 if (code == WAIT_TIMEOUT)
7556 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7559 if (code == WAIT_FAILED)
7561 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7564 idx_NCB = code - WAIT_OBJECT_0;
7566 /* check idx range! */
7567 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7569 /* this is fatal - log as much as possible */
7570 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7574 ncbp = NCBs[idx_NCB];
7575 idx_session = NCBsessions[idx_NCB];
7576 rc = ncbp->ncb_retcode;
7578 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7579 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7583 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7587 /* Can this happen? Or is it just my UNIX paranoia? */
7588 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7593 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7596 /* Client closed session */
7597 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7599 lock_ObtainMutex(&vcp->mx);
7600 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7601 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7603 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7604 lock_ReleaseMutex(&vcp->mx);
7605 lock_ObtainWrite(&smb_globalLock);
7606 dead_sessions[vcp->session] = TRUE;
7607 lock_ReleaseWrite(&smb_globalLock);
7608 smb_CleanupDeadVC(vcp);
7612 lock_ReleaseMutex(&vcp->mx);
7618 /* Treat as transient error */
7619 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7622 "dispatch smb recv failed, message incomplete, ncb_length %d",
7625 "SMB message incomplete, "
7626 "length %d", ncbp->ncb_length);
7629 * We used to discard the packet.
7630 * Instead, try handling it normally.
7634 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7638 /* A weird error code. Log it, sleep, and continue. */
7639 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7641 lock_ObtainMutex(&vcp->mx);
7642 if (vcp && vcp->errorCount++ > 3) {
7643 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7644 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7645 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7647 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7648 lock_ReleaseMutex(&vcp->mx);
7649 lock_ObtainWrite(&smb_globalLock);
7650 dead_sessions[vcp->session] = TRUE;
7651 lock_ReleaseWrite(&smb_globalLock);
7652 smb_CleanupDeadVC(vcp);
7656 lock_ReleaseMutex(&vcp->mx);
7662 lock_ReleaseMutex(&vcp->mx);
7664 thrd_SetEvent(SessionEvents[idx_session]);
7669 /* Success, so now dispatch on all the data in the packet */
7671 smb_concurrentCalls++;
7672 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7673 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7676 * If at this point vcp is NULL (implies that packet was invalid)
7677 * then we are in big trouble. This means either :
7678 * a) we have the wrong NCB.
7679 * b) Netbios screwed up the call.
7680 * c) The VC was already marked dead before we were able to
7682 * Obviously this implies that
7683 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7684 * lanas[idx_session] != ncbp->ncb_lana_num )
7685 * Either way, we can't do anything with this packet.
7686 * Log, sleep and resume.
7689 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7693 ncbp->ncb_lana_num);
7695 /* Also log in the trace log. */
7696 osi_Log4(smb_logp, "Server: VCP does not exist!"
7697 "LSNs[idx_session]=[%d],"
7698 "lanas[idx_session]=[%d],"
7699 "ncbp->ncb_lsn=[%d],"
7700 "ncbp->ncb_lana_num=[%d]",
7704 ncbp->ncb_lana_num);
7706 /* thrd_Sleep(1000); Don't bother sleeping */
7707 thrd_SetEvent(SessionEvents[idx_session]);
7708 smb_concurrentCalls--;
7712 smb_SetRequestStartTime();
7714 vcp->errorCount = 0;
7715 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7716 smbp = (smb_t *)bufp->data;
7721 if (smbp->com == 0x1d) {
7722 /* Special handling for Write Raw */
7723 raw_write_cont_t rwc;
7724 EVENT_HANDLE rwevent;
7725 char eventName[MAX_PATH];
7727 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7728 if (rwc.code == 0) {
7729 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7730 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7731 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7732 ncbp->ncb_command = NCBRECV | ASYNCH;
7733 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7734 ncbp->ncb_lana_num = vcp->lana;
7735 ncbp->ncb_buffer = rwc.buf;
7736 ncbp->ncb_length = 65535;
7737 ncbp->ncb_event = rwevent;
7739 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7740 thrd_CloseHandle(rwevent);
7742 thrd_SetEvent(SessionEvents[idx_session]);
7744 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7746 else if (smbp->com == 0xa0) {
7748 * Serialize the handling for NT Transact
7751 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7752 thrd_SetEvent(SessionEvents[idx_session]);
7754 thrd_SetEvent(SessionEvents[idx_session]);
7755 /* TODO: what else needs to be serialized? */
7756 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7759 __except( smb_ServerExceptionFilter() ) {
7762 smb_concurrentCalls--;
7765 thrd_SetEvent(NCBavails[idx_NCB]);
7772 * Exception filter for the server threads. If an exception occurs in the
7773 * dispatch routines, which is where exceptions are most common, then do a
7774 * force trace and give control to upstream exception handlers. Useful for
7777 DWORD smb_ServerExceptionFilter(void) {
7778 /* While this is not the best time to do a trace, if it succeeds, then
7779 * we have a trace (assuming tracing was enabled). Otherwise, this should
7780 * throw a second exception.
7782 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7783 afsd_ForceTrace(TRUE);
7784 buf_ForceTrace(TRUE);
7785 return EXCEPTION_CONTINUE_SEARCH;
7789 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7790 * If the number of server threads is M, and the number of live sessions is
7791 * N, then the number of NCB's in use at any time either waiting for, or
7792 * holding, received messages is M + N, so that is how many NCB's get created.
7794 void InitNCBslot(int idx)
7796 struct smb_packet *bufp;
7797 EVENT_HANDLE retHandle;
7799 char eventName[MAX_PATH];
7801 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7803 NCBs[idx] = GetNCB();
7804 sprintf(eventName,"NCBavails[%d]", idx);
7805 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7806 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7807 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7808 sprintf(eventName,"NCBevents[%d]", idx);
7809 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7810 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7811 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7812 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7813 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7814 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7815 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7816 for (i=0; i<smb_NumServerThreads; i++)
7817 NCBreturns[i][idx] = retHandle;
7819 bufp->spacep = cm_GetSpace();
7823 /* listen for new connections */
7824 void smb_Listener(void *parmp)
7830 int session, thread;
7831 smb_vc_t *vcp = NULL;
7833 char rname[NCBNAMSZ+1];
7834 char cname[MAX_COMPUTERNAME_LENGTH+1];
7835 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7836 INT_PTR lana = (INT_PTR) parmp;
7840 /* retrieve computer name */
7841 GetComputerName(cname, &cnamelen);
7845 memset(ncbp, 0, sizeof(NCB));
7848 ncbp->ncb_command = NCBLISTEN;
7849 ncbp->ncb_rto = 0; /* No receive timeout */
7850 ncbp->ncb_sto = 0; /* No send timeout */
7852 /* pad out with spaces instead of null termination */
7853 len = (long)strlen(smb_localNamep);
7854 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7855 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7857 strcpy(ncbp->ncb_callname, "*");
7858 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7860 ncbp->ncb_lana_num = (UCHAR)lana;
7862 code = Netbios(ncbp);
7868 /* terminate silently if shutdown flag is set */
7869 if (smbShutdownFlag == 1) {
7874 "NCBLISTEN lana=%d failed with code %d",
7875 ncbp->ncb_lana_num, code);
7877 "Client exiting due to network failure. Please restart client.\n");
7880 "Client exiting due to network failure. Please restart client.\n"
7881 "NCBLISTEN lana=%d failed with code %d",
7882 ncbp->ncb_lana_num, code);
7884 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7885 MB_OK|MB_SERVICE_NOTIFICATION);
7886 osi_panic(tbuffer, __FILE__, __LINE__);
7889 /* check for remote conns */
7890 /* first get remote name and insert null terminator */
7891 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7892 for (i=NCBNAMSZ; i>0; i--) {
7893 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7899 /* compare with local name */
7901 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7902 flags |= SMB_VCFLAG_REMOTECONN;
7905 lock_ObtainMutex(&smb_ListenerLock);
7907 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7908 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7910 /* now ncbp->ncb_lsn is the connection ID */
7911 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7912 if (vcp->session == 0) {
7913 /* New generation */
7914 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7917 /* Log session startup */
7919 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7920 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7921 #endif /* NOTSERVICE */
7922 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7923 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7925 if (reportSessionStartups) {
7926 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7929 lock_ObtainMutex(&vcp->mx);
7930 strcpy(vcp->rname, rname);
7931 vcp->flags |= flags;
7932 lock_ReleaseMutex(&vcp->mx);
7934 /* Allocate slot in session arrays */
7935 /* Re-use dead session if possible, otherwise add one more */
7936 /* But don't look at session[0], it is reserved */
7937 lock_ObtainWrite(&smb_globalLock);
7938 for (session = 1; session < numSessions; session++) {
7939 if (dead_sessions[session]) {
7940 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
7941 dead_sessions[session] = FALSE;
7945 lock_ReleaseWrite(&smb_globalLock);
7947 /* We are re-using an existing VC because the lsn and lana
7949 session = vcp->session;
7951 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
7953 /* Log session startup */
7955 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7956 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7957 #endif /* NOTSERVICE */
7958 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7959 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7961 if (reportSessionStartups) {
7962 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7966 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
7967 unsigned long code = CM_ERROR_ALLBUSY;
7968 smb_packet_t * outp = GetPacket();
7969 unsigned char *outWctp;
7972 smb_FormatResponsePacket(vcp, NULL, outp);
7975 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7976 unsigned long NTStatus;
7977 smb_MapNTError(code, &NTStatus);
7978 outWctp = outp->wctp;
7979 smbp = (smb_t *) &outp->data;
7983 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7984 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7985 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7986 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7987 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7989 unsigned short errCode;
7990 unsigned char errClass;
7991 smb_MapCoreError(code, vcp, &errCode, &errClass);
7992 outWctp = outp->wctp;
7993 smbp = (smb_t *) &outp->data;
7997 smbp->errLow = (unsigned char) (errCode & 0xff);
7998 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7999 smbp->rcls = errClass;
8001 smb_SendPacket(vcp, outp);
8002 smb_FreePacket(outp);
8004 lock_ObtainMutex(&vcp->mx);
8005 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8006 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8008 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8009 lock_ReleaseMutex(&vcp->mx);
8010 lock_ObtainWrite(&smb_globalLock);
8011 dead_sessions[vcp->session] = TRUE;
8012 lock_ReleaseWrite(&smb_globalLock);
8013 smb_CleanupDeadVC(vcp);
8015 lock_ReleaseMutex(&vcp->mx);
8018 /* assert that we do not exceed the maximum number of sessions or NCBs.
8019 * we should probably want to wait for a session to be freed in case
8022 osi_assert(session < SESSION_MAX - 1);
8023 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8025 lock_ObtainMutex(&vcp->mx);
8026 vcp->session = session;
8027 lock_ReleaseMutex(&vcp->mx);
8028 lock_ObtainWrite(&smb_globalLock);
8029 LSNs[session] = ncbp->ncb_lsn;
8030 lanas[session] = ncbp->ncb_lana_num;
8031 lock_ReleaseWrite(&smb_globalLock);
8033 if (session == numSessions) {
8034 /* Add new NCB for new session */
8035 char eventName[MAX_PATH];
8037 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8039 InitNCBslot(numNCBs);
8040 lock_ObtainWrite(&smb_globalLock);
8042 lock_ReleaseWrite(&smb_globalLock);
8043 thrd_SetEvent(NCBavails[0]);
8044 thrd_SetEvent(NCBevents[0]);
8045 for (thread = 0; thread < smb_NumServerThreads; thread++)
8046 thrd_SetEvent(NCBreturns[thread][0]);
8047 /* Also add new session event */
8048 sprintf(eventName, "SessionEvents[%d]", session);
8049 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8050 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8051 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8052 lock_ObtainWrite(&smb_globalLock);
8054 lock_ReleaseWrite(&smb_globalLock);
8055 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8056 thrd_SetEvent(SessionEvents[0]);
8058 thrd_SetEvent(SessionEvents[session]);
8064 lock_ReleaseMutex(&smb_ListenerLock);
8065 } /* dispatch while loop */
8068 /* initialize Netbios */
8069 void smb_NetbiosInit()
8072 int i, lana, code, l;
8074 int delname_tried=0;
8077 OSVERSIONINFO Version;
8079 /* Get the version of Windows */
8080 memset(&Version, 0x00, sizeof(Version));
8081 Version.dwOSVersionInfoSize = sizeof(Version);
8082 GetVersionEx(&Version);
8084 /* setup the NCB system */
8087 if (smb_LANadapter == -1) {
8088 ncbp->ncb_command = NCBENUM;
8089 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8090 ncbp->ncb_length = sizeof(lana_list);
8091 code = Netbios(ncbp);
8093 afsi_log("Netbios NCBENUM error code %d", code);
8094 osi_panic(s, __FILE__, __LINE__);
8098 lana_list.length = 1;
8099 lana_list.lana[0] = smb_LANadapter;
8102 for (i = 0; i < lana_list.length; i++) {
8103 /* reset the adaptor: in Win32, this is required for every process, and
8104 * acts as an init call, not as a real hardware reset.
8106 ncbp->ncb_command = NCBRESET;
8107 ncbp->ncb_callname[0] = 100;
8108 ncbp->ncb_callname[2] = 100;
8109 ncbp->ncb_lana_num = lana_list.lana[i];
8110 code = Netbios(ncbp);
8112 code = ncbp->ncb_retcode;
8114 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8115 lana_list.lana[i] = 255; /* invalid lana */
8117 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8121 /* and declare our name so we can receive connections */
8122 memset(ncbp, 0, sizeof(*ncbp));
8123 len=lstrlen(smb_localNamep);
8124 memset(smb_sharename,' ',NCBNAMSZ);
8125 memcpy(smb_sharename,smb_localNamep,len);
8126 afsi_log("lana_list.length %d", lana_list.length);
8128 /* Keep the name so we can unregister it later */
8129 for (l = 0; l < lana_list.length; l++) {
8130 lana = lana_list.lana[l];
8132 ncbp->ncb_command = NCBADDNAME;
8133 ncbp->ncb_lana_num = lana;
8134 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8135 code = Netbios(ncbp);
8137 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8138 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8140 char name[NCBNAMSZ+1];
8142 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8143 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8146 if (code == 0) code = ncbp->ncb_retcode;
8148 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8151 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8152 if (code == NRC_BRIDGE) { /* invalid LANA num */
8153 lana_list.lana[l] = 255;
8156 else if (code == NRC_DUPNAME) {
8157 afsi_log("Name already exists; try to delete it");
8158 memset(ncbp, 0, sizeof(*ncbp));
8159 ncbp->ncb_command = NCBDELNAME;
8160 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8161 ncbp->ncb_lana_num = lana;
8162 code = Netbios(ncbp);
8164 code = ncbp->ncb_retcode;
8166 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8168 if (code != 0 || delname_tried) {
8169 lana_list.lana[l] = 255;
8171 else if (code == 0) {
8172 if (!delname_tried) {
8180 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8181 lana_list.lana[l] = 255; /* invalid lana */
8182 osi_panic(s, __FILE__, __LINE__);
8186 lana_found = 1; /* at least one worked */
8190 osi_assert(lana_list.length >= 0);
8192 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8195 /* we're done with the NCB now */
8199 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8210 EVENT_HANDLE retHandle;
8211 char eventName[MAX_PATH];
8213 smb_TlsRequestSlot = TlsAlloc();
8215 smb_MBfunc = aMBfunc;
8218 smb_LANadapter = LANadapt;
8220 /* Initialize smb_localZero */
8221 myTime.tm_isdst = -1; /* compute whether on DST or not */
8222 myTime.tm_year = 70;
8228 smb_localZero = mktime(&myTime);
8230 #ifndef USE_NUMERIC_TIME_CONV
8231 /* Initialize kludge-GMT */
8232 smb_CalculateNowTZ();
8233 #endif /* USE_NUMERIC_TIME_CONV */
8234 #ifdef AFS_FREELANCE_CLIENT
8235 /* Make sure the root.afs volume has the correct time */
8236 cm_noteLocalMountPointChange();
8239 /* initialize the remote debugging log */
8242 /* remember the name */
8243 len = (int)strlen(snamep);
8244 smb_localNamep = malloc(len+1);
8245 strcpy(smb_localNamep, snamep);
8246 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8248 /* and the global lock */
8249 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8250 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8252 /* Raw I/O data structures */
8253 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8255 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8257 /* 4 Raw I/O buffers */
8258 smb_RawBufs = calloc(65536,1);
8259 *((char **)smb_RawBufs) = NULL;
8260 for (i=0; i<3; i++) {
8261 char *rawBuf = calloc(65536,1);
8262 *((char **)rawBuf) = smb_RawBufs;
8263 smb_RawBufs = rawBuf;
8266 /* global free lists */
8267 smb_ncbFreeListp = NULL;
8268 smb_packetFreeListp = NULL;
8272 /* Initialize listener and server structures */
8274 memset(dead_sessions, 0, sizeof(dead_sessions));
8275 sprintf(eventName, "SessionEvents[0]");
8276 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8277 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8278 afsi_log("Event Object Already Exists: %s", eventName);
8280 smb_NumServerThreads = nThreads;
8281 sprintf(eventName, "NCBavails[0]");
8282 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8283 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8284 afsi_log("Event Object Already Exists: %s", eventName);
8285 sprintf(eventName, "NCBevents[0]");
8286 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8287 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8288 afsi_log("Event Object Already Exists: %s", eventName);
8289 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8290 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8291 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8292 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8293 afsi_log("Event Object Already Exists: %s", eventName);
8294 for (i = 0; i < smb_NumServerThreads; i++) {
8295 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8296 NCBreturns[i][0] = retHandle;
8299 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8300 for (i = 0; i < smb_NumServerThreads; i++) {
8301 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8302 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8303 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8304 afsi_log("Event Object Already Exists: %s", eventName);
8305 InitNCBslot((int)(i+1));
8307 numNCBs = smb_NumServerThreads + 1;
8309 /* Initialize dispatch table */
8310 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8311 /* Prepare the table for unknown operations */
8312 for(i=0; i<= SMB_NOPCODES; i++) {
8313 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8315 /* Fill in the ones we do know */
8316 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8317 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8318 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8319 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8320 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8321 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8322 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8323 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8324 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8325 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8326 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8327 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8328 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8329 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8330 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8331 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8332 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8333 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8334 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8335 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8336 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8337 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8338 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8339 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8340 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8341 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8342 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8343 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8344 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8345 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8346 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8347 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8348 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8349 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8350 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8351 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8352 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8353 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8354 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8355 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8356 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8357 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8358 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8359 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8360 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8361 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8362 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8363 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8364 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8365 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8366 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8367 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8368 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8369 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8370 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8371 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8372 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8373 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8374 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8375 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8376 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8377 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8378 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8379 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8380 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8381 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8382 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8383 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8384 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8385 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8386 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8387 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8388 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8389 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8391 /* setup tran 2 dispatch table */
8392 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8393 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8394 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8395 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8396 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8397 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8398 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8399 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8400 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8401 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8402 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8403 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8404 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8405 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8406 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8407 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8408 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8409 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8411 /* setup the rap dispatch table */
8412 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8413 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8414 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8415 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8416 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8420 /* if we are doing SMB authentication we have register outselves as a logon process */
8421 if (smb_authType != SMB_AUTH_NONE) {
8422 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8423 LSA_STRING afsProcessName;
8424 LSA_OPERATIONAL_MODE dummy; /*junk*/
8426 afsProcessName.Buffer = "OpenAFSClientDaemon";
8427 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8428 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8430 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8432 if (nts == STATUS_SUCCESS) {
8433 LSA_STRING packageName;
8434 /* we are registered. Find out the security package id */
8435 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8436 packageName.Length = (USHORT)strlen(packageName.Buffer);
8437 packageName.MaximumLength = packageName.Length + 1;
8438 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8439 if (nts == STATUS_SUCCESS) {
8441 * This code forces Windows to authenticate against the Logon Cache
8442 * first instead of attempting to authenticate against the Domain
8443 * Controller. When the Windows logon cache is enabled this improves
8444 * performance by removing the network access and works around a bug
8445 * seen at sites which are using a MIT Kerberos principal to login
8446 * to machines joined to a non-root domain in a multi-domain forest.
8448 PVOID pResponse = NULL;
8449 ULONG cbResponse = 0;
8450 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8452 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8453 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8454 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8455 OptionsRequest.DisableOptions = FALSE;
8457 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8460 sizeof(OptionsRequest),
8466 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8468 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8470 OutputDebugString(message);
8473 OutputDebugString("MsV1_0SetProcessOption success");
8474 afsi_log("MsV1_0SetProcessOption success");
8476 /* END - code from Larry */
8478 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8479 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8480 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8482 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8484 /* something went wrong. We report the error and revert back to no authentication
8485 because we can't perform any auth requests without a successful lsa handle
8486 or sec package id. */
8487 afsi_log("Reverting to NO SMB AUTH");
8488 smb_authType = SMB_AUTH_NONE;
8491 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8493 /* something went wrong. We report the error and revert back to no authentication
8494 because we can't perform any auth requests without a successful lsa handle
8495 or sec package id. */
8496 afsi_log("Reverting to NO SMB AUTH");
8497 smb_authType = SMB_AUTH_NONE;
8501 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8502 * time prevents the failure of authentication when logged into Windows with an
8503 * external Kerberos principal mapped to a local account.
8505 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8506 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8507 * then the only option is NTLMSSP anyway; so just fallback.
8512 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8513 if (secBlobLength == 0) {
8514 smb_authType = SMB_AUTH_NTLM;
8515 afsi_log("Reverting to SMB AUTH NTLM");
8524 /* Now get ourselves a domain name. */
8525 /* For now we are using the local computer name as the domain name.
8526 * It is actually the domain for local logins, and we are acting as
8527 * a local SMB server.
8529 bufsize = sizeof(smb_ServerDomainName) - 1;
8530 GetComputerName(smb_ServerDomainName, &bufsize);
8531 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8532 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8535 /* Start listeners, waiters, servers, and daemons */
8537 for (i = 0; i < lana_list.length; i++) {
8538 if (lana_list.lana[i] == 255)
8540 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8541 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8542 osi_assert(phandle != NULL);
8543 thrd_CloseHandle(phandle);
8546 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8547 NULL, 0, &lpid, "smb_ClientWaiter");
8548 osi_assert(phandle != NULL);
8549 thrd_CloseHandle(phandle);
8551 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8552 NULL, 0, &lpid, "smb_ServerWaiter");
8553 osi_assert(phandle != NULL);
8554 thrd_CloseHandle(phandle);
8556 for (i=0; i<smb_NumServerThreads; i++) {
8557 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8558 (void *) i, 0, &lpid, "smb_Server");
8559 osi_assert(phandle != NULL);
8560 thrd_CloseHandle(phandle);
8563 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8564 NULL, 0, &lpid, "smb_Daemon");
8565 osi_assert(phandle != NULL);
8566 thrd_CloseHandle(phandle);
8568 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8569 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8570 osi_assert(phandle != NULL);
8571 thrd_CloseHandle(phandle);
8576 void smb_Shutdown(void)
8583 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8585 /* setup the NCB system */
8588 /* Block new sessions by setting shutdown flag */
8589 smbShutdownFlag = 1;
8591 /* Hang up all sessions */
8592 memset((char *)ncbp, 0, sizeof(NCB));
8593 for (i = 1; i < numSessions; i++)
8595 if (dead_sessions[i])
8598 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8599 ncbp->ncb_command = NCBHANGUP;
8600 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8601 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8602 code = Netbios(ncbp);
8603 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8604 if (code == 0) code = ncbp->ncb_retcode;
8606 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8607 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8611 /* Trigger the shutdown of all SMB threads */
8612 for (i = 0; i < smb_NumServerThreads; i++)
8613 thrd_SetEvent(NCBreturns[i][0]);
8615 thrd_SetEvent(NCBevents[0]);
8616 thrd_SetEvent(SessionEvents[0]);
8617 thrd_SetEvent(NCBavails[0]);
8619 for (i = 0;i < smb_NumServerThreads; i++) {
8620 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8621 if (code == WAIT_OBJECT_0) {
8624 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8625 thrd_SetEvent(NCBreturns[i--][0]);
8629 /* Delete Netbios name */
8630 memset((char *)ncbp, 0, sizeof(NCB));
8631 for (i = 0; i < lana_list.length; i++) {
8632 if (lana_list.lana[i] == 255) continue;
8633 ncbp->ncb_command = NCBDELNAME;
8634 ncbp->ncb_lana_num = lana_list.lana[i];
8635 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8636 code = Netbios(ncbp);
8638 code = ncbp->ncb_retcode;
8640 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8641 ncbp->ncb_lana_num, code);
8646 /* Release the reference counts held by the VCs */
8647 lock_ObtainWrite(&smb_rctLock);
8648 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8653 if (vcp->magic != SMB_VC_MAGIC)
8654 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8655 __FILE__, __LINE__);
8657 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8659 if (fidp->scp != NULL) {
8662 lock_ObtainMutex(&fidp->mx);
8663 if (fidp->scp != NULL) {
8666 lock_ObtainMutex(&scp->mx);
8667 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8668 lock_ReleaseMutex(&scp->mx);
8669 osi_Log2(afsd_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8670 cm_ReleaseSCache(scp);
8672 lock_ReleaseMutex(&fidp->mx);
8676 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8678 smb_ReleaseVCNoLock(tidp->vcp);
8680 cm_user_t *userp = tidp->userp;
8682 lock_ReleaseWrite(&smb_rctLock);
8683 cm_ReleaseUser(userp);
8684 lock_ObtainWrite(&smb_rctLock);
8688 lock_ReleaseWrite(&smb_rctLock);
8690 TlsFree(smb_TlsRequestSlot);
8693 /* Get the UNC \\<servername>\<sharename> prefix. */
8694 char *smb_GetSharename()
8698 /* Make sure we have been properly initialized. */
8699 if (smb_localNamep == NULL)
8702 /* Allocate space for \\<servername>\<sharename>, plus the
8705 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8706 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8712 void smb_LogPacket(smb_packet_t *packet)
8715 unsigned length, paramlen, datalen, i, j;
8717 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8719 if (!packet) return;
8721 osi_Log0(smb_logp, "*** SMB packet dump ***");
8723 vp = (BYTE *) packet->data;
8725 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8726 length = paramlen + 2 + datalen;
8729 for (i=0;i < length; i+=16)
8731 memset( buf, ' ', 80 );
8736 buf[strlen(buf)] = ' ';
8738 cp = (BYTE*) buf + 7;
8740 for (j=0;j < 16 && (i+j)<length; j++)
8742 *(cp++) = hex[vp[i+j] >> 4];
8743 *(cp++) = hex[vp[i+j] & 0xf];
8753 for (j=0;j < 16 && (i+j)<length;j++)
8755 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8766 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8769 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8771 #endif /* LOG_PACKET */
8774 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8782 lock_ObtainRead(&smb_rctLock);
8784 sprintf(output, "begin dumping smb_vc_t\n");
8785 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8787 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8791 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8792 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8793 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8795 sprintf(output, "begin dumping smb_fid_t\n");
8796 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8798 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8800 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",
8801 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8802 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8803 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8804 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8807 sprintf(output, "done dumping smb_fid_t\n");
8808 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8811 sprintf(output, "done dumping smb_vc_t\n");
8812 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8814 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8815 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8817 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8821 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8822 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8823 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8825 sprintf(output, "begin dumping smb_fid_t\n");
8826 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8828 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8830 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",
8831 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8832 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8833 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8834 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8837 sprintf(output, "done dumping smb_fid_t\n");
8838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8841 sprintf(output, "done dumping DEAD smb_vc_t\n");
8842 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8844 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8845 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8847 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8851 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8852 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8853 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8855 sprintf(output, "begin dumping smb_fid_t\n");
8856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8858 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8860 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",
8861 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8862 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8863 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8864 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8867 sprintf(output, "done dumping smb_fid_t\n");
8868 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8871 sprintf(output, "done dumping DEAD smb_vc_t\n");
8872 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8875 lock_ReleaseRead(&smb_rctLock);