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>
17 #include <sys/timeb.h>
30 #include <rx/rx_prototypes.h>
31 #include <WINNT\afsreg.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
39 int smbShutdownFlag = 0;
41 int smb_LogoffTokenTransfer;
42 time_t smb_LogoffTransferTimeout;
44 int smb_StoreAnsiFilenames = 0;
46 DWORD last_msg_time = 0;
50 unsigned int sessionGen = 0;
52 extern void afsi_log(char *pattern, ...);
53 extern HANDLE afsi_file;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
64 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
67 long smb_maxObsConcurrentCalls=0;
68 long smb_concurrentCalls=0;
70 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
72 smb_packet_t *smb_packetFreeListp;
73 smb_ncb_t *smb_ncbFreeListp;
75 int smb_NumServerThreads;
77 int numNCBs, numSessions, numVCs;
79 int smb_maxVCPerServer;
80 int smb_maxMpxRequests;
82 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
84 ULONG smb_lsaSecPackage;
85 LSA_STRING smb_lsaLogonOrigin;
87 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
88 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
89 EVENT_HANDLE **NCBreturns;
90 EVENT_HANDLE **NCBShutdown;
91 EVENT_HANDLE *smb_ServerShutdown;
92 DWORD NCBsessions[NCB_MAX];
94 struct smb_packet *bufs[NCB_MAX];
96 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
97 EVENT_HANDLE SessionEvents[SESSION_MAX];
98 unsigned short LSNs[SESSION_MAX];
99 int lanas[SESSION_MAX];
100 BOOL dead_sessions[SESSION_MAX];
104 osi_mutex_t smb_RawBufLock;
106 #define SMB_RAW_BUFS 4
108 int smb_RawBufSel[SMB_RAW_BUFS];
113 #define SMB_MASKFLAG_TILDE 1
114 #define SMB_MASKFLAG_CASEFOLD 2
116 #define RAWTIMEOUT INFINITE
119 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* global state about V3 protocols */
141 int smb_useV3; /* try to negotiate V3 */
144 static showErrors = 1;
145 /* MessageBox or something like it */
146 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
150 * Time in Unix format of midnight, 1/1/1970 local time.
151 * When added to dosUTime, gives Unix (AFS) time.
153 time_t smb_localZero = 0;
155 #define USE_NUMERIC_TIME_CONV 1
157 #ifndef USE_NUMERIC_TIME_CONV
158 /* Time difference for converting to kludge-GMT */
159 afs_uint32 smb_NowTZ;
160 #endif /* USE_NUMERIC_TIME_CONV */
162 char *smb_localNamep = NULL;
164 smb_vc_t *smb_allVCsp;
165 smb_vc_t *smb_deadVCsp;
167 smb_username_t *usernamesp = NULL;
169 smb_waitingLockRequest_t *smb_allWaitingLocks;
171 DWORD smb_TlsRequestSlot = -1;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
182 extern char cm_HostName[];
183 extern char cm_confDir[];
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189 strcpy((str), cm_HostName); \
190 *(sizep) = strlen(cm_HostName)
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
197 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
198 int smb_ServerDomainNameLength = 0;
199 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
200 int smb_ServerOSLength = sizeof(smb_ServerOS);
201 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
202 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
204 /* Faux server GUID. This is never checked. */
205 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
207 void smb_ResetServerPriority()
209 void * p = TlsGetValue(smb_TlsRequestSlot);
212 TlsSetValue(smb_TlsRequestSlot, NULL);
213 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
217 void smb_SetRequestStartTime()
219 time_t * tp = malloc(sizeof(time_t));
223 if (!TlsSetValue(smb_TlsRequestSlot, tp))
228 void smb_UpdateServerPriority()
230 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
233 time_t now = osi_Time();
235 /* Give one priority boost for each 15 seconds */
236 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
241 const char * ncb_error_string(int code)
245 case 0x01: s = "llegal buffer length"; break;
246 case 0x03: s = "illegal command"; break;
247 case 0x05: s = "command timed out"; break;
248 case 0x06: s = "message incomplete, issue another command"; break;
249 case 0x07: s = "illegal buffer address"; break;
250 case 0x08: s = "session number out of range"; break;
251 case 0x09: s = "no resource available"; break;
252 case 0x0a: s = "session closed"; break;
253 case 0x0b: s = "command cancelled"; break;
254 case 0x0d: s = "duplicate name"; break;
255 case 0x0e: s = "name table full"; break;
256 case 0x0f: s = "no deletions, name has active sessions"; break;
257 case 0x11: s = "local session table full"; break;
258 case 0x12: s = "remote session table full"; break;
259 case 0x13: s = "illegal name number"; break;
260 case 0x14: s = "no callname"; break;
261 case 0x15: s = "cannot put * in NCB_NAME"; break;
262 case 0x16: s = "name in use on remote adapter"; break;
263 case 0x17: s = "name deleted"; break;
264 case 0x18: s = "session ended abnormally"; break;
265 case 0x19: s = "name conflict detected"; break;
266 case 0x21: s = "interface busy, IRET before retrying"; break;
267 case 0x22: s = "too many commands outstanding, retry later";break;
268 case 0x23: s = "ncb_lana_num field invalid"; break;
269 case 0x24: s = "command completed while cancel occurring "; break;
270 case 0x26: s = "command not valid to cancel"; break;
271 case 0x30: s = "name defined by anther local process"; break;
272 case 0x34: s = "environment undefined. RESET required"; break;
273 case 0x35: s = "required OS resources exhausted"; break;
274 case 0x36: s = "max number of applications exceeded"; break;
275 case 0x37: s = "no saps available for netbios"; break;
276 case 0x38: s = "requested resources are not available"; break;
277 case 0x39: s = "invalid ncb address or length > segment"; break;
278 case 0x3B: s = "invalid NCB DDID"; break;
279 case 0x3C: s = "lock of user area failed"; break;
280 case 0x3f: s = "NETBIOS not loaded"; break;
281 case 0x40: s = "system error"; break;
282 default: s = "unknown error";
288 char * myCrt_Dispatch(int i)
293 return "(00)ReceiveCoreMakeDir";
295 return "(01)ReceiveCoreRemoveDir";
297 return "(02)ReceiveCoreOpen";
299 return "(03)ReceiveCoreCreate";
301 return "(04)ReceiveCoreClose";
303 return "(05)ReceiveCoreFlush";
305 return "(06)ReceiveCoreUnlink";
307 return "(07)ReceiveCoreRename";
309 return "(08)ReceiveCoreGetFileAttributes";
311 return "(09)ReceiveCoreSetFileAttributes";
313 return "(0a)ReceiveCoreRead";
315 return "(0b)ReceiveCoreWrite";
317 return "(0c)ReceiveCoreLockRecord";
319 return "(0d)ReceiveCoreUnlockRecord";
321 return "(0e)SendCoreBadOp";
323 return "(0f)ReceiveCoreCreate";
325 return "(10)ReceiveCoreCheckPath";
327 return "(11)SendCoreBadOp";
329 return "(12)ReceiveCoreSeek";
331 return "(1a)ReceiveCoreReadRaw";
333 return "(1d)ReceiveCoreWriteRawDummy";
335 return "(22)ReceiveV3SetAttributes";
337 return "(23)ReceiveV3GetAttributes";
339 return "(24)ReceiveV3LockingX";
341 return "(25)ReceiveV3Trans";
343 return "(26)ReceiveV3Trans[aux]";
345 return "(29)SendCoreBadOp";
347 return "(2b)ReceiveCoreEcho";
349 return "(2d)ReceiveV3OpenX";
351 return "(2e)ReceiveV3ReadX";
353 return "(2f)ReceiveV3WriteX";
355 return "(32)ReceiveV3Tran2A";
357 return "(33)ReceiveV3Tran2A[aux]";
359 return "(34)ReceiveV3FindClose";
361 return "(35)ReceiveV3FindNotifyClose";
363 return "(70)ReceiveCoreTreeConnect";
365 return "(71)ReceiveCoreTreeDisconnect";
367 return "(72)ReceiveNegotiate";
369 return "(73)ReceiveV3SessionSetupX";
371 return "(74)ReceiveV3UserLogoffX";
373 return "(75)ReceiveV3TreeConnectX";
375 return "(80)ReceiveCoreGetDiskAttributes";
377 return "(81)ReceiveCoreSearchDir";
381 return "(83)FindUnique";
383 return "(84)FindClose";
385 return "(A0)ReceiveNTTransact";
387 return "(A2)ReceiveNTCreateX";
389 return "(A4)ReceiveNTCancel";
391 return "(A5)ReceiveNTRename";
393 return "(C0)OpenPrintFile";
395 return "(C1)WritePrintFile";
397 return "(C2)ClosePrintFile";
399 return "(C3)GetPrintQueue";
401 return "(D8)ReadBulk";
403 return "(D9)WriteBulk";
405 return "(DA)WriteBulkData";
407 return "unknown SMB op";
411 char * myCrt_2Dispatch(int i)
416 return "unknown SMB op-2";
418 return "S(00)CreateFile_ReceiveTran2Open";
420 return "S(01)FindFirst_ReceiveTran2SearchDir";
422 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
424 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
426 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
428 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
430 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
432 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
434 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
436 return "S(09)_ReceiveTran2FSCTL";
438 return "S(0a)_ReceiveTran2IOCTL";
440 return "S(0b)_ReceiveTran2FindNotifyFirst";
442 return "S(0c)_ReceiveTran2FindNotifyNext";
444 return "S(0d)_ReceiveTran2CreateDirectory";
446 return "S(0e)_ReceiveTran2SessionSetup";
448 return "S(0f)_QueryFileSystemInformationFid";
450 return "S(10)_ReceiveTran2GetDfsReferral";
452 return "S(11)_ReceiveTran2ReportDfsInconsistency";
456 char * myCrt_RapDispatch(int i)
461 return "unknown RAP OP";
463 return "RAP(0)NetShareEnum";
465 return "RAP(1)NetShareGetInfo";
467 return "RAP(13)NetServerGetInfo";
469 return "RAP(63)NetWkStaGetInfo";
473 /* scache must be locked */
474 unsigned int smb_Attributes(cm_scache_t *scp)
478 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
479 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
480 scp->fileType == CM_SCACHETYPE_INVALID)
482 attrs = SMB_ATTR_DIRECTORY;
483 #ifdef SPECIAL_FOLDERS
484 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
485 #endif /* SPECIAL_FOLDERS */
486 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
487 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
492 * We used to mark a file RO if it was in an RO volume, but that
493 * turns out to be impolitic in NT. See defect 10007.
496 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
497 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
499 if ((scp->unixModeBits & 0222) == 0)
500 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
506 /* Check if the named file/dir is a dotfile/dotdir */
507 /* String pointed to by lastComp can have leading slashes, but otherwise should have
508 no other patch components */
509 unsigned int smb_IsDotFile(char *lastComp) {
512 /* skip over slashes */
513 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
518 /* nulls, curdir and parent dir doesn't count */
524 if(*(s+1) == '.' && !*(s + 2))
531 static int ExtractBits(WORD bits, short start, short len)
538 num = bits << (16 - end);
539 num = num >> ((16 - end) + start);
545 void ShowUnixTime(char *FuncName, time_t unixTime)
550 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
552 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
553 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
555 int day, month, year, sec, min, hour;
558 day = ExtractBits(wDate, 0, 5);
559 month = ExtractBits(wDate, 5, 4);
560 year = ExtractBits(wDate, 9, 7) + 1980;
562 sec = ExtractBits(wTime, 0, 5);
563 min = ExtractBits(wTime, 5, 6);
564 hour = ExtractBits(wTime, 11, 5);
566 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
567 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
573 /* Determine if we are observing daylight savings time */
574 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
576 TIME_ZONE_INFORMATION timeZoneInformation;
577 SYSTEMTIME utc, local, localDST;
579 /* Get the time zone info. NT uses this to calc if we are in DST. */
580 GetTimeZoneInformation(&timeZoneInformation);
582 /* Return the daylight bias */
583 *pDstBias = timeZoneInformation.DaylightBias;
585 /* Return the bias */
586 *pBias = timeZoneInformation.Bias;
588 /* Now determine if DST is being observed */
590 /* Get the UTC (GMT) time */
593 /* Convert UTC time to local time using the time zone info. If we are
594 observing DST, the calculated local time will include this.
596 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
598 /* Set the daylight bias to 0. The daylight bias is the amount of change
599 * in time that we use for daylight savings time. By setting this to 0
600 * we cause there to be no change in time during daylight savings time.
602 timeZoneInformation.DaylightBias = 0;
604 /* Convert the utc time to local time again, but this time without any
605 adjustment for daylight savings time.
607 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
609 /* If the two times are different, then it means that the localDST that
610 we calculated includes the daylight bias, and therefore we are
611 observing daylight savings time.
613 *pDST = localDST.wHour != local.wHour;
616 /* Determine if we are observing daylight savings time */
617 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
623 *pDstBias = -60; /* where can this be different? */
629 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
631 BOOL dst; /* Will be TRUE if observing DST */
632 LONG dstBias; /* Offset from local time if observing DST */
633 LONG bias; /* Offset from GMT for local time */
636 * This function will adjust the last write time to compensate
637 * for two bugs in the smb client:
639 * 1) During Daylight Savings Time, the LastWriteTime is ahead
640 * in time by the DaylightBias (ignoring the sign - the
641 * DaylightBias is always stored as a negative number). If
642 * the DaylightBias is -60, then the LastWriteTime will be
643 * ahead by 60 minutes.
645 * 2) If the local time zone is a positive offset from GMT, then
646 * the LastWriteTime will be the correct local time plus the
647 * Bias (ignoring the sign - a positive offset from GMT is
648 * always stored as a negative Bias). If the Bias is -120,
649 * then the LastWriteTime will be ahead by 120 minutes.
651 * These bugs can occur at the same time.
654 GetTimeZoneInfo(&dst, &dstBias, &bias);
656 /* First adjust for DST */
658 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
660 /* Now adjust for a positive offset from GMT (a negative bias). */
662 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
665 #ifndef USE_NUMERIC_TIME_CONV
667 * Calculate the difference (in seconds) between local time and GMT.
668 * This enables us to convert file times to kludge-GMT.
674 struct tm gmt_tm, local_tm;
675 int days, hours, minutes, seconds;
678 gmt_tm = *(gmtime(&t));
679 local_tm = *(localtime(&t));
681 days = local_tm.tm_yday - gmt_tm.tm_yday;
682 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
683 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
684 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
688 #endif /* USE_NUMERIC_TIME_CONV */
691 #ifdef USE_NUMERIC_TIME_CONV
692 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
694 // Note that LONGLONG is a 64-bit value
697 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
698 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
699 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
702 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
707 time_t ersatz_unixTime;
710 * Must use kludge-GMT instead of real GMT.
711 * kludge-GMT is computed by adding time zone difference to localtime.
714 * ltp = gmtime(&unixTime);
716 ersatz_unixTime = unixTime - smb_NowTZ;
717 ltp = localtime(&ersatz_unixTime);
719 /* if we fail, make up something */
722 localJunk.tm_year = 89 - 20;
723 localJunk.tm_mon = 4;
724 localJunk.tm_mday = 12;
725 localJunk.tm_hour = 0;
726 localJunk.tm_min = 0;
727 localJunk.tm_sec = 0;
730 stm.wYear = ltp->tm_year + 1900;
731 stm.wMonth = ltp->tm_mon + 1;
732 stm.wDayOfWeek = ltp->tm_wday;
733 stm.wDay = ltp->tm_mday;
734 stm.wHour = ltp->tm_hour;
735 stm.wMinute = ltp->tm_min;
736 stm.wSecond = ltp->tm_sec;
737 stm.wMilliseconds = 0;
739 SystemTimeToFileTime(&stm, largeTimep);
741 #endif /* USE_NUMERIC_TIME_CONV */
743 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
745 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
746 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
747 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
749 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
751 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
752 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
754 *ft = LargeIntegerMultiplyByLong(*ft, 60);
755 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
758 ut = ConvertLongToLargeInteger(unixTime);
759 ut = LargeIntegerMultiplyByLong(ut, 10000000);
760 *ft = LargeIntegerAdd(*ft, ut);
765 #ifdef USE_NUMERIC_TIME_CONV
766 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
768 // Note that LONGLONG is a 64-bit value
771 ll = largeTimep->dwHighDateTime;
773 ll += largeTimep->dwLowDateTime;
775 ll -= 116444736000000000;
778 *unixTimep = (DWORD)ll;
780 #else /* USE_NUMERIC_TIME_CONV */
781 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
787 FileTimeToSystemTime(largeTimep, &stm);
789 lt.tm_year = stm.wYear - 1900;
790 lt.tm_mon = stm.wMonth - 1;
791 lt.tm_wday = stm.wDayOfWeek;
792 lt.tm_mday = stm.wDay;
793 lt.tm_hour = stm.wHour;
794 lt.tm_min = stm.wMinute;
795 lt.tm_sec = stm.wSecond;
798 save_timezone = _timezone;
799 _timezone += smb_NowTZ;
800 *unixTimep = mktime(<);
801 _timezone = save_timezone;
803 #endif /* USE_NUMERIC_TIME_CONV */
805 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
807 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
808 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
809 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
813 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
814 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
815 a = LargeIntegerMultiplyByLong(a, 60);
816 a = LargeIntegerMultiplyByLong(a, 10000000);
818 /* subtract it from ft */
819 a = LargeIntegerSubtract(*ft, a);
821 /* divide down to seconds */
822 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
826 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
836 /* if we fail, make up something */
839 localJunk.tm_year = 89 - 20;
840 localJunk.tm_mon = 4;
841 localJunk.tm_mday = 12;
842 localJunk.tm_hour = 0;
843 localJunk.tm_min = 0;
844 localJunk.tm_sec = 0;
847 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
848 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
849 *searchTimep = (dosDate<<16) | dosTime;
852 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
854 unsigned short dosDate;
855 unsigned short dosTime;
858 dosDate = (unsigned short) (searchTime & 0xffff);
859 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
861 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
862 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
863 localTm.tm_mday = (dosDate) & 0x1f;
864 localTm.tm_hour = (dosTime>>11) & 0x1f;
865 localTm.tm_min = (dosTime >> 5) & 0x3f;
866 localTm.tm_sec = (dosTime & 0x1f) * 2;
867 localTm.tm_isdst = -1; /* compute whether DST in effect */
869 *unixTimep = mktime(&localTm);
872 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
874 time_t diff_t = unixTime - smb_localZero;
875 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
876 osi_assert(diff_t < _UI32_MAX);
878 *dosUTimep = (afs_uint32)diff_t;
881 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
884 *unixTimep = dosTime + smb_localZero;
886 /* dosTime seems to be already adjusted for GMT */
887 *unixTimep = dosTime;
891 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
895 lock_ObtainWrite(&smb_rctLock);
896 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
897 if (vcp->magic != SMB_VC_MAGIC)
898 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
901 if (lsn == vcp->lsn && lana == vcp->lana &&
902 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
903 smb_HoldVCNoLock(vcp);
907 if (!vcp && (flags & SMB_FLAG_CREATE)) {
908 vcp = malloc(sizeof(*vcp));
909 memset(vcp, 0, sizeof(*vcp));
910 lock_ObtainWrite(&smb_globalLock);
911 vcp->vcID = ++numVCs;
912 lock_ReleaseWrite(&smb_globalLock);
913 vcp->magic = SMB_VC_MAGIC;
914 vcp->refCount = 2; /* smb_allVCsp and caller */
917 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
918 vcp->nextp = smb_allVCsp;
920 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
925 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
926 /* We must obtain a challenge for extended auth
927 * in case the client negotiates smb v3
929 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
930 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
931 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
932 ULONG lsaRespSize = 0;
934 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
936 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
943 if (nts != STATUS_SUCCESS)
944 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
945 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
946 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
948 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
949 LsaFreeReturnBuffer(lsaResp);
952 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
954 if (numVCs >= CM_SESSION_RESERVED) {
955 lock_ObtainWrite(&smb_globalLock);
957 lock_ReleaseWrite(&smb_globalLock);
958 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
961 lock_ReleaseWrite(&smb_rctLock);
965 int smb_IsStarMask(char *maskp)
970 for(i=0; i<11; i++) {
972 if (tc == '?' || tc == '*' || tc == '>')
978 void smb_ReleaseVCInternal(smb_vc_t *vcp)
985 if (vcp->refCount == 0) {
986 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
987 /* remove VCP from smb_deadVCsp */
988 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
994 lock_FinalizeMutex(&vcp->mx);
995 memset(vcp,0,sizeof(smb_vc_t));
998 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1002 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1003 avcp?"not ":"",vcp, vcp->refCount);
1005 GenerateMiniDump(NULL);
1007 /* This is a wrong. However, I suspect that there is an undercount
1008 * and I don't want to release 1.4.1 in a state that will allow
1009 * smb_vc_t objects to be deallocated while still in the
1010 * smb_allVCsp list. The list is supposed to keep a reference
1011 * to the smb_vc_t. Put it back.
1018 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1020 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1021 smb_ReleaseVCInternal(vcp);
1024 void smb_ReleaseVC(smb_vc_t *vcp)
1026 lock_ObtainWrite(&smb_rctLock);
1027 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1028 smb_ReleaseVCInternal(vcp);
1029 lock_ReleaseWrite(&smb_rctLock);
1032 void smb_HoldVCNoLock(smb_vc_t *vcp)
1035 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1038 void smb_HoldVC(smb_vc_t *vcp)
1040 lock_ObtainWrite(&smb_rctLock);
1042 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1043 lock_ReleaseWrite(&smb_rctLock);
1046 void smb_CleanupDeadVC(smb_vc_t *vcp)
1048 smb_fid_t *fidpIter;
1049 smb_fid_t *fidpNext;
1051 smb_tid_t *tidpIter;
1052 smb_tid_t *tidpNext;
1054 smb_user_t *uidpIter;
1055 smb_user_t *uidpNext;
1059 lock_ObtainMutex(&vcp->mx);
1060 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1061 lock_ReleaseMutex(&vcp->mx);
1062 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1065 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1066 lock_ReleaseMutex(&vcp->mx);
1067 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1069 lock_ObtainWrite(&smb_rctLock);
1070 /* remove VCP from smb_allVCsp */
1071 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1072 if ((*vcpp)->magic != SMB_VC_MAGIC)
1073 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1074 __FILE__, __LINE__);
1077 vcp->nextp = smb_deadVCsp;
1079 /* Hold onto the reference until we are done with this function */
1084 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1085 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1087 if (fidpIter->delete)
1090 fid = fidpIter->fid;
1091 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1093 smb_HoldFIDNoLock(fidpIter);
1094 lock_ReleaseWrite(&smb_rctLock);
1096 smb_CloseFID(vcp, fidpIter, NULL, 0);
1097 smb_ReleaseFID(fidpIter);
1099 lock_ObtainWrite(&smb_rctLock);
1100 fidpNext = vcp->fidsp;
1103 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1104 tidpNext = tidpIter->nextp;
1105 if (tidpIter->delete)
1107 tidpIter->delete = 1;
1109 tid = tidpIter->tid;
1110 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1112 smb_HoldTIDNoLock(tidpIter);
1113 lock_ReleaseWrite(&smb_rctLock);
1115 smb_ReleaseTID(tidpIter);
1117 lock_ObtainWrite(&smb_rctLock);
1118 tidpNext = vcp->tidsp;
1121 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1122 uidpNext = uidpIter->nextp;
1123 if (uidpIter->delete)
1125 uidpIter->delete = 1;
1127 /* do not add an additional reference count for the smb_user_t
1128 * as the smb_vc_t already is holding a reference */
1129 lock_ReleaseWrite(&smb_rctLock);
1131 smb_ReleaseUID(uidpIter);
1133 lock_ObtainWrite(&smb_rctLock);
1134 uidpNext = vcp->usersp;
1137 /* The vcp is now on the deadVCsp list. We intentionally drop the
1138 * reference so that the refcount can reach 0 and we can delete it */
1139 smb_ReleaseVCNoLock(vcp);
1141 lock_ReleaseWrite(&smb_rctLock);
1142 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1145 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1149 lock_ObtainWrite(&smb_rctLock);
1150 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1151 if (tid == tidp->tid) {
1156 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1157 tidp = malloc(sizeof(*tidp));
1158 memset(tidp, 0, sizeof(*tidp));
1159 tidp->nextp = vcp->tidsp;
1162 smb_HoldVCNoLock(vcp);
1164 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1167 lock_ReleaseWrite(&smb_rctLock);
1171 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1176 void smb_ReleaseTID(smb_tid_t *tidp)
1183 lock_ObtainWrite(&smb_rctLock);
1184 osi_assert(tidp->refCount-- > 0);
1185 if (tidp->refCount == 0 && (tidp->delete)) {
1186 ltpp = &tidp->vcp->tidsp;
1187 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1191 osi_assert(tp != NULL);
1193 lock_FinalizeMutex(&tidp->mx);
1194 userp = tidp->userp; /* remember to drop ref later */
1196 smb_ReleaseVCNoLock(tidp->vcp);
1199 lock_ReleaseWrite(&smb_rctLock);
1201 cm_ReleaseUser(userp);
1204 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1206 smb_user_t *uidp = NULL;
1208 lock_ObtainWrite(&smb_rctLock);
1209 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1210 if (uid == uidp->userID) {
1212 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1214 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1218 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1219 uidp = malloc(sizeof(*uidp));
1220 memset(uidp, 0, sizeof(*uidp));
1221 uidp->nextp = vcp->usersp;
1222 uidp->refCount = 2; /* one for the vcp and one for the caller */
1224 smb_HoldVCNoLock(vcp);
1226 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1228 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1230 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1232 lock_ReleaseWrite(&smb_rctLock);
1236 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1238 smb_username_t *unp= NULL;
1240 lock_ObtainWrite(&smb_rctLock);
1241 for(unp = usernamesp; unp; unp = unp->nextp) {
1242 if (stricmp(unp->name, usern) == 0 &&
1243 stricmp(unp->machine, machine) == 0) {
1248 if (!unp && (flags & SMB_FLAG_CREATE)) {
1249 unp = malloc(sizeof(*unp));
1250 memset(unp, 0, sizeof(*unp));
1252 unp->nextp = usernamesp;
1253 unp->name = strdup(usern);
1254 unp->machine = strdup(machine);
1256 lock_InitializeMutex(&unp->mx, "username_t mutex");
1257 if (flags & SMB_FLAG_AFSLOGON)
1258 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1261 lock_ReleaseWrite(&smb_rctLock);
1265 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1267 smb_user_t *uidp= NULL;
1269 lock_ObtainWrite(&smb_rctLock);
1270 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1273 if (stricmp(uidp->unp->name, usern) == 0) {
1275 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1276 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1281 lock_ReleaseWrite(&smb_rctLock);
1285 void smb_ReleaseUsername(smb_username_t *unp)
1288 smb_username_t **lupp;
1289 cm_user_t *userp = NULL;
1290 time_t now = osi_Time();
1292 lock_ObtainWrite(&smb_rctLock);
1293 osi_assert(unp->refCount-- > 0);
1294 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1295 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1297 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1301 osi_assert(up != NULL);
1303 up->nextp = NULL; /* do not remove this */
1304 lock_FinalizeMutex(&unp->mx);
1310 lock_ReleaseWrite(&smb_rctLock);
1313 cm_ReleaseUser(userp);
1317 void smb_HoldUIDNoLock(smb_user_t *uidp)
1322 void smb_ReleaseUID(smb_user_t *uidp)
1326 smb_username_t *unp = NULL;
1328 lock_ObtainWrite(&smb_rctLock);
1329 osi_assert(uidp->refCount-- > 0);
1330 if (uidp->refCount == 0) {
1331 lupp = &uidp->vcp->usersp;
1332 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1336 osi_assert(up != NULL);
1338 lock_FinalizeMutex(&uidp->mx);
1340 smb_ReleaseVCNoLock(uidp->vcp);
1344 lock_ReleaseWrite(&smb_rctLock);
1348 cm_ReleaseUserVCRef(unp->userp);
1349 smb_ReleaseUsername(unp);
1353 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1355 cm_user_t *up = NULL;
1360 lock_ObtainMutex(&uidp->mx);
1362 up = uidp->unp->userp;
1365 lock_ReleaseMutex(&uidp->mx);
1371 /* retrieve a held reference to a user structure corresponding to an incoming
1373 * corresponding release function is cm_ReleaseUser.
1375 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1378 cm_user_t *up = NULL;
1381 smbp = (smb_t *) inp;
1382 uidp = smb_FindUID(vcp, smbp->uid, 0);
1386 up = smb_GetUserFromUID(uidp);
1388 smb_ReleaseUID(uidp);
1393 * Return a pointer to a pathname extracted from a TID structure. The
1394 * TID structure is not held; assume it won't go away.
1396 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1401 tidp = smb_FindTID(vcp, tid, 0);
1405 if (tidp->flags & SMB_TIDFLAG_IPC) {
1406 code = CM_ERROR_TIDIPC;
1407 /* tidp->pathname would be NULL, but that's fine */
1409 *treepath = tidp->pathname;
1410 smb_ReleaseTID(tidp);
1415 /* check to see if we have a chained fid, that is, a fid that comes from an
1416 * OpenAndX message that ran earlier in this packet. In this case, the fid
1417 * field in a read, for example, request, isn't set, since the value is
1418 * supposed to be inherited from the openAndX call.
1420 int smb_ChainFID(int fid, smb_packet_t *inp)
1422 if (inp->fid == 0 || inp->inCount == 0)
1428 /* are we a priv'd user? What does this mean on NT? */
1429 int smb_SUser(cm_user_t *userp)
1434 /* find a file ID. If we pass in 0 we select an unused File ID.
1435 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1436 * smb_fid_t data structure if desired File ID cannot be found.
1438 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1443 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1446 lock_ObtainWrite(&smb_rctLock);
1447 /* figure out if we need to allocate a new file ID */
1450 fid = vcp->fidCounter;
1454 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1455 if (fid == fidp->fid) {
1458 if (fid == 0xFFFF) {
1460 "New FID number wraps on vcp 0x%x", vcp);
1470 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1471 char eventName[MAX_PATH];
1473 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1474 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1475 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1476 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1477 thrd_CloseHandle(event);
1479 if (fid == 0xFFFF) {
1480 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1486 fidp = malloc(sizeof(*fidp));
1487 memset(fidp, 0, sizeof(*fidp));
1488 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1491 smb_HoldVCNoLock(vcp);
1492 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1494 fidp->curr_chunk = fidp->prev_chunk = -2;
1495 fidp->raw_write_event = event;
1497 vcp->fidCounter = fid+1;
1498 if (vcp->fidCounter == 0xFFFF) {
1499 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1501 vcp->fidCounter = 1;
1506 lock_ReleaseWrite(&smb_rctLock);
1510 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1512 smb_fid_t *fidp = NULL;
1518 lock_ObtainWrite(&smb_rctLock);
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (scp == fidp->scp) {
1525 lock_ReleaseWrite(&smb_rctLock);
1529 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1534 void smb_ReleaseFID(smb_fid_t *fidp)
1536 cm_scache_t *scp = NULL;
1537 cm_user_t *userp = NULL;
1538 smb_vc_t *vcp = NULL;
1539 smb_ioctl_t *ioctlp;
1541 lock_ObtainMutex(&fidp->mx);
1542 lock_ObtainWrite(&smb_rctLock);
1543 osi_assert(fidp->refCount-- > 0);
1544 if (fidp->refCount == 0 && (fidp->delete)) {
1547 scp = fidp->scp; /* release after lock is released */
1549 userp = fidp->userp;
1553 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1554 thrd_CloseHandle(fidp->raw_write_event);
1556 /* and see if there is ioctl stuff to free */
1557 ioctlp = fidp->ioctlp;
1560 cm_FreeSpace(ioctlp->prefix);
1561 if (ioctlp->inAllocp)
1562 free(ioctlp->inAllocp);
1563 if (ioctlp->outAllocp)
1564 free(ioctlp->outAllocp);
1567 lock_ReleaseMutex(&fidp->mx);
1568 lock_FinalizeMutex(&fidp->mx);
1572 smb_ReleaseVCNoLock(vcp);
1574 lock_ReleaseMutex(&fidp->mx);
1576 lock_ReleaseWrite(&smb_rctLock);
1578 /* now release the scache structure */
1580 cm_ReleaseSCache(scp);
1583 cm_ReleaseUser(userp);
1587 * Case-insensitive search for one string in another;
1588 * used to find variable names in submount pathnames.
1590 static char *smb_stristr(char *str1, char *str2)
1594 for (cursor = str1; *cursor; cursor++)
1595 if (stricmp(cursor, str2) == 0)
1602 * Substitute a variable value for its name in a submount pathname. Variable
1603 * name has been identified by smb_stristr() and is in substr. Variable name
1604 * length (plus one) is in substr_size. Variable value is in newstr.
1606 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1611 strcpy(temp, substr + substr_size - 1);
1612 strcpy(substr, newstr);
1616 char VNUserName[] = "%USERNAME%";
1617 char VNLCUserName[] = "%LCUSERNAME%";
1618 char VNComputerName[] = "%COMPUTERNAME%";
1619 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1622 /* List available shares */
1623 int smb_ListShares()
1627 char shareBuf[4096];
1635 /*strcpy(shareNameList[num_shares], "all");
1636 strcpy(pathNameList[num_shares++], "/afs");*/
1637 fprintf(stderr, "The following shares are available:\n");
1638 fprintf(stderr, "Share Name (AFS Path)\n");
1639 fprintf(stderr, "---------------------\n");
1640 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1643 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1644 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1646 strcpy(sbmtpath, cm_confDir);
1648 strcat(sbmtpath, "/afsdsbmt.ini");
1649 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1650 shareBuf, sizeof(shareBuf),
1656 this_share = shareBuf;
1660 /*strcpy(shareNameList[num_shares], this_share);*/
1661 len = GetPrivateProfileString("AFS Submounts", this_share,
1668 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1671 if (*p == '\\') *p = '/'; /* change to / */
1675 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1676 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1679 while (*this_share != 0) this_share++; /* find next NUL */
1680 this_share++; /* skip past the NUL */
1681 } while (*this_share != 0); /* stop at final NUL */
1687 typedef struct smb_findShare_rock {
1691 } smb_findShare_rock_t;
1693 #define SMB_FINDSHARE_EXACT_MATCH 1
1694 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1696 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1700 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1701 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1702 if(!stricmp(dep->name, vrock->shareName))
1703 matchType = SMB_FINDSHARE_EXACT_MATCH;
1705 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1706 if(vrock->match) free(vrock->match);
1707 vrock->match = strdup(dep->name);
1708 vrock->matchType = matchType;
1710 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1711 return CM_ERROR_STOPNOW;
1717 /* find a shareName in the table of submounts */
1718 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1722 char pathName[1024];
1727 char sbmtpath[MAX_PATH];
1732 DWORD allSubmount = 1;
1734 /* if allSubmounts == 0, only return the //mountRoot/all share
1735 * if in fact it has been been created in the subMounts table.
1736 * This is to allow sites that want to restrict access to the
1739 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1740 0, KEY_QUERY_VALUE, &parmKey);
1741 if (code == ERROR_SUCCESS) {
1742 len = sizeof(allSubmount);
1743 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1744 (BYTE *) &allSubmount, &len);
1745 if (code != ERROR_SUCCESS) {
1748 RegCloseKey (parmKey);
1751 if (allSubmount && _stricmp(shareName, "all") == 0) {
1756 /* In case, the all share is disabled we need to still be able
1757 * to handle ioctl requests
1759 if (_stricmp(shareName, "ioctl$") == 0) {
1760 *pathNamep = strdup("/.__ioctl__");
1764 if (_stricmp(shareName, "IPC$") == 0 ||
1765 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1766 _stricmp(shareName, "DESKTOP.INI") == 0
1773 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1774 0, KEY_QUERY_VALUE, &parmKey);
1775 if (code == ERROR_SUCCESS) {
1776 len = sizeof(pathName);
1777 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1778 (BYTE *) pathName, &len);
1779 if (code != ERROR_SUCCESS)
1781 RegCloseKey (parmKey);
1786 strcpy(sbmtpath, cm_confDir);
1787 strcat(sbmtpath, "/afsdsbmt.ini");
1788 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1789 pathName, sizeof(pathName), sbmtpath);
1791 if (len != 0 && len != sizeof(pathName) - 1) {
1792 /* We can accept either unix or PC style AFS pathnames. Convert
1793 * Unix-style to PC style here for internal use.
1796 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1797 p += strlen(cm_mountRoot); /* skip mount path */
1800 if (*q == '/') *q = '\\'; /* change to \ */
1806 if (var = smb_stristr(p, VNUserName)) {
1807 if (uidp && uidp->unp)
1808 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1810 smb_subst(p, var, sizeof(VNUserName)," ");
1812 else if (var = smb_stristr(p, VNLCUserName))
1814 if (uidp && uidp->unp)
1815 strcpy(temp, uidp->unp->name);
1819 smb_subst(p, var, sizeof(VNLCUserName), temp);
1821 else if (var = smb_stristr(p, VNComputerName))
1823 sizeTemp = sizeof(temp);
1824 GetComputerName((LPTSTR)temp, &sizeTemp);
1825 smb_subst(p, var, sizeof(VNComputerName), temp);
1827 else if (var = smb_stristr(p, VNLCComputerName))
1829 sizeTemp = sizeof(temp);
1830 GetComputerName((LPTSTR)temp, &sizeTemp);
1832 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1837 *pathNamep = strdup(p);
1842 /* First lookup shareName in root.afs */
1844 smb_findShare_rock_t vrock;
1846 char * p = shareName;
1849 /* attempt to locate a partial match in root.afs. This is because
1850 when using the ANSI RAP calls, the share name is limited to 13 chars
1851 and hence is truncated. Of course we prefer exact matches. */
1853 thyper.HighPart = 0;
1856 vrock.shareName = shareName;
1858 vrock.matchType = 0;
1860 cm_HoldSCache(cm_data.rootSCachep);
1861 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1862 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1863 cm_ReleaseSCache(cm_data.rootSCachep);
1865 if (vrock.matchType) {
1866 sprintf(pathName,"/%s/",vrock.match);
1867 *pathNamep = strdup(strlwr(pathName));
1872 /* if we get here, there was no match for the share in root.afs */
1873 /* so try to create \\<netbiosName>\<cellname> */
1878 /* Get the full name for this cell */
1879 code = cm_SearchCellFile(p, temp, 0, 0);
1880 #ifdef AFS_AFSDB_ENV
1881 if (code && cm_dnsEnabled) {
1883 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1886 /* construct the path */
1888 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1889 *pathNamep = strdup(strlwr(pathName));
1898 /* Client-side offline caching policy types */
1899 #define CSC_POLICY_MANUAL 0
1900 #define CSC_POLICY_DOCUMENTS 1
1901 #define CSC_POLICY_PROGRAMS 2
1902 #define CSC_POLICY_DISABLE 3
1904 int smb_FindShareCSCPolicy(char *shareName)
1910 int retval = CSC_POLICY_MANUAL;
1912 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1913 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1916 REG_OPTION_NON_VOLATILE,
1922 len = sizeof(policy);
1923 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1925 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1927 else if (stricmp(policy, "documents") == 0)
1929 retval = CSC_POLICY_DOCUMENTS;
1931 else if (stricmp(policy, "programs") == 0)
1933 retval = CSC_POLICY_PROGRAMS;
1935 else if (stricmp(policy, "disable") == 0)
1937 retval = CSC_POLICY_DISABLE;
1940 RegCloseKey(hkCSCPolicy);
1944 /* find a dir search structure by cookie value, and return it held.
1945 * Must be called with smb_globalLock held.
1947 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1949 smb_dirSearch_t *dsp;
1951 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1952 if (dsp->cookie == cookie) {
1953 if (dsp != smb_firstDirSearchp) {
1954 /* move to head of LRU queue, too, if we're not already there */
1955 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1956 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1957 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1958 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1959 if (!smb_lastDirSearchp)
1960 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1962 lock_ObtainMutex(&dsp->mx);
1964 lock_ReleaseMutex(&dsp->mx);
1970 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1971 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1972 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1978 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1980 lock_ObtainWrite(&smb_globalLock);
1981 lock_ObtainMutex(&dsp->mx);
1982 dsp->flags |= SMB_DIRSEARCH_DELETE;
1983 if (dsp->scp != NULL) {
1984 lock_ObtainMutex(&dsp->scp->mx);
1985 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1986 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1987 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1988 dsp->scp->bulkStatProgress = hzero;
1990 lock_ReleaseMutex(&dsp->scp->mx);
1992 lock_ReleaseMutex(&dsp->mx);
1993 lock_ReleaseWrite(&smb_globalLock);
1996 /* Must be called with the smb_globalLock held */
1997 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1999 cm_scache_t *scp = NULL;
2001 lock_ObtainMutex(&dsp->mx);
2002 osi_assert(dsp->refCount-- > 0);
2003 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
2004 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2005 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2006 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2007 lock_ReleaseMutex(&dsp->mx);
2008 lock_FinalizeMutex(&dsp->mx);
2012 lock_ReleaseMutex(&dsp->mx);
2014 /* do this now to avoid spurious locking hierarchy creation */
2016 cm_ReleaseSCache(scp);
2019 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2021 lock_ObtainWrite(&smb_globalLock);
2022 smb_ReleaseDirSearchNoLock(dsp);
2023 lock_ReleaseWrite(&smb_globalLock);
2026 /* find a dir search structure by cookie value, and return it held */
2027 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2029 smb_dirSearch_t *dsp;
2031 lock_ObtainWrite(&smb_globalLock);
2032 dsp = smb_FindDirSearchNoLock(cookie);
2033 lock_ReleaseWrite(&smb_globalLock);
2037 /* GC some dir search entries, in the address space expected by the specific protocol.
2038 * Must be called with smb_globalLock held; release the lock temporarily.
2040 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2041 void smb_GCDirSearches(int isV3)
2043 smb_dirSearch_t *prevp;
2044 smb_dirSearch_t *tp;
2045 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2049 victimCount = 0; /* how many have we got so far */
2050 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2051 /* we'll move tp from queue, so
2054 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2055 /* if no one is using this guy, and we're either in the new protocol,
2056 * or we're in the old one and this is a small enough ID to be useful
2057 * to the old protocol, GC this guy.
2059 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2060 /* hold and delete */
2061 lock_ObtainMutex(&tp->mx);
2062 tp->flags |= SMB_DIRSEARCH_DELETE;
2063 lock_ReleaseMutex(&tp->mx);
2064 victimsp[victimCount++] = tp;
2068 /* don't do more than this */
2069 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2073 /* now release them */
2074 for (i = 0; i < victimCount; i++) {
2075 smb_ReleaseDirSearchNoLock(victimsp[i]);
2079 /* function for allocating a dir search entry. We need these to remember enough context
2080 * since we don't get passed the path from call to call during a directory search.
2082 * Returns a held dir search structure, and bumps the reference count on the vnode,
2083 * since it saves a pointer to the vnode.
2085 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2087 smb_dirSearch_t *dsp;
2093 lock_ObtainWrite(&smb_globalLock);
2096 /* what's the biggest ID allowed in this version of the protocol */
2097 maxAllowed = isV3 ? 65535 : 255;
2098 if (smb_dirSearchCounter > maxAllowed)
2099 smb_dirSearchCounter = 1;
2101 start = smb_dirSearchCounter;
2104 /* twice so we have enough tries to find guys we GC after one pass;
2105 * 10 extra is just in case I mis-counted.
2107 if (++counter > 2*maxAllowed+10)
2108 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2110 if (smb_dirSearchCounter > maxAllowed) {
2111 smb_dirSearchCounter = 1;
2113 if (smb_dirSearchCounter == start) {
2115 smb_GCDirSearches(isV3);
2118 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2120 /* don't need to watch for refcount zero and deleted, since
2121 * we haven't dropped the global lock.
2123 lock_ObtainMutex(&dsp->mx);
2125 lock_ReleaseMutex(&dsp->mx);
2126 ++smb_dirSearchCounter;
2130 dsp = malloc(sizeof(*dsp));
2131 memset(dsp, 0, sizeof(*dsp));
2132 dsp->cookie = smb_dirSearchCounter;
2133 ++smb_dirSearchCounter;
2135 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2136 dsp->lastTime = osi_Time();
2137 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2138 if (!smb_lastDirSearchp)
2139 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2142 lock_ReleaseWrite(&smb_globalLock);
2146 static smb_packet_t *GetPacket(void)
2150 unsigned int npar, seg, tb_sel;
2153 lock_ObtainWrite(&smb_globalLock);
2154 tbp = smb_packetFreeListp;
2156 smb_packetFreeListp = tbp->nextp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 tbp = calloc(65540,1);
2162 tbp = malloc(sizeof(smb_packet_t));
2164 tbp->magic = SMB_PACKETMAGIC;
2167 tbp->resumeCode = 0;
2173 tbp->ncb_length = 0;
2178 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2181 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2183 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2185 osi_panic("",__FILE__,__LINE__);
2188 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2193 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2194 tbp->dos_pkt_sel = tb_sel;
2197 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2202 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2206 memcpy(tbp, pkt, sizeof(smb_packet_t));
2207 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2209 smb_HoldVC(tbp->vcp);
2213 static NCB *GetNCB(void)
2218 unsigned int npar, seg, tb_sel;
2221 lock_ObtainWrite(&smb_globalLock);
2222 tbp = smb_ncbFreeListp;
2224 smb_ncbFreeListp = tbp->nextp;
2225 lock_ReleaseWrite(&smb_globalLock);
2228 tbp = calloc(sizeof(*tbp),1);
2230 tbp = malloc(sizeof(*tbp));
2231 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2234 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2236 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2238 osi_panic("",__FILE__,__LINE__);
2240 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2245 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2246 tbp->dos_ncb_sel = tb_sel;
2248 tbp->magic = SMB_NCBMAGIC;
2251 osi_assert(tbp->magic == SMB_NCBMAGIC);
2253 memset(&tbp->ncb, 0, sizeof(NCB));
2256 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2261 void smb_FreePacket(smb_packet_t *tbp)
2263 smb_vc_t * vcp = NULL;
2264 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2266 lock_ObtainWrite(&smb_globalLock);
2267 tbp->nextp = smb_packetFreeListp;
2268 smb_packetFreeListp = tbp;
2269 tbp->magic = SMB_PACKETMAGIC;
2273 tbp->resumeCode = 0;
2279 tbp->ncb_length = 0;
2281 lock_ReleaseWrite(&smb_globalLock);
2287 static void FreeNCB(NCB *bufferp)
2291 tbp = (smb_ncb_t *) bufferp;
2292 osi_assert(tbp->magic == SMB_NCBMAGIC);
2294 lock_ObtainWrite(&smb_globalLock);
2295 tbp->nextp = smb_ncbFreeListp;
2296 smb_ncbFreeListp = tbp;
2297 lock_ReleaseWrite(&smb_globalLock);
2300 /* get a ptr to the data part of a packet, and its count */
2301 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2305 unsigned char *afterParmsp;
2307 parmBytes = *smbp->wctp << 1;
2308 afterParmsp = smbp->wctp + parmBytes + 1;
2310 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2311 if (nbytesp) *nbytesp = dataBytes;
2313 /* don't forget to skip the data byte count, since it follows
2314 * the parameters; that's where the "2" comes from below.
2316 return (unsigned char *) (afterParmsp + 2);
2319 /* must set all the returned parameters before playing around with the
2320 * data region, since the data region is located past the end of the
2321 * variable number of parameters.
2323 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2325 unsigned char *afterParmsp;
2327 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2329 *afterParmsp++ = dsize & 0xff;
2330 *afterParmsp = (dsize>>8) & 0xff;
2333 /* return the parm'th parameter in the smbp packet */
2334 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2337 unsigned char *parmDatap;
2339 parmCount = *smbp->wctp;
2341 if (parm >= parmCount) {
2344 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2345 parm, parmCount, smbp->ncb_length);
2346 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2347 parm, parmCount, smbp->ncb_length);
2349 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2350 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2352 osi_panic(s, __FILE__, __LINE__);
2354 parmDatap = smbp->wctp + (2*parm) + 1;
2356 return parmDatap[0] + (parmDatap[1] << 8);
2359 /* return the parm'th parameter in the smbp packet */
2360 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2363 unsigned char *parmDatap;
2365 parmCount = *smbp->wctp;
2367 if (parm + 1 >= parmCount) {
2370 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2371 parm, parmCount, smbp->ncb_length);
2372 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2373 parm, parmCount, smbp->ncb_length);
2375 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2376 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2378 osi_panic(s, __FILE__, __LINE__);
2380 parmDatap = smbp->wctp + (2*parm) + 1;
2382 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2385 /* return the parm'th parameter in the smbp packet */
2386 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2389 unsigned char *parmDatap;
2391 parmCount = *smbp->wctp;
2393 if (parm * 2 + offset >= parmCount * 2) {
2396 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2397 parm, offset, parmCount, smbp->ncb_length);
2399 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2400 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2402 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2403 parm, offset, parmCount, smbp->ncb_length);
2404 osi_panic(s, __FILE__, __LINE__);
2406 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2408 return parmDatap[0] + (parmDatap[1] << 8);
2411 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2415 /* make sure we have enough slots */
2416 if (*smbp->wctp <= slot)
2417 *smbp->wctp = slot+1;
2419 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2420 *parmDatap++ = parmValue & 0xff;
2421 *parmDatap = (parmValue>>8) & 0xff;
2424 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2428 /* make sure we have enough slots */
2429 if (*smbp->wctp <= slot)
2430 *smbp->wctp = slot+2;
2432 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2433 *parmDatap++ = parmValue & 0xff;
2434 *parmDatap++ = (parmValue>>8) & 0xff;
2435 *parmDatap++ = (parmValue>>16) & 0xff;
2436 *parmDatap = (parmValue>>24) & 0xff;
2439 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2444 /* make sure we have enough slots */
2445 if (*smbp->wctp <= slot)
2446 *smbp->wctp = slot+4;
2448 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2450 *parmDatap++ = *parmValuep++;
2453 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2457 /* make sure we have enough slots */
2458 if (*smbp->wctp <= slot) {
2459 if (smbp->oddByte) {
2461 *smbp->wctp = slot+1;
2466 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2467 *parmDatap++ = parmValue & 0xff;
2470 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2474 lastSlashp = strrchr(inPathp, '\\');
2476 *lastComponentp = lastSlashp;
2479 if (inPathp == lastSlashp)
2481 *outPathp++ = *inPathp++;
2490 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2495 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2500 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2506 tlen = inp[0] + (inp[1]<<8);
2507 inp += 2; /* skip length field */
2510 *chainpp = inp + tlen;
2519 /* format a packet as a response */
2520 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2525 outp = (smb_t *) op;
2527 /* zero the basic structure through the smb_wct field, and zero the data
2528 * size field, assuming that wct stays zero; otherwise, you have to
2529 * explicitly set the data size field, too.
2531 inSmbp = (smb_t *) inp;
2532 memset(outp, 0, sizeof(smb_t)+2);
2538 outp->com = inSmbp->com;
2539 outp->tid = inSmbp->tid;
2540 outp->pid = inSmbp->pid;
2541 outp->uid = inSmbp->uid;
2542 outp->mid = inSmbp->mid;
2543 outp->res[0] = inSmbp->res[0];
2544 outp->res[1] = inSmbp->res[1];
2545 op->inCom = inSmbp->com;
2547 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2548 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2550 /* copy fields in generic packet area */
2551 op->wctp = &outp->wct;
2554 /* send a (probably response) packet; vcp tells us to whom to send it.
2555 * we compute the length by looking at wct and bcc fields.
2557 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2574 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2577 memset((char *)ncbp, 0, sizeof(NCB));
2579 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2580 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2581 extra += tp[0] + (tp[1]<<8);
2582 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2583 extra += 3; /* wct and length fields */
2585 ncbp->ncb_length = extra; /* bytes to send */
2586 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2587 ncbp->ncb_lana_num = vcp->lana;
2588 ncbp->ncb_command = NCBSEND; /* op means send data */
2590 ncbp->ncb_buffer = (char *) inp;/* packet */
2591 code = Netbios(ncbp);
2593 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2594 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2596 /* copy header information from virtual to DOS address space */
2597 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2598 code = Netbios(ncbp, dos_ncb);
2602 const char * s = ncb_error_string(code);
2603 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2605 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2608 lock_ObtainMutex(&vcp->mx);
2609 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2610 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2612 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2613 lock_ReleaseMutex(&vcp->mx);
2614 lock_ObtainWrite(&smb_globalLock);
2615 dead_sessions[vcp->session] = TRUE;
2616 lock_ReleaseWrite(&smb_globalLock);
2617 smb_CleanupDeadVC(vcp);
2619 lock_ReleaseMutex(&vcp->mx);
2627 void smb_MapNTError(long code, unsigned long *NTStatusp)
2629 unsigned long NTStatus;
2631 /* map CM_ERROR_* errors to NT 32-bit status codes */
2632 /* NT Status codes are listed in ntstatus.h not winerror.h */
2633 if (code == CM_ERROR_NOSUCHCELL) {
2634 NTStatus = 0xC000000FL; /* No such file */
2636 else if (code == CM_ERROR_NOSUCHVOLUME) {
2637 NTStatus = 0xC000000FL; /* No such file */
2639 else if (code == CM_ERROR_TIMEDOUT) {
2641 NTStatus = 0xC00000CFL; /* Sharing Paused */
2643 NTStatus = 0x00000102L; /* Timeout */
2646 else if (code == CM_ERROR_RETRY) {
2647 NTStatus = 0xC000022DL; /* Retry */
2649 else if (code == CM_ERROR_NOACCESS) {
2650 NTStatus = 0xC0000022L; /* Access denied */
2652 else if (code == CM_ERROR_READONLY) {
2653 NTStatus = 0xC00000A2L; /* Write protected */
2655 else if (code == CM_ERROR_NOSUCHFILE) {
2656 NTStatus = 0xC000000FL; /* No such file */
2658 else if (code == CM_ERROR_NOSUCHPATH) {
2659 NTStatus = 0xC000003AL; /* Object path not found */
2661 else if (code == CM_ERROR_TOOBIG) {
2662 NTStatus = 0xC000007BL; /* Invalid image format */
2664 else if (code == CM_ERROR_INVAL) {
2665 NTStatus = 0xC000000DL; /* Invalid parameter */
2667 else if (code == CM_ERROR_BADFD) {
2668 NTStatus = 0xC0000008L; /* Invalid handle */
2670 else if (code == CM_ERROR_BADFDOP) {
2671 NTStatus = 0xC0000022L; /* Access denied */
2673 else if (code == CM_ERROR_EXISTS) {
2674 NTStatus = 0xC0000035L; /* Object name collision */
2676 else if (code == CM_ERROR_NOTEMPTY) {
2677 NTStatus = 0xC0000101L; /* Directory not empty */
2679 else if (code == CM_ERROR_CROSSDEVLINK) {
2680 NTStatus = 0xC00000D4L; /* Not same device */
2682 else if (code == CM_ERROR_NOTDIR) {
2683 NTStatus = 0xC0000103L; /* Not a directory */
2685 else if (code == CM_ERROR_ISDIR) {
2686 NTStatus = 0xC00000BAL; /* File is a directory */
2688 else if (code == CM_ERROR_BADOP) {
2690 /* I have no idea where this comes from */
2691 NTStatus = 0xC09820FFL; /* SMB no support */
2693 NTStatus = 0xC00000BBL; /* Not supported */
2694 #endif /* COMMENT */
2696 else if (code == CM_ERROR_BADSHARENAME) {
2697 NTStatus = 0xC00000CCL; /* Bad network name */
2699 else if (code == CM_ERROR_NOIPC) {
2701 NTStatus = 0xC0000022L; /* Access Denied */
2703 NTStatus = 0xC000013DL; /* Remote Resources */
2706 else if (code == CM_ERROR_CLOCKSKEW) {
2707 NTStatus = 0xC0000133L; /* Time difference at DC */
2709 else if (code == CM_ERROR_BADTID) {
2710 NTStatus = 0xC0982005L; /* SMB bad TID */
2712 else if (code == CM_ERROR_USESTD) {
2713 NTStatus = 0xC09820FBL; /* SMB use standard */
2715 else if (code == CM_ERROR_QUOTA) {
2717 NTStatus = 0xC0000044L; /* Quota exceeded */
2719 NTStatus = 0xC000007FL; /* Disk full */
2722 else if (code == CM_ERROR_SPACE) {
2723 NTStatus = 0xC000007FL; /* Disk full */
2725 else if (code == CM_ERROR_ATSYS) {
2726 NTStatus = 0xC0000033L; /* Object name invalid */
2728 else if (code == CM_ERROR_BADNTFILENAME) {
2729 NTStatus = 0xC0000033L; /* Object name invalid */
2731 else if (code == CM_ERROR_WOULDBLOCK) {
2732 NTStatus = 0xC0000055L; /* Lock not granted */
2734 else if (code == CM_ERROR_SHARING_VIOLATION) {
2735 NTStatus = 0xC0000043L; /* Sharing violation */
2737 else if (code == CM_ERROR_LOCK_CONFLICT) {
2738 NTStatus = 0xC0000054L; /* Lock conflict */
2740 else if (code == CM_ERROR_PARTIALWRITE) {
2741 NTStatus = 0xC000007FL; /* Disk full */
2743 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2744 NTStatus = 0xC0000023L; /* Buffer too small */
2746 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2747 NTStatus = 0xC0000035L; /* Object name collision */
2749 else if (code == CM_ERROR_BADPASSWORD) {
2750 NTStatus = 0xC000006DL; /* unknown username or bad password */
2752 else if (code == CM_ERROR_BADLOGONTYPE) {
2753 NTStatus = 0xC000015BL; /* logon type not granted */
2755 else if (code == CM_ERROR_GSSCONTINUE) {
2756 NTStatus = 0xC0000016L; /* more processing required */
2758 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2760 NTStatus = 0xC0000280L; /* reparse point not resolved */
2762 NTStatus = 0xC0000022L; /* Access Denied */
2765 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2766 NTStatus = 0xC0000257L; /* Path Not Covered */
2769 else if (code == CM_ERROR_ALLBUSY) {
2770 NTStatus = 0xC00000BFL; /* Network Busy */
2772 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2773 NTStatus = 0xC0000350L; /* Remote Host Down */
2776 /* we do not want to be telling the SMB/CIFS client that
2777 * the AFS Client Service is busy or down.
2779 else if (code == CM_ERROR_ALLBUSY ||
2780 code == CM_ERROR_ALLOFFLINE ||
2781 code == CM_ERROR_ALLDOWN) {
2782 NTStatus = 0xC00000BEL; /* Bad Network Path */
2785 else if (code == RXKADUNKNOWNKEY) {
2786 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2788 NTStatus = 0xC0982001L; /* SMB non-specific error */
2791 *NTStatusp = NTStatus;
2792 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2795 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2796 unsigned char *classp)
2798 unsigned char class;
2799 unsigned short error;
2801 /* map CM_ERROR_* errors to SMB errors */
2802 if (code == CM_ERROR_NOSUCHCELL) {
2804 error = 3; /* bad path */
2806 else if (code == CM_ERROR_NOSUCHVOLUME) {
2808 error = 3; /* bad path */
2810 else if (code == CM_ERROR_TIMEDOUT) {
2812 error = 81; /* server is paused */
2814 else if (code == CM_ERROR_RETRY) {
2815 class = 2; /* shouldn't happen */
2818 else if (code == CM_ERROR_NOACCESS) {
2820 error = 4; /* bad access */
2822 else if (code == CM_ERROR_READONLY) {
2824 error = 19; /* read only */
2826 else if (code == CM_ERROR_NOSUCHFILE) {
2828 error = 2; /* ENOENT! */
2830 else if (code == CM_ERROR_NOSUCHPATH) {
2832 error = 3; /* Bad path */
2834 else if (code == CM_ERROR_TOOBIG) {
2836 error = 11; /* bad format */
2838 else if (code == CM_ERROR_INVAL) {
2839 class = 2; /* server non-specific error code */
2842 else if (code == CM_ERROR_BADFD) {
2844 error = 6; /* invalid file handle */
2846 else if (code == CM_ERROR_BADFDOP) {
2847 class = 1; /* invalid op on FD */
2850 else if (code == CM_ERROR_EXISTS) {
2852 error = 80; /* file already exists */
2854 else if (code == CM_ERROR_NOTEMPTY) {
2856 error = 5; /* delete directory not empty */
2858 else if (code == CM_ERROR_CROSSDEVLINK) {
2860 error = 17; /* EXDEV */
2862 else if (code == CM_ERROR_NOTDIR) {
2863 class = 1; /* bad path */
2866 else if (code == CM_ERROR_ISDIR) {
2867 class = 1; /* access denied; DOS doesn't have a good match */
2870 else if (code == CM_ERROR_BADOP) {
2874 else if (code == CM_ERROR_BADSHARENAME) {
2878 else if (code == CM_ERROR_NOIPC) {
2880 error = 4; /* bad access */
2882 else if (code == CM_ERROR_CLOCKSKEW) {
2883 class = 1; /* invalid function */
2886 else if (code == CM_ERROR_BADTID) {
2890 else if (code == CM_ERROR_USESTD) {
2894 else if (code == CM_ERROR_REMOTECONN) {
2898 else if (code == CM_ERROR_QUOTA) {
2899 if (vcp->flags & SMB_VCFLAG_USEV3) {
2901 error = 39; /* disk full */
2905 error = 5; /* access denied */
2908 else if (code == CM_ERROR_SPACE) {
2909 if (vcp->flags & SMB_VCFLAG_USEV3) {
2911 error = 39; /* disk full */
2915 error = 5; /* access denied */
2918 else if (code == CM_ERROR_PARTIALWRITE) {
2920 error = 39; /* disk full */
2922 else if (code == CM_ERROR_ATSYS) {
2924 error = 2; /* ENOENT */
2926 else if (code == CM_ERROR_WOULDBLOCK) {
2928 error = 33; /* lock conflict */
2930 else if (code == CM_ERROR_LOCK_CONFLICT) {
2932 error = 33; /* lock conflict */
2934 else if (code == CM_ERROR_SHARING_VIOLATION) {
2936 error = 33; /* lock conflict */
2938 else if (code == CM_ERROR_NOFILES) {
2940 error = 18; /* no files in search */
2942 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2944 error = 183; /* Samba uses this */
2946 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2947 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2949 error = 2; /* bad password */
2951 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2953 error = 3; /* bad path */
2962 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2965 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2967 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2968 return CM_ERROR_BADOP;
2971 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2973 unsigned short EchoCount, i;
2974 char *data, *outdata;
2977 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2979 for (i=1; i<=EchoCount; i++) {
2980 data = smb_GetSMBData(inp, &dataSize);
2981 smb_SetSMBParm(outp, 0, i);
2982 smb_SetSMBDataLength(outp, dataSize);
2983 outdata = smb_GetSMBData(outp, NULL);
2984 memcpy(outdata, data, dataSize);
2985 smb_SendPacket(vcp, outp);
2991 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2994 long count, minCount, finalCount;
2999 cm_user_t *userp = NULL;
3003 char *rawBuf = NULL;
3005 dos_ptr rawBuf = NULL;
3012 fd = smb_GetSMBParm(inp, 0);
3013 count = smb_GetSMBParm(inp, 3);
3014 minCount = smb_GetSMBParm(inp, 4);
3015 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3017 if (*inp->wctp == 10) {
3018 /* we were sent a request with 64-bit file offsets */
3019 #ifdef AFS_LARGEFILES
3020 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3022 if (LargeIntegerLessThanZero(offset)) {
3023 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3027 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3028 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3031 offset.HighPart = 0;
3035 /* we were sent a request with 32-bit file offsets */
3036 offset.HighPart = 0;
3039 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3040 fd, offset.HighPart, offset.LowPart, count);
3042 fidp = smb_FindFID(vcp, fd, 0);
3046 pid = ((smb_t *) inp)->pid;
3048 LARGE_INTEGER LOffset, LLength;
3051 key = cm_GenerateKey(vcp->vcID, pid, fd);
3053 LOffset.HighPart = offset.HighPart;
3054 LOffset.LowPart = offset.LowPart;
3055 LLength.HighPart = 0;
3056 LLength.LowPart = count;
3058 lock_ObtainMutex(&fidp->scp->mx);
3059 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3060 lock_ReleaseMutex(&fidp->scp->mx);
3066 lock_ObtainMutex(&smb_RawBufLock);
3068 /* Get a raw buf, from head of list */
3069 rawBuf = smb_RawBufs;
3071 smb_RawBufs = *(char **)smb_RawBufs;
3073 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3076 lock_ReleaseMutex(&smb_RawBufLock);
3080 lock_ObtainMutex(&fidp->mx);
3081 if (fidp->flags & SMB_FID_IOCTL)
3083 lock_ReleaseMutex(&fidp->mx);
3085 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3087 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3090 /* Give back raw buffer */
3091 lock_ObtainMutex(&smb_RawBufLock);
3093 *((char **) rawBuf) = smb_RawBufs;
3095 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3098 smb_RawBufs = rawBuf;
3099 lock_ReleaseMutex(&smb_RawBufLock);
3102 smb_ReleaseFID(fidp);
3105 lock_ReleaseMutex(&fidp->mx);
3107 userp = smb_GetUserFromVCP(vcp, inp);
3110 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3112 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3113 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3114 userp, &finalCount, TRUE /* rawFlag */);
3121 cm_ReleaseUser(userp);
3124 smb_ReleaseFID(fidp);
3129 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3131 memset((char *)ncbp, 0, sizeof(NCB));
3133 ncbp->ncb_length = (unsigned short) finalCount;
3134 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3135 ncbp->ncb_lana_num = vcp->lana;
3136 ncbp->ncb_command = NCBSEND;
3137 ncbp->ncb_buffer = rawBuf;
3140 code = Netbios(ncbp);
3142 code = Netbios(ncbp, dos_ncb);
3145 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3148 /* Give back raw buffer */
3149 lock_ObtainMutex(&smb_RawBufLock);
3151 *((char **) rawBuf) = smb_RawBufs;
3153 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3156 smb_RawBufs = rawBuf;
3157 lock_ReleaseMutex(&smb_RawBufLock);
3163 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3165 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3170 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3172 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3177 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3184 int VistaProtoIndex;
3185 int protoIndex; /* index we're using */
3190 char protocol_array[10][1024]; /* protocol signature of the client */
3191 int caps; /* capabilities */
3194 TIME_ZONE_INFORMATION tzi;
3196 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3199 namep = smb_GetSMBData(inp, &dbytes);
3202 coreProtoIndex = -1; /* not found */
3205 VistaProtoIndex = -1;
3206 while(namex < dbytes) {
3207 osi_Log1(smb_logp, "Protocol %s",
3208 osi_LogSaveString(smb_logp, namep+1));
3209 strcpy(protocol_array[tcounter], namep+1);
3211 /* namep points at the first protocol, or really, a 0x02
3212 * byte preceding the null-terminated ASCII name.
3214 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3215 coreProtoIndex = tcounter;
3217 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3218 v3ProtoIndex = tcounter;
3220 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3221 NTProtoIndex = tcounter;
3223 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3224 VistaProtoIndex = tcounter;
3227 /* compute size of protocol entry */
3228 entryLength = (int)strlen(namep+1);
3229 entryLength += 2; /* 0x02 bytes and null termination */
3231 /* advance over this protocol entry */
3232 namex += entryLength;
3233 namep += entryLength;
3234 tcounter++; /* which proto entry we're looking at */
3237 lock_ObtainMutex(&vcp->mx);
3239 if (VistaProtoIndex != -1) {
3240 protoIndex = VistaProtoIndex;
3241 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3244 if (NTProtoIndex != -1) {
3245 protoIndex = NTProtoIndex;
3246 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3248 else if (v3ProtoIndex != -1) {
3249 protoIndex = v3ProtoIndex;
3250 vcp->flags |= SMB_VCFLAG_USEV3;
3252 else if (coreProtoIndex != -1) {
3253 protoIndex = coreProtoIndex;
3254 vcp->flags |= SMB_VCFLAG_USECORE;
3256 else protoIndex = -1;
3257 lock_ReleaseMutex(&vcp->mx);
3259 if (protoIndex == -1)
3260 return CM_ERROR_INVAL;
3261 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3262 smb_SetSMBParm(outp, 0, protoIndex);
3263 if (smb_authType != SMB_AUTH_NONE) {
3264 smb_SetSMBParmByte(outp, 1,
3265 NEGOTIATE_SECURITY_USER_LEVEL |
3266 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3268 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3270 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3271 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3272 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3273 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3274 /* The session key is not a well documented field however most clients
3275 * will echo back the session key to the server. Currently we are using
3276 * the same value for all sessions. We should generate a random value
3277 * and store it into the vcp
3279 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3280 smb_SetSMBParm(outp, 8, 1);
3282 * Tried changing the capabilities to support for W2K - defect 117695
3283 * Maybe something else needs to be changed here?
3287 smb_SetSMBParmLong(outp, 9, 0x43fd);
3289 smb_SetSMBParmLong(outp, 9, 0x251);
3292 * 32-bit error codes *
3297 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3299 NTNEGOTIATE_CAPABILITY_DFS |
3301 #ifdef AFS_LARGEFILES
3302 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3304 NTNEGOTIATE_CAPABILITY_NTFIND |
3305 NTNEGOTIATE_CAPABILITY_RAWMODE |
3306 NTNEGOTIATE_CAPABILITY_NTSMB;
3308 if ( smb_authType == SMB_AUTH_EXTENDED )
3309 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3311 smb_SetSMBParmLong(outp, 9, caps);
3313 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3314 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3315 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3317 GetTimeZoneInformation(&tzi);
3318 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3320 if (smb_authType == SMB_AUTH_NTLM) {
3321 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3322 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3323 /* paste in encryption key */
3324 datap = smb_GetSMBData(outp, NULL);
3325 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3326 /* and the faux domain name */
3327 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3328 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3332 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3334 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3336 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3338 datap = smb_GetSMBData(outp, NULL);
3339 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3342 datap += sizeof(smb_ServerGUID);
3343 memcpy(datap, secBlob, secBlobLength);
3347 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3348 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3351 else if (v3ProtoIndex != -1) {
3352 smb_SetSMBParm(outp, 0, protoIndex);
3354 /* NOTE: Extended authentication cannot be negotiated with v3
3355 * therefore we fail over to NTLM
3357 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3358 smb_SetSMBParm(outp, 1,
3359 NEGOTIATE_SECURITY_USER_LEVEL |
3360 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3362 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3364 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3365 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3366 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3367 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3368 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3369 smb_SetSMBParm(outp, 7, 1);
3371 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3372 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3373 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3375 GetTimeZoneInformation(&tzi);
3376 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3378 /* NOTE: Extended authentication cannot be negotiated with v3
3379 * therefore we fail over to NTLM
3381 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3382 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3383 smb_SetSMBParm(outp, 12, 0); /* resvd */
3384 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3385 datap = smb_GetSMBData(outp, NULL);
3386 /* paste in a new encryption key */
3387 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3388 /* and the faux domain name */
3389 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3391 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3392 smb_SetSMBParm(outp, 12, 0); /* resvd */
3393 smb_SetSMBDataLength(outp, 0);
3396 else if (coreProtoIndex != -1) { /* not really supported anymore */
3397 smb_SetSMBParm(outp, 0, protoIndex);
3398 smb_SetSMBDataLength(outp, 0);
3403 void smb_CheckVCs(void)
3405 smb_vc_t * vcp, *nextp;
3406 smb_packet_t * outp = GetPacket();
3409 lock_ObtainWrite(&smb_rctLock);
3410 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3412 if (vcp->magic != SMB_VC_MAGIC)
3413 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3414 __FILE__, __LINE__);
3418 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3421 smb_HoldVCNoLock(vcp);
3423 smb_HoldVCNoLock(nextp);
3424 smb_FormatResponsePacket(vcp, NULL, outp);
3425 smbp = (smb_t *)outp;
3426 outp->inCom = smbp->com = 0x2b /* Echo */;
3434 smb_SetSMBParm(outp, 0, 0);
3435 smb_SetSMBDataLength(outp, 0);
3436 lock_ReleaseWrite(&smb_rctLock);
3438 smb_SendPacket(vcp, outp);
3440 lock_ObtainWrite(&smb_rctLock);
3441 smb_ReleaseVCNoLock(vcp);
3443 smb_ReleaseVCNoLock(nextp);
3445 lock_ReleaseWrite(&smb_rctLock);
3446 smb_FreePacket(outp);
3449 void smb_Daemon(void *parmp)
3451 afs_uint32 count = 0;
3452 smb_username_t **unpp;
3455 while(smbShutdownFlag == 0) {
3459 if (smbShutdownFlag == 1)
3462 if ((count % 72) == 0) { /* every five minutes */
3464 time_t old_localZero = smb_localZero;
3466 /* Initialize smb_localZero */
3467 myTime.tm_isdst = -1; /* compute whether on DST or not */
3468 myTime.tm_year = 70;
3474 smb_localZero = mktime(&myTime);
3476 #ifndef USE_NUMERIC_TIME_CONV
3477 smb_CalculateNowTZ();
3478 #endif /* USE_NUMERIC_TIME_CONV */
3479 #ifdef AFS_FREELANCE
3480 if ( smb_localZero != old_localZero )
3481 cm_noteLocalMountPointChange();
3487 /* GC smb_username_t objects that will no longer be used */
3489 lock_ObtainWrite(&smb_rctLock);
3490 for ( unpp=&usernamesp; *unpp; ) {
3492 smb_username_t *unp;
3494 lock_ObtainMutex(&(*unpp)->mx);
3495 if ( (*unpp)->refCount > 0 ||
3496 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3497 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3499 else if (!smb_LogoffTokenTransfer ||
3500 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3502 lock_ReleaseMutex(&(*unpp)->mx);
3510 lock_FinalizeMutex(&unp->mx);
3516 lock_ReleaseWrite(&smb_rctLock);
3517 cm_ReleaseUser(userp);
3518 lock_ObtainWrite(&smb_rctLock);
3521 unpp = &(*unpp)->nextp;
3524 lock_ReleaseWrite(&smb_rctLock);
3526 /* XXX GC dir search entries */
3530 void smb_WaitingLocksDaemon()
3532 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3533 smb_waitingLock_t *wl, *wlNext;
3536 smb_packet_t *inp, *outp;
3540 while (smbShutdownFlag == 0) {
3541 lock_ObtainWrite(&smb_globalLock);
3542 nwlRequest = smb_allWaitingLocks;
3543 if (nwlRequest == NULL) {
3544 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3549 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3556 lock_ObtainWrite(&smb_globalLock);
3558 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3560 wlRequest = nwlRequest;
3561 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3562 lock_ReleaseWrite(&smb_globalLock);
3566 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3567 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3570 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3572 /* wl->state is either _DONE or _WAITING. _ERROR
3573 would no longer be on the queue. */
3574 code = cm_RetryLock( wl->lockp,
3575 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3578 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3579 } else if (code != CM_ERROR_WOULDBLOCK) {
3580 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3585 if (code == CM_ERROR_WOULDBLOCK) {
3588 if (wlRequest->timeRemaining != 0xffffffff
3589 && (wlRequest->timeRemaining -= 1000) < 0)
3601 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3604 scp = wlRequest->scp;
3608 lock_ObtainMutex(&scp->mx);
3610 for (wl = wlRequest->locks; wl; wl = wlNext) {
3611 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3613 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3614 wl->LLength, wl->key, NULL, &req);
3616 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3621 lock_ReleaseMutex(&scp->mx);
3625 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3628 for (wl = wlRequest->locks; wl; wl = wlNext) {
3629 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3630 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3635 vcp = wlRequest->vcp;
3636 inp = wlRequest->inp;
3637 outp = wlRequest->outp;
3639 ncbp->ncb_length = inp->ncb_length;
3640 inp->spacep = cm_GetSpace();
3642 /* Remove waitingLock from list */
3643 lock_ObtainWrite(&smb_globalLock);
3644 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3646 lock_ReleaseWrite(&smb_globalLock);
3648 /* Resume packet processing */
3650 smb_SetSMBDataLength(outp, 0);
3651 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3652 outp->resumeCode = code;
3654 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3657 cm_FreeSpace(inp->spacep);
3658 smb_FreePacket(inp);
3659 smb_FreePacket(outp);
3661 cm_ReleaseSCache(wlRequest->scp);
3664 } while (nwlRequest && smbShutdownFlag == 0);
3669 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3671 osi_Log0(smb_logp, "SMB receive get disk attributes");
3673 smb_SetSMBParm(outp, 0, 32000);
3674 smb_SetSMBParm(outp, 1, 64);
3675 smb_SetSMBParm(outp, 2, 1024);
3676 smb_SetSMBParm(outp, 3, 30000);
3677 smb_SetSMBParm(outp, 4, 0);
3678 smb_SetSMBDataLength(outp, 0);
3682 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3686 unsigned short newTid;
3687 char shareName[256];
3695 osi_Log0(smb_logp, "SMB receive tree connect");
3697 /* parse input parameters */
3698 tp = smb_GetSMBData(inp, NULL);
3699 pathp = smb_ParseASCIIBlock(tp, &tp);
3700 if (smb_StoreAnsiFilenames)
3701 OemToChar(pathp,pathp);
3702 passwordp = smb_ParseASCIIBlock(tp, &tp);
3703 tp = strrchr(pathp, '\\');
3705 return CM_ERROR_BADSMB;
3706 strcpy(shareName, tp+1);
3708 lock_ObtainMutex(&vcp->mx);
3709 newTid = vcp->tidCounter++;
3710 lock_ReleaseMutex(&vcp->mx);
3712 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3713 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3714 userp = smb_GetUserFromUID(uidp);
3715 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3717 smb_ReleaseUID(uidp);
3719 smb_ReleaseTID(tidp);
3720 return CM_ERROR_BADSHARENAME;
3722 lock_ObtainMutex(&tidp->mx);
3723 tidp->userp = userp;
3724 tidp->pathname = sharePath;
3725 lock_ReleaseMutex(&tidp->mx);
3726 smb_ReleaseTID(tidp);
3728 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3729 smb_SetSMBParm(rsp, 1, newTid);
3730 smb_SetSMBDataLength(rsp, 0);
3732 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3736 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3740 if (*inp++ != 0x1) return NULL;
3741 tlen = inp[0] + (inp[1]<<8);
3742 inp += 2; /* skip length field */
3745 *chainpp = inp + tlen;
3748 if (lengthp) *lengthp = tlen;
3753 /* set maskp to the mask part of the incoming path.
3754 * Mask is 11 bytes long (8.3 with the dot elided).
3755 * Returns true if succeeds with a valid name, otherwise it does
3756 * its best, but returns false.
3758 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3766 /* starts off valid */
3769 /* mask starts out all blanks */
3770 memset(maskp, ' ', 11);
3772 /* find last backslash, or use whole thing if there is none */
3773 tp = strrchr(pathp, '\\');
3774 if (!tp) tp = pathp;
3775 else tp++; /* skip slash */
3779 /* names starting with a dot are illegal */
3780 if (*tp == '.') valid8Dot3 = 0;
3784 if (tc == 0) return valid8Dot3;
3785 if (tc == '.' || tc == '"') break;
3786 if (i < 8) *up++ = tc;
3787 else valid8Dot3 = 0;
3790 /* if we get here, tp point after the dot */
3791 up = maskp+8; /* ext goes here */
3798 if (tc == '.' || tc == '"')
3801 /* copy extension if not too long */
3811 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3821 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3823 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3827 /* otherwise, we have a valid 8.3 name; see if we have a match,
3828 * treating '?' as a wildcard in maskp (but not in the file name).
3830 tp1 = umask; /* real name, in mask format */
3831 tp2 = maskp; /* mask, in mask format */
3832 for(i=0; i<11; i++) {
3833 tc1 = *tp1++; /* char from real name */
3834 tc2 = *tp2++; /* char from mask */
3835 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3836 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3839 if (tc2 == '?' && tc1 != ' ')
3846 /* we got a match */
3850 char *smb_FindMask(char *pathp)
3854 tp = strrchr(pathp, '\\'); /* find last slash */
3857 return tp+1; /* skip the slash */
3859 return pathp; /* no slash, return the entire path */
3862 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3864 unsigned char *pathp;
3866 unsigned char mask[11];
3867 unsigned char *statBlockp;
3868 unsigned char initStatBlock[21];
3871 osi_Log0(smb_logp, "SMB receive search volume");
3873 /* pull pathname and stat block out of request */
3874 tp = smb_GetSMBData(inp, NULL);
3875 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3876 osi_assert(pathp != NULL);
3877 if (smb_StoreAnsiFilenames)
3878 OemToChar(pathp,pathp);
3879 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3880 osi_assert(statBlockp != NULL);
3882 statBlockp = initStatBlock;
3886 /* for returning to caller */
3887 smb_Get8Dot3MaskFromPath(mask, pathp);
3889 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3890 tp = smb_GetSMBData(outp, NULL);
3892 *tp++ = 43; /* bytes in a dir entry */
3893 *tp++ = 0; /* high byte in counter */
3895 /* now marshall the dir entry, starting with the search status */
3896 *tp++ = statBlockp[0]; /* Reserved */
3897 memcpy(tp, mask, 11); tp += 11; /* FileName */
3899 /* now pass back server use info, with 1st byte non-zero */
3901 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3903 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3905 *tp++ = 0x8; /* attribute: volume */
3915 /* 4 byte file size */
3921 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3922 memset(tp, ' ', 13);
3925 /* set the length of the data part of the packet to 43 + 3, for the dir
3926 * entry plus the 5 and the length fields.
3928 smb_SetSMBDataLength(outp, 46);
3932 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3933 cm_user_t *userp, cm_req_t *reqp)
3941 smb_dirListPatch_t *patchp;
3942 smb_dirListPatch_t *npatchp;
3944 for (patchp = *dirPatchespp; patchp; patchp =
3945 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3947 dptr = patchp->dptr;
3949 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3951 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3952 *dptr++ = SMB_ATTR_HIDDEN;
3955 lock_ObtainMutex(&scp->mx);
3956 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3957 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3959 lock_ReleaseMutex(&scp->mx);
3960 cm_ReleaseSCache(scp);
3961 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3962 *dptr++ = SMB_ATTR_HIDDEN;
3966 attr = smb_Attributes(scp);
3967 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3968 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3969 attr |= SMB_ATTR_HIDDEN;
3973 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3976 shortTemp = (unsigned short) (dosTime & 0xffff);
3977 *((u_short *)dptr) = shortTemp;
3980 /* and copy out date */
3981 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3982 *((u_short *)dptr) = shortTemp;
3985 /* copy out file length */
3986 *((u_long *)dptr) = scp->length.LowPart;
3988 lock_ReleaseMutex(&scp->mx);
3989 cm_ReleaseSCache(scp);
3992 /* now free the patches */
3993 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3994 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3998 /* and mark the list as empty */
3999 *dirPatchespp = NULL;
4004 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4013 smb_dirListPatch_t *dirListPatchesp;
4014 smb_dirListPatch_t *curPatchp;
4018 osi_hyper_t dirLength;
4019 osi_hyper_t bufferOffset;
4020 osi_hyper_t curOffset;
4022 unsigned char *inCookiep;
4023 smb_dirSearch_t *dsp;
4027 unsigned long clientCookie;
4028 cm_pageHeader_t *pageHeaderp;
4029 cm_user_t *userp = NULL;
4036 long nextEntryCookie;
4037 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4038 char resByte; /* reserved byte from the cookie */
4039 char *op; /* output data ptr */
4040 char *origOp; /* original value of op */
4041 cm_space_t *spacep; /* for pathname buffer */
4052 maxCount = smb_GetSMBParm(inp, 0);
4054 dirListPatchesp = NULL;
4056 caseFold = CM_FLAG_CASEFOLD;
4058 tp = smb_GetSMBData(inp, NULL);
4059 pathp = smb_ParseASCIIBlock(tp, &tp);
4060 if (smb_StoreAnsiFilenames)
4061 OemToChar(pathp,pathp);
4062 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4064 /* bail out if request looks bad */
4065 if (!tp || !pathp) {
4066 return CM_ERROR_BADSMB;
4069 /* We can handle long names */
4070 if (vcp->flags & SMB_VCFLAG_USENT)
4071 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4073 /* make sure we got a whole search status */
4074 if (dataLength < 21) {
4075 nextCookie = 0; /* start at the beginning of the dir */
4078 attribute = smb_GetSMBParm(inp, 1);
4080 /* handle volume info in another function */
4081 if (attribute & 0x8)
4082 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4084 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4085 maxCount, osi_LogSaveString(smb_logp, pathp));
4087 if (*pathp == 0) { /* null pathp, treat as root dir */
4088 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4089 return CM_ERROR_NOFILES;
4093 dsp = smb_NewDirSearch(0);
4094 dsp->attribute = attribute;
4095 smb_Get8Dot3MaskFromPath(mask, pathp);
4096 memcpy(dsp->mask, mask, 11);
4098 /* track if this is likely to match a lot of entries */
4099 if (smb_IsStarMask(mask))
4104 /* pull the next cookie value out of the search status block */
4105 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4106 + (inCookiep[16]<<24);
4107 dsp = smb_FindDirSearch(inCookiep[12]);
4109 /* can't find dir search status; fatal error */
4110 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4111 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4112 return CM_ERROR_BADFD;
4114 attribute = dsp->attribute;
4115 resByte = inCookiep[0];
4117 /* copy out client cookie, in host byte order. Don't bother
4118 * interpreting it, since we're just passing it through, anyway.
4120 memcpy(&clientCookie, &inCookiep[17], 4);
4122 memcpy(mask, dsp->mask, 11);
4124 /* assume we're doing a star match if it has continued for more
4130 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4131 nextCookie, dsp->cookie, attribute);
4133 userp = smb_GetUserFromVCP(vcp, inp);
4135 /* try to get the vnode for the path name next */
4136 lock_ObtainMutex(&dsp->mx);
4142 spacep = inp->spacep;
4143 smb_StripLastComponent(spacep->data, NULL, pathp);
4144 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4146 lock_ReleaseMutex(&dsp->mx);
4147 cm_ReleaseUser(userp);
4148 smb_DeleteDirSearch(dsp);
4149 smb_ReleaseDirSearch(dsp);
4150 return CM_ERROR_NOFILES;
4152 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4153 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4156 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4157 cm_ReleaseSCache(scp);
4158 lock_ReleaseMutex(&dsp->mx);
4159 cm_ReleaseUser(userp);
4160 smb_DeleteDirSearch(dsp);
4161 smb_ReleaseDirSearch(dsp);
4162 if ( WANTS_DFS_PATHNAMES(inp) )
4163 return CM_ERROR_PATH_NOT_COVERED;
4165 return CM_ERROR_BADSHARENAME;
4167 #endif /* DFS_SUPPORT */
4170 /* we need one hold for the entry we just stored into,
4171 * and one for our own processing. When we're done with this
4172 * function, we'll drop the one for our own processing.
4173 * We held it once from the namei call, and so we do another hold
4177 lock_ObtainMutex(&scp->mx);
4178 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4179 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4180 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4181 dsp->flags |= SMB_DIRSEARCH_BULKST;
4182 dsp->scp->bulkStatProgress = hzero;
4184 lock_ReleaseMutex(&scp->mx);
4187 lock_ReleaseMutex(&dsp->mx);
4189 cm_ReleaseUser(userp);
4190 smb_DeleteDirSearch(dsp);
4191 smb_ReleaseDirSearch(dsp);
4195 /* reserves space for parameter; we'll adjust it again later to the
4196 * real count of the # of entries we returned once we've actually
4197 * assembled the directory listing.
4199 smb_SetSMBParm(outp, 0, 0);
4201 /* get the directory size */
4202 lock_ObtainMutex(&scp->mx);
4203 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4204 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4206 lock_ReleaseMutex(&scp->mx);
4207 cm_ReleaseSCache(scp);
4208 cm_ReleaseUser(userp);
4209 smb_DeleteDirSearch(dsp);
4210 smb_ReleaseDirSearch(dsp);
4214 dirLength = scp->length;
4216 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4217 curOffset.HighPart = 0;
4218 curOffset.LowPart = nextCookie;
4219 origOp = op = smb_GetSMBData(outp, NULL);
4220 /* and write out the basic header */
4221 *op++ = 5; /* variable block */
4222 op += 2; /* skip vbl block length; we'll fill it in later */
4226 /* make sure that curOffset.LowPart doesn't point to the first
4227 * 32 bytes in the 2nd through last dir page, and that it doesn't
4228 * point at the first 13 32-byte chunks in the first dir page,
4229 * since those are dir and page headers, and don't contain useful
4232 temp = curOffset.LowPart & (2048-1);
4233 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4234 /* we're in the first page */
4235 if (temp < 13*32) temp = 13*32;
4238 /* we're in a later dir page */
4239 if (temp < 32) temp = 32;
4242 /* make sure the low order 5 bits are zero */
4245 /* now put temp bits back ito curOffset.LowPart */
4246 curOffset.LowPart &= ~(2048-1);
4247 curOffset.LowPart |= temp;
4249 /* check if we've returned all the names that will fit in the
4252 if (returnedNames >= maxCount) {
4253 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4254 returnedNames, maxCount);
4258 /* check if we've passed the dir's EOF */
4259 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4261 /* see if we can use the bufferp we have now; compute in which page
4262 * the current offset would be, and check whether that's the offset
4263 * of the buffer we have. If not, get the buffer.
4265 thyper.HighPart = curOffset.HighPart;
4266 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4267 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4270 buf_Release(bufferp);
4273 lock_ReleaseMutex(&scp->mx);
4274 lock_ObtainRead(&scp->bufCreateLock);
4275 code = buf_Get(scp, &thyper, &bufferp);
4276 lock_ReleaseRead(&scp->bufCreateLock);
4277 lock_ObtainMutex(&dsp->mx);
4279 /* now, if we're doing a star match, do bulk fetching of all of
4280 * the status info for files in the dir.
4283 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4284 lock_ObtainMutex(&scp->mx);
4285 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4286 LargeIntegerGreaterThanOrEqualTo(thyper,
4287 scp->bulkStatProgress)) {
4288 /* Don't bulk stat if risking timeout */
4289 int now = GetTickCount();
4290 if (now - req.startTime > RDRtimeout) {
4291 scp->bulkStatProgress = thyper;
4292 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4293 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4294 dsp->scp->bulkStatProgress = hzero;
4296 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4299 lock_ObtainMutex(&scp->mx);
4301 lock_ReleaseMutex(&dsp->mx);
4303 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4307 bufferOffset = thyper;
4309 /* now get the data in the cache */
4311 code = cm_SyncOp(scp, bufferp, userp, &req,
4313 CM_SCACHESYNC_NEEDCALLBACK |
4314 CM_SCACHESYNC_READ);
4316 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4320 if (cm_HaveBuffer(scp, bufferp, 0)) {
4321 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4325 /* otherwise, load the buffer and try again */
4326 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4328 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4329 scp, bufferp, code);
4334 buf_Release(bufferp);
4338 } /* if (wrong buffer) ... */
4340 /* now we have the buffer containing the entry we're interested in; copy
4341 * it out if it represents a non-deleted entry.
4343 entryInDir = curOffset.LowPart & (2048-1);
4344 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4346 /* page header will help tell us which entries are free. Page header
4347 * can change more often than once per buffer, since AFS 3 dir page size
4348 * may be less than (but not more than a buffer package buffer.
4350 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4351 temp &= ~(2048 - 1); /* turn off intra-page bits */
4352 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4354 /* now determine which entry we're looking at in the page. If it is
4355 * free (there's a free bitmap at the start of the dir), we should
4356 * skip these 32 bytes.
4358 slotInPage = (entryInDir & 0x7e0) >> 5;
4359 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4360 /* this entry is free */
4361 numDirChunks = 1; /* only skip this guy */
4365 tp = bufferp->datap + entryInBuffer;
4366 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4368 /* while we're here, compute the next entry's location, too,
4369 * since we'll need it when writing out the cookie into the dir
4372 * XXXX Probably should do more sanity checking.
4374 numDirChunks = cm_NameEntries(dep->name, NULL);
4376 /* compute the offset of the cookie representing the next entry */
4377 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4379 /* Compute 8.3 name if necessary */
4380 actualName = dep->name;
4381 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4382 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4383 actualName = shortName;
4386 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4387 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4388 osi_LogSaveString(smb_logp, actualName));
4390 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4391 /* this is one of the entries to use: it is not deleted
4392 * and it matches the star pattern we're looking for.
4395 /* Eliminate entries that don't match requested
4398 /* no hidden files */
4399 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4400 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4404 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4406 /* We have already done the cm_TryBulkStat above */
4407 fid.cell = scp->fid.cell;
4408 fid.volume = scp->fid.volume;
4409 fid.vnode = ntohl(dep->fid.vnode);
4410 fid.unique = ntohl(dep->fid.unique);
4411 fileType = cm_FindFileType(&fid);
4412 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4413 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4415 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4416 fileType == CM_SCACHETYPE_DFSLINK ||
4417 fileType == CM_SCACHETYPE_INVALID)
4418 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4423 memcpy(op, mask, 11); op += 11;
4424 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4425 *op++ = (char)(nextEntryCookie & 0xff);
4426 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4427 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4428 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4429 memcpy(op, &clientCookie, 4); op += 4;
4431 /* now we emit the attribute. This is sort of tricky,
4432 * since we need to really stat the file to find out
4433 * what type of entry we've got. Right now, we're
4434 * copying out data from a buffer, while holding the
4435 * scp locked, so it isn't really convenient to stat
4436 * something now. We'll put in a place holder now,
4437 * and make a second pass before returning this to get
4438 * the real attributes. So, we just skip the data for
4439 * now, and adjust it later. We allocate a patch
4440 * record to make it easy to find this point later.
4441 * The replay will happen at a time when it is safe to
4442 * unlock the directory.
4444 curPatchp = malloc(sizeof(*curPatchp));
4445 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4446 curPatchp->dptr = op;
4447 curPatchp->fid.cell = scp->fid.cell;
4448 curPatchp->fid.volume = scp->fid.volume;
4449 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4450 curPatchp->fid.unique = ntohl(dep->fid.unique);
4452 /* do hidden attribute here since name won't be around when applying
4456 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4457 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4459 curPatchp->flags = 0;
4461 op += 9; /* skip attr, time, date and size */
4463 /* zero out name area. The spec says to pad with
4464 * spaces, but Samba doesn't, and neither do we.
4468 /* finally, we get to copy out the name; we know that
4469 * it fits in 8.3 or the pattern wouldn't match, but it
4470 * never hurts to be sure.
4472 strncpy(op, actualName, 13);
4473 if (smb_StoreAnsiFilenames)
4476 /* Uppercase if requested by client */
4477 if (!KNOWS_LONG_NAMES(inp))
4482 /* now, adjust the # of entries copied */
4484 } /* if we're including this name */
4487 /* and adjust curOffset to be where the new cookie is */
4488 thyper.HighPart = 0;
4489 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4490 curOffset = LargeIntegerAdd(thyper, curOffset);
4491 } /* while copying data for dir listing */
4493 /* release the mutex */
4494 lock_ReleaseMutex(&scp->mx);
4495 if (bufferp) buf_Release(bufferp);
4497 /* apply and free last set of patches; if not doing a star match, this
4498 * will be empty, but better safe (and freeing everything) than sorry.
4500 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4502 /* special return code for unsuccessful search */
4503 if (code == 0 && dataLength < 21 && returnedNames == 0)
4504 code = CM_ERROR_NOFILES;
4506 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4507 returnedNames, code);
4510 smb_DeleteDirSearch(dsp);
4511 smb_ReleaseDirSearch(dsp);
4512 cm_ReleaseSCache(scp);
4513 cm_ReleaseUser(userp);
4517 /* finalize the output buffer */
4518 smb_SetSMBParm(outp, 0, returnedNames);
4519 temp = (long) (op - origOp);
4520 smb_SetSMBDataLength(outp, temp);
4522 /* the data area is a variable block, which has a 5 (already there)
4523 * followed by the length of the # of data bytes. We now know this to
4524 * be "temp," although that includes the 3 bytes of vbl block header.
4525 * Deduct for them and fill in the length field.
4527 temp -= 3; /* deduct vbl block info */
4528 osi_assert(temp == (43 * returnedNames));
4529 origOp[1] = (char)(temp & 0xff);
4530 origOp[2] = (char)((temp>>8) & 0xff);
4531 if (returnedNames == 0)
4532 smb_DeleteDirSearch(dsp);
4533 smb_ReleaseDirSearch(dsp);
4534 cm_ReleaseSCache(scp);
4535 cm_ReleaseUser(userp);
4539 /* verify that this is a valid path to a directory. I don't know why they
4540 * don't use the get file attributes call.
4542 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4546 cm_scache_t *rootScp;
4547 cm_scache_t *newScp;
4556 pathp = smb_GetSMBData(inp, NULL);
4557 pathp = smb_ParseASCIIBlock(pathp, NULL);
4559 return CM_ERROR_BADFD;
4560 if (smb_StoreAnsiFilenames)
4561 OemToChar(pathp,pathp);
4562 osi_Log1(smb_logp, "SMB receive check path %s",
4563 osi_LogSaveString(smb_logp, pathp));
4565 rootScp = cm_data.rootSCachep;
4567 userp = smb_GetUserFromVCP(vcp, inp);
4569 caseFold = CM_FLAG_CASEFOLD;
4571 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4573 cm_ReleaseUser(userp);
4574 return CM_ERROR_NOSUCHPATH;
4576 code = cm_NameI(rootScp, pathp,
4577 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4578 userp, tidPathp, &req, &newScp);
4581 cm_ReleaseUser(userp);
4586 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4587 cm_ReleaseSCache(newScp);
4588 cm_ReleaseUser(userp);
4589 if ( WANTS_DFS_PATHNAMES(inp) )
4590 return CM_ERROR_PATH_NOT_COVERED;
4592 return CM_ERROR_BADSHARENAME;
4594 #endif /* DFS_SUPPORT */
4596 /* now lock the vnode with a callback; returns with newScp locked */
4597 lock_ObtainMutex(&newScp->mx);
4598 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4599 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4600 if (code && code != CM_ERROR_NOACCESS) {
4601 lock_ReleaseMutex(&newScp->mx);
4602 cm_ReleaseSCache(newScp);
4603 cm_ReleaseUser(userp);
4607 attrs = smb_Attributes(newScp);
4609 if (!(attrs & SMB_ATTR_DIRECTORY))
4610 code = CM_ERROR_NOTDIR;
4612 lock_ReleaseMutex(&newScp->mx);
4614 cm_ReleaseSCache(newScp);
4615 cm_ReleaseUser(userp);
4619 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4623 cm_scache_t *rootScp;
4624 unsigned short attribute;
4626 cm_scache_t *newScp;
4635 /* decode basic attributes we're passed */
4636 attribute = smb_GetSMBParm(inp, 0);
4637 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4639 pathp = smb_GetSMBData(inp, NULL);
4640 pathp = smb_ParseASCIIBlock(pathp, NULL);
4642 return CM_ERROR_BADSMB;
4643 if (smb_StoreAnsiFilenames)
4644 OemToChar(pathp,pathp);
4646 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4647 dosTime, attribute);
4649 rootScp = cm_data.rootSCachep;
4651 userp = smb_GetUserFromVCP(vcp, inp);
4653 caseFold = CM_FLAG_CASEFOLD;
4655 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4657 cm_ReleaseUser(userp);
4658 return CM_ERROR_NOSUCHFILE;
4660 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4661 tidPathp, &req, &newScp);
4664 cm_ReleaseUser(userp);
4669 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4670 cm_ReleaseSCache(newScp);
4671 cm_ReleaseUser(userp);
4672 if ( WANTS_DFS_PATHNAMES(inp) )
4673 return CM_ERROR_PATH_NOT_COVERED;
4675 return CM_ERROR_BADSHARENAME;
4677 #endif /* DFS_SUPPORT */
4679 /* now lock the vnode with a callback; returns with newScp locked; we
4680 * need the current status to determine what the new status is, in some
4683 lock_ObtainMutex(&newScp->mx);
4684 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4685 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4687 lock_ReleaseMutex(&newScp->mx);
4688 cm_ReleaseSCache(newScp);
4689 cm_ReleaseUser(userp);
4693 /* Check for RO volume */
4694 if (newScp->flags & CM_SCACHEFLAG_RO) {
4695 lock_ReleaseMutex(&newScp->mx);
4696 cm_ReleaseSCache(newScp);
4697 cm_ReleaseUser(userp);
4698 return CM_ERROR_READONLY;
4701 /* prepare for setattr call */
4704 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4705 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4707 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4708 /* we're told to make a writable file read-only */
4709 attr.unixModeBits = newScp->unixModeBits & ~0222;
4710 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4712 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4713 /* we're told to make a read-only file writable */
4714 attr.unixModeBits = newScp->unixModeBits | 0222;
4715 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4717 lock_ReleaseMutex(&newScp->mx);
4719 /* now call setattr */
4721 code = cm_SetAttr(newScp, &attr, userp, &req);
4725 cm_ReleaseSCache(newScp);
4726 cm_ReleaseUser(userp);
4731 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4735 cm_scache_t *rootScp;
4736 cm_scache_t *newScp, *dscp;
4748 pathp = smb_GetSMBData(inp, NULL);
4749 pathp = smb_ParseASCIIBlock(pathp, NULL);
4751 return CM_ERROR_BADSMB;
4753 if (*pathp == 0) /* null path */
4756 if (smb_StoreAnsiFilenames)
4757 OemToChar(pathp,pathp);
4759 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4760 osi_LogSaveString(smb_logp, pathp));
4762 rootScp = cm_data.rootSCachep;
4764 userp = smb_GetUserFromVCP(vcp, inp);
4766 /* we shouldn't need this for V3 requests, but we seem to */
4767 caseFold = CM_FLAG_CASEFOLD;
4769 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4771 cm_ReleaseUser(userp);
4772 return CM_ERROR_NOSUCHFILE;
4776 * XXX Strange hack XXX
4778 * As of Patch 5 (16 July 97), we are having the following problem:
4779 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4780 * requests to look up "desktop.ini" in all the subdirectories.
4781 * This can cause zillions of timeouts looking up non-existent cells
4782 * and volumes, especially in the top-level directory.
4784 * We have not found any way to avoid this or work around it except
4785 * to explicitly ignore the requests for mount points that haven't
4786 * yet been evaluated and for directories that haven't yet been
4789 * We should modify this hack to provide a fake desktop.ini file
4790 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4792 spacep = inp->spacep;
4793 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4794 #ifndef SPECIAL_FOLDERS
4795 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4796 code = cm_NameI(rootScp, spacep->data,
4797 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4798 userp, tidPathp, &req, &dscp);
4801 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4802 if ( WANTS_DFS_PATHNAMES(inp) )
4803 return CM_ERROR_PATH_NOT_COVERED;
4805 return CM_ERROR_BADSHARENAME;
4807 #endif /* DFS_SUPPORT */
4808 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4809 code = CM_ERROR_NOSUCHFILE;
4810 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4811 cm_buf_t *bp = buf_Find(dscp, &hzero);
4815 code = CM_ERROR_NOSUCHFILE;
4817 cm_ReleaseSCache(dscp);
4819 cm_ReleaseUser(userp);
4824 #endif /* SPECIAL_FOLDERS */
4826 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4827 tidPathp, &req, &newScp);
4829 cm_ReleaseUser(userp);
4834 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4835 cm_ReleaseSCache(newScp);
4836 cm_ReleaseUser(userp);
4837 if ( WANTS_DFS_PATHNAMES(inp) )
4838 return CM_ERROR_PATH_NOT_COVERED;
4840 return CM_ERROR_BADSHARENAME;
4842 #endif /* DFS_SUPPORT */
4844 /* now lock the vnode with a callback; returns with newScp locked */
4845 lock_ObtainMutex(&newScp->mx);
4846 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4847 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4849 lock_ReleaseMutex(&newScp->mx);
4850 cm_ReleaseSCache(newScp);
4851 cm_ReleaseUser(userp);
4856 /* use smb_Attributes instead. Also the fact that a file is
4857 * in a readonly volume doesn't mean it shojuld be marked as RO
4859 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4860 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4861 newScp->fileType == CM_SCACHETYPE_INVALID)
4862 attrs = SMB_ATTR_DIRECTORY;
4865 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4866 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4868 attrs = smb_Attributes(newScp);
4871 smb_SetSMBParm(outp, 0, attrs);
4873 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4874 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4875 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4876 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4877 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4878 smb_SetSMBParm(outp, 5, 0);
4879 smb_SetSMBParm(outp, 6, 0);
4880 smb_SetSMBParm(outp, 7, 0);
4881 smb_SetSMBParm(outp, 8, 0);
4882 smb_SetSMBParm(outp, 9, 0);
4883 smb_SetSMBDataLength(outp, 0);
4884 lock_ReleaseMutex(&newScp->mx);
4886 cm_ReleaseSCache(newScp);
4887 cm_ReleaseUser(userp);
4892 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4896 osi_Log0(smb_logp, "SMB receive tree disconnect");
4898 /* find the tree and free it */
4899 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4901 lock_ObtainWrite(&smb_rctLock);
4903 lock_ReleaseWrite(&smb_rctLock);
4904 smb_ReleaseTID(tidp);
4910 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4928 pathp = smb_GetSMBData(inp, NULL);
4929 pathp = smb_ParseASCIIBlock(pathp, NULL);
4930 if (smb_StoreAnsiFilenames)
4931 OemToChar(pathp,pathp);
4933 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4935 #ifdef DEBUG_VERBOSE
4939 hexpath = osi_HexifyString( pathp );
4940 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4945 share = smb_GetSMBParm(inp, 0);
4946 attribute = smb_GetSMBParm(inp, 1);
4948 spacep = inp->spacep;
4949 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4950 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4951 /* special case magic file name for receiving IOCTL requests
4952 * (since IOCTL calls themselves aren't getting through).
4954 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4955 smb_SetupIoctlFid(fidp, spacep);
4956 smb_SetSMBParm(outp, 0, fidp->fid);
4957 smb_SetSMBParm(outp, 1, 0); /* attrs */
4958 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4959 smb_SetSMBParm(outp, 3, 0);
4960 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4961 smb_SetSMBParm(outp, 5, 0x7fff);
4962 /* pass the open mode back */
4963 smb_SetSMBParm(outp, 6, (share & 0xf));
4964 smb_SetSMBDataLength(outp, 0);
4965 smb_ReleaseFID(fidp);
4969 userp = smb_GetUserFromVCP(vcp, inp);
4971 caseFold = CM_FLAG_CASEFOLD;
4973 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4975 cm_ReleaseUser(userp);
4976 return CM_ERROR_NOSUCHPATH;
4978 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4979 tidPathp, &req, &scp);
4982 cm_ReleaseUser(userp);
4987 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4988 cm_ReleaseSCache(scp);
4989 cm_ReleaseUser(userp);
4990 if ( WANTS_DFS_PATHNAMES(inp) )
4991 return CM_ERROR_PATH_NOT_COVERED;
4993 return CM_ERROR_BADSHARENAME;
4995 #endif /* DFS_SUPPORT */
4997 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4999 cm_ReleaseSCache(scp);
5000 cm_ReleaseUser(userp);
5004 /* don't need callback to check file type, since file types never
5005 * change, and namei and cm_Lookup all stat the object at least once on
5006 * a successful return.
5008 if (scp->fileType != CM_SCACHETYPE_FILE) {
5009 cm_ReleaseSCache(scp);
5010 cm_ReleaseUser(userp);
5011 return CM_ERROR_ISDIR;
5014 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5017 /* save a pointer to the vnode */
5021 fidp->userp = userp;
5023 lock_ObtainMutex(&fidp->mx);
5024 if ((share & 0xf) == 0)
5025 fidp->flags |= SMB_FID_OPENREAD;
5026 else if ((share & 0xf) == 1)
5027 fidp->flags |= SMB_FID_OPENWRITE;
5029 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5030 lock_ReleaseMutex(&fidp->mx);
5032 lock_ObtainMutex(&scp->mx);
5033 smb_SetSMBParm(outp, 0, fidp->fid);
5034 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5035 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5036 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5037 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5038 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5039 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5040 /* pass the open mode back; XXXX add access checks */
5041 smb_SetSMBParm(outp, 6, (share & 0xf));
5042 smb_SetSMBDataLength(outp, 0);
5043 lock_ReleaseMutex(&scp->mx);
5046 cm_Open(scp, 0, userp);
5048 /* send and free packet */
5049 smb_ReleaseFID(fidp);
5050 cm_ReleaseUser(userp);
5051 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5055 typedef struct smb_unlinkRock {
5060 char *maskp; /* pointer to the star pattern */
5065 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5068 smb_unlinkRock_t *rockp;
5076 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5077 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5078 caseFold |= CM_FLAG_8DOT3;
5080 matchName = dep->name;
5081 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5083 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5084 !cm_Is8Dot3(dep->name)) {
5085 cm_Gen8Dot3Name(dep, shortName, NULL);
5086 matchName = shortName;
5087 /* 8.3 matches are always case insensitive */
5088 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5091 osi_Log1(smb_logp, "Unlinking %s",
5092 osi_LogSaveString(smb_logp, matchName));
5093 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
5094 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5095 smb_NotifyChange(FILE_ACTION_REMOVED,
5096 FILE_NOTIFY_CHANGE_FILE_NAME,
5097 dscp, dep->name, NULL, TRUE);
5101 /* If we made a case sensitive exact match, we might as well quit now. */
5102 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5103 code = CM_ERROR_STOPNOW;
5111 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5120 smb_unlinkRock_t rock;
5129 attribute = smb_GetSMBParm(inp, 0);
5131 tp = smb_GetSMBData(inp, NULL);
5132 pathp = smb_ParseASCIIBlock(tp, &tp);
5133 if (smb_StoreAnsiFilenames)
5134 OemToChar(pathp,pathp);
5136 osi_Log1(smb_logp, "SMB receive unlink %s",
5137 osi_LogSaveString(smb_logp, pathp));
5139 spacep = inp->spacep;
5140 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5142 userp = smb_GetUserFromVCP(vcp, inp);
5144 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5146 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5148 cm_ReleaseUser(userp);
5149 return CM_ERROR_NOSUCHPATH;
5151 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5154 cm_ReleaseUser(userp);
5159 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5160 cm_ReleaseSCache(dscp);
5161 cm_ReleaseUser(userp);
5162 if ( WANTS_DFS_PATHNAMES(inp) )
5163 return CM_ERROR_PATH_NOT_COVERED;
5165 return CM_ERROR_BADSHARENAME;
5167 #endif /* DFS_SUPPORT */
5169 /* otherwise, scp points to the parent directory. */
5176 rock.maskp = smb_FindMask(pathp);
5177 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5180 thyper.HighPart = 0;
5186 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5187 * match. If that fails, we do a case insensitve match.
5189 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5190 !smb_IsStarMask(rock.maskp)) {
5191 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5194 thyper.HighPart = 0;
5195 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5200 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5202 if (code == CM_ERROR_STOPNOW)
5205 cm_ReleaseUser(userp);
5207 cm_ReleaseSCache(dscp);
5209 if (code == 0 && !rock.any)
5210 code = CM_ERROR_NOSUCHFILE;
5214 typedef struct smb_renameRock {
5215 cm_scache_t *odscp; /* old dir */
5216 cm_scache_t *ndscp; /* new dir */
5217 cm_user_t *userp; /* user */
5218 cm_req_t *reqp; /* request struct */
5219 smb_vc_t *vcp; /* virtual circuit */
5220 char *maskp; /* pointer to star pattern of old file name */
5221 int flags; /* tilde, casefold, etc */
5222 char *newNamep; /* ptr to the new file's name */
5225 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5228 smb_renameRock_t *rockp;
5233 rockp = (smb_renameRock_t *) vrockp;
5235 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5236 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5237 caseFold |= CM_FLAG_8DOT3;
5239 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5241 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5242 !cm_Is8Dot3(dep->name)) {
5243 cm_Gen8Dot3Name(dep, shortName, NULL);
5244 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5247 code = cm_Rename(rockp->odscp, dep->name,
5248 rockp->ndscp, rockp->newNamep, rockp->userp,
5250 /* if the call worked, stop doing the search now, since we
5251 * really only want to rename one file.
5254 code = CM_ERROR_STOPNOW;
5263 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5266 cm_space_t *spacep = NULL;
5267 smb_renameRock_t rock;
5268 cm_scache_t *oldDscp = NULL;
5269 cm_scache_t *newDscp = NULL;
5270 cm_scache_t *tmpscp= NULL;
5271 cm_scache_t *tmpscp2 = NULL;
5281 userp = smb_GetUserFromVCP(vcp, inp);
5282 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5284 cm_ReleaseUser(userp);
5285 return CM_ERROR_NOSUCHPATH;
5289 spacep = inp->spacep;
5290 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5292 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5293 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5294 userp, tidPathp, &req, &oldDscp);
5296 cm_ReleaseUser(userp);
5301 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5302 cm_ReleaseSCache(oldDscp);
5303 cm_ReleaseUser(userp);
5304 if ( WANTS_DFS_PATHNAMES(inp) )
5305 return CM_ERROR_PATH_NOT_COVERED;
5307 return CM_ERROR_BADSHARENAME;
5309 #endif /* DFS_SUPPORT */
5311 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5312 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5313 userp, tidPathp, &req, &newDscp);
5316 cm_ReleaseSCache(oldDscp);
5317 cm_ReleaseUser(userp);
5322 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5323 cm_ReleaseSCache(oldDscp);
5324 cm_ReleaseSCache(newDscp);
5325 cm_ReleaseUser(userp);
5326 if ( WANTS_DFS_PATHNAMES(inp) )
5327 return CM_ERROR_PATH_NOT_COVERED;
5329 return CM_ERROR_BADSHARENAME;
5331 #endif /* DFS_SUPPORT */
5334 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5335 * next, get the component names, and lower case them.
5338 /* handle the old name first */
5340 oldLastNamep = oldPathp;
5344 /* and handle the new name, too */
5346 newLastNamep = newPathp;
5350 /* TODO: The old name could be a wildcard. The new name must not be */
5352 /* do the vnode call */
5353 rock.odscp = oldDscp;
5354 rock.ndscp = newDscp;
5358 rock.maskp = oldLastNamep;
5359 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5360 rock.newNamep = newLastNamep;
5362 /* Check if the file already exists; if so return error */
5363 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5364 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5365 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5366 osi_LogSaveString(afsd_logp, newLastNamep));
5368 /* Check if the old and the new names differ only in case. If so return
5369 * success, else return CM_ERROR_EXISTS
5371 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5373 /* This would be a success only if the old file is *as same as* the new file */
5374 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5376 if (tmpscp == tmpscp2)
5379 code = CM_ERROR_EXISTS;
5380 cm_ReleaseSCache(tmpscp2);
5383 code = CM_ERROR_NOSUCHFILE;
5386 /* file exist, do not rename, also fixes move */
5387 osi_Log0(smb_logp, "Can't rename. Target already exists");
5388 code = CM_ERROR_EXISTS;
5392 cm_ReleaseSCache(tmpscp);
5393 cm_ReleaseSCache(newDscp);
5394 cm_ReleaseSCache(oldDscp);
5395 cm_ReleaseUser(userp);
5399 /* Now search the directory for the pattern, and do the appropriate rename when found */
5400 thyper.LowPart = 0; /* search dir from here */
5401 thyper.HighPart = 0;
5403 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5404 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5406 if (code == CM_ERROR_STOPNOW)
5409 code = CM_ERROR_NOSUCHFILE;
5411 /* Handle Change Notification */
5413 * Being lazy, not distinguishing between files and dirs in this
5414 * filter, since we'd have to do a lookup.
5416 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5417 if (oldDscp == newDscp) {
5418 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5419 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5420 filter, oldDscp, oldLastNamep,
5421 newLastNamep, TRUE);
5423 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5424 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5425 filter, oldDscp, oldLastNamep,
5427 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5428 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5429 filter, newDscp, newLastNamep,
5434 cm_ReleaseSCache(tmpscp);
5435 cm_ReleaseUser(userp);
5436 cm_ReleaseSCache(oldDscp);
5437 cm_ReleaseSCache(newDscp);
5442 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5445 cm_space_t *spacep = NULL;
5446 cm_scache_t *oldDscp = NULL;
5447 cm_scache_t *newDscp = NULL;
5448 cm_scache_t *tmpscp= NULL;
5449 cm_scache_t *tmpscp2 = NULL;
5450 cm_scache_t *sscp = NULL;
5459 userp = smb_GetUserFromVCP(vcp, inp);
5461 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5463 cm_ReleaseUser(userp);
5464 return CM_ERROR_NOSUCHPATH;
5469 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5471 spacep = inp->spacep;
5472 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5474 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5475 userp, tidPathp, &req, &oldDscp);
5477 cm_ReleaseUser(userp);
5482 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5483 cm_ReleaseSCache(oldDscp);
5484 cm_ReleaseUser(userp);
5485 if ( WANTS_DFS_PATHNAMES(inp) )
5486 return CM_ERROR_PATH_NOT_COVERED;
5488 return CM_ERROR_BADSHARENAME;
5490 #endif /* DFS_SUPPORT */
5492 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5493 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5494 userp, tidPathp, &req, &newDscp);
5496 cm_ReleaseSCache(oldDscp);
5497 cm_ReleaseUser(userp);
5502 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5503 cm_ReleaseSCache(newDscp);
5504 cm_ReleaseSCache(oldDscp);
5505 cm_ReleaseUser(userp);
5506 if ( WANTS_DFS_PATHNAMES(inp) )
5507 return CM_ERROR_PATH_NOT_COVERED;
5509 return CM_ERROR_BADSHARENAME;
5511 #endif /* DFS_SUPPORT */
5513 /* Now, although we did two lookups for the two directories (because the same
5514 * directory can be referenced through different paths), we only allow hard links
5515 * within the same directory. */
5516 if (oldDscp != newDscp) {
5517 cm_ReleaseSCache(oldDscp);
5518 cm_ReleaseSCache(newDscp);
5519 cm_ReleaseUser(userp);
5520 return CM_ERROR_CROSSDEVLINK;
5523 /* handle the old name first */
5525 oldLastNamep = oldPathp;
5529 /* and handle the new name, too */
5531 newLastNamep = newPathp;
5535 /* now lookup the old name */
5536 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5537 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5539 cm_ReleaseSCache(oldDscp);
5540 cm_ReleaseSCache(newDscp);
5541 cm_ReleaseUser(userp);
5545 /* Check if the file already exists; if so return error */
5546 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5547 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5548 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5549 osi_LogSaveString(afsd_logp, newLastNamep));
5551 /* if the existing link is to the same file, then we return success */
5553 if(sscp == tmpscp) {
5556 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5557 code = CM_ERROR_EXISTS;
5562 cm_ReleaseSCache(tmpscp);
5563 cm_ReleaseSCache(sscp);
5564 cm_ReleaseSCache(newDscp);
5565 cm_ReleaseSCache(oldDscp);
5566 cm_ReleaseUser(userp);
5570 /* now create the hardlink */
5571 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5572 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5573 osi_Log1(smb_logp," Link returns 0x%x", code);
5575 /* Handle Change Notification */
5577 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5578 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5579 smb_NotifyChange(FILE_ACTION_ADDED,
5580 filter, newDscp, newLastNamep,
5585 cm_ReleaseSCache(tmpscp);
5586 cm_ReleaseUser(userp);
5587 cm_ReleaseSCache(sscp);
5588 cm_ReleaseSCache(oldDscp);
5589 cm_ReleaseSCache(newDscp);
5594 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5600 tp = smb_GetSMBData(inp, NULL);
5601 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5602 if (smb_StoreAnsiFilenames)
5603 OemToChar(oldPathp,oldPathp);
5604 newPathp = smb_ParseASCIIBlock(tp, &tp);
5605 if (smb_StoreAnsiFilenames)
5606 OemToChar(newPathp,newPathp);
5608 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5609 osi_LogSaveString(smb_logp, oldPathp),
5610 osi_LogSaveString(smb_logp, newPathp));
5612 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5617 typedef struct smb_rmdirRock {
5621 char *maskp; /* pointer to the star pattern */
5626 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5629 smb_rmdirRock_t *rockp;
5634 rockp = (smb_rmdirRock_t *) vrockp;
5636 matchName = dep->name;
5637 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5638 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5640 match = (strcmp(matchName, rockp->maskp) == 0);
5642 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5643 !cm_Is8Dot3(dep->name)) {
5644 cm_Gen8Dot3Name(dep, shortName, NULL);
5645 matchName = shortName;
5646 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5649 osi_Log1(smb_logp, "Removing directory %s",
5650 osi_LogSaveString(smb_logp, matchName));
5651 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5652 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5653 smb_NotifyChange(FILE_ACTION_REMOVED,
5654 FILE_NOTIFY_CHANGE_DIR_NAME,
5655 dscp, dep->name, NULL, TRUE);
5664 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5672 smb_rmdirRock_t rock;
5681 tp = smb_GetSMBData(inp, NULL);
5682 pathp = smb_ParseASCIIBlock(tp, &tp);
5683 if (smb_StoreAnsiFilenames)
5684 OemToChar(pathp,pathp);
5686 spacep = inp->spacep;
5687 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5689 userp = smb_GetUserFromVCP(vcp, inp);
5691 caseFold = CM_FLAG_CASEFOLD;
5693 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5695 cm_ReleaseUser(userp);
5696 return CM_ERROR_NOSUCHPATH;
5698 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5699 userp, tidPathp, &req, &dscp);
5702 cm_ReleaseUser(userp);
5707 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5708 cm_ReleaseSCache(dscp);
5709 cm_ReleaseUser(userp);
5710 if ( WANTS_DFS_PATHNAMES(inp) )
5711 return CM_ERROR_PATH_NOT_COVERED;
5713 return CM_ERROR_BADSHARENAME;
5715 #endif /* DFS_SUPPORT */
5717 /* otherwise, scp points to the parent directory. */
5724 rock.maskp = lastNamep;
5725 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5728 thyper.HighPart = 0;
5732 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5733 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5734 if (code == 0 && !rock.any) {
5736 thyper.HighPart = 0;
5737 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5738 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5741 cm_ReleaseUser(userp);
5743 cm_ReleaseSCache(dscp);
5745 if (code == 0 && !rock.any)
5746 code = CM_ERROR_NOSUCHFILE;
5750 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5760 fid = smb_GetSMBParm(inp, 0);
5762 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5764 fid = smb_ChainFID(fid, inp);
5765 fidp = smb_FindFID(vcp, fid, 0);
5767 return CM_ERROR_BADFD;
5769 lock_ObtainMutex(&fidp->mx);
5770 if (fidp->flags & SMB_FID_IOCTL) {
5771 lock_ReleaseMutex(&fidp->mx);
5772 smb_ReleaseFID(fidp);
5773 return CM_ERROR_BADFD;
5775 lock_ReleaseMutex(&fidp->mx);
5777 userp = smb_GetUserFromVCP(vcp, inp);
5779 lock_ObtainMutex(&fidp->mx);
5780 if (fidp->flags & SMB_FID_OPENWRITE) {
5781 cm_scache_t * scp = fidp->scp;
5783 lock_ReleaseMutex(&fidp->mx);
5784 code = cm_FSync(scp, userp, &req);
5785 cm_ReleaseSCache(scp);
5788 lock_ReleaseMutex(&fidp->mx);
5791 smb_ReleaseFID(fidp);
5793 cm_ReleaseUser(userp);
5798 struct smb_FullNameRock {
5804 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5808 struct smb_FullNameRock *vrockp;
5810 vrockp = (struct smb_FullNameRock *)rockp;
5812 if (!cm_Is8Dot3(dep->name)) {
5813 cm_Gen8Dot3Name(dep, shortName, NULL);
5815 if (cm_stricmp(shortName, vrockp->name) == 0) {
5816 vrockp->fullName = strdup(dep->name);
5817 return CM_ERROR_STOPNOW;
5820 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5821 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5822 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5823 vrockp->fullName = strdup(dep->name);
5824 return CM_ERROR_STOPNOW;
5829 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5830 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5832 struct smb_FullNameRock rock;
5838 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5839 if (code == CM_ERROR_STOPNOW)
5840 *newPathp = rock.fullName;
5842 *newPathp = strdup(pathp);
5845 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5846 afs_uint32 dosTime) {
5849 cm_scache_t *dscp = fidp->NTopen_dscp;
5850 char *pathp = fidp->NTopen_pathp;
5853 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5854 fidp, fidp->fid, vcp);
5857 lock_ObtainMutex(&fidp->mx);
5858 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5859 lock_ReleaseMutex(&fidp->mx);
5860 osi_Log0(smb_logp, " No user specified. Not closing fid");
5861 return CM_ERROR_BADFD;
5864 userp = fidp->userp; /* no hold required since fidp is held
5865 throughout the function */
5866 lock_ReleaseMutex(&fidp->mx);
5871 lock_ObtainWrite(&smb_rctLock);
5873 osi_Log0(smb_logp, " Fid already closed.");
5874 lock_ReleaseWrite(&smb_rctLock);
5875 return CM_ERROR_BADFD;
5878 lock_ReleaseWrite(&smb_rctLock);
5880 lock_ObtainMutex(&fidp->mx);
5881 /* Don't jump the gun on an async raw write */
5882 while (fidp->raw_writers) {
5883 lock_ReleaseMutex(&fidp->mx);
5884 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5885 lock_ObtainMutex(&fidp->mx);
5892 /* watch for ioctl closes, and read-only opens */
5894 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5895 == SMB_FID_OPENWRITE) {
5896 if (dosTime != 0 && dosTime != -1) {
5897 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5898 /* This fixes defect 10958 */
5899 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5900 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5902 lock_ReleaseMutex(&fidp->mx);
5903 code = cm_FSync(scp, userp, &req);
5904 lock_ObtainMutex(&fidp->mx);
5909 /* unlock any pending locks */
5910 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5911 scp->fileType == CM_SCACHETYPE_FILE) {
5915 lock_ReleaseMutex(&fidp->mx);
5917 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5919 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5920 lock_ObtainMutex(&scp->mx);
5922 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5923 CM_SCACHESYNC_NEEDCALLBACK
5924 | CM_SCACHESYNC_GETSTATUS
5925 | CM_SCACHESYNC_LOCK);
5929 "smb CoreClose SyncOp failure code 0x%x", tcode);
5930 goto post_syncopdone;
5933 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5935 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5939 lock_ReleaseMutex(&scp->mx);
5940 lock_ObtainMutex(&fidp->mx);
5943 if (fidp->flags & SMB_FID_DELONCLOSE) {
5946 lock_ReleaseMutex(&fidp->mx);
5947 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5948 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5949 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5950 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5951 smb_NotifyChange(FILE_ACTION_REMOVED,
5952 FILE_NOTIFY_CHANGE_DIR_NAME,
5953 dscp, fullPathp, NULL, TRUE);
5955 code = cm_Unlink(dscp, fullPathp, userp, &req);
5956 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5957 smb_NotifyChange(FILE_ACTION_REMOVED,
5958 FILE_NOTIFY_CHANGE_FILE_NAME,
5959 dscp, fullPathp, NULL, TRUE);
5962 lock_ObtainMutex(&fidp->mx);
5963 fidp->flags &= ~SMB_FID_DELONCLOSE;
5966 /* if this was a newly created file, then clear the creator
5967 * in the stat cache entry. */
5968 if (fidp->flags & SMB_FID_CREATED) {
5969 lock_ObtainMutex(&scp->mx);
5970 if (scp->creator == userp)
5971 scp->creator = NULL;
5972 lock_ReleaseMutex(&scp->mx);
5973 fidp->flags &= ~SMB_FID_CREATED;
5976 if (fidp->flags & SMB_FID_NTOPEN) {
5977 fidp->NTopen_dscp = NULL;
5978 fidp->NTopen_pathp = NULL;
5979 fidp->flags &= ~SMB_FID_NTOPEN;
5981 if (fidp->NTopen_wholepathp) {
5982 free(fidp->NTopen_wholepathp);
5983 fidp->NTopen_wholepathp = NULL;
5985 lock_ReleaseMutex(&fidp->mx);
5988 cm_ReleaseSCache(dscp);
5991 cm_ReleaseSCache(scp);
5999 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6007 fid = smb_GetSMBParm(inp, 0);
6008 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6010 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6012 fid = smb_ChainFID(fid, inp);
6013 fidp = smb_FindFID(vcp, fid, 0);
6015 return CM_ERROR_BADFD;
6018 userp = smb_GetUserFromVCP(vcp, inp);
6020 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6022 smb_ReleaseFID(fidp);
6023 cm_ReleaseUser(userp);
6028 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6031 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6032 cm_user_t *userp, long *readp)
6034 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6035 cm_user_t *userp, long *readp, int dosflag)
6042 osi_hyper_t fileLength;
6044 osi_hyper_t lastByte;
6045 osi_hyper_t bufferOffset;
6046 long bufIndex, nbytes;
6056 lock_ObtainMutex(&fidp->mx);
6058 lock_ObtainMutex(&scp->mx);
6060 if (offset.HighPart == 0) {
6061 chunk = offset.LowPart >> cm_logChunkSize;
6062 if (chunk != fidp->curr_chunk) {
6063 fidp->prev_chunk = fidp->curr_chunk;
6064 fidp->curr_chunk = chunk;
6066 if (fidp->curr_chunk == fidp->prev_chunk + 1)
6069 lock_ReleaseMutex(&fidp->mx);
6071 /* start by looking up the file's end */
6072 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6073 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6074 if (code) goto done;
6076 /* now we have the entry locked, look up the length */
6077 fileLength = scp->length;
6079 /* adjust count down so that it won't go past EOF */
6080 thyper.LowPart = count;
6081 thyper.HighPart = 0;
6082 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6084 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6085 /* we'd read past EOF, so just stop at fileLength bytes.
6086 * Start by computing how many bytes remain in the file.
6088 thyper = LargeIntegerSubtract(fileLength, offset);
6090 /* if we are past EOF, read 0 bytes */
6091 if (LargeIntegerLessThanZero(thyper))
6094 count = thyper.LowPart;
6099 /* now, copy the data one buffer at a time,
6100 * until we've filled the request packet
6103 /* if we've copied all the data requested, we're done */
6104 if (count <= 0) break;
6106 /* otherwise, load up a buffer of data */
6107 thyper.HighPart = offset.HighPart;
6108 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6109 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6112 buf_Release(bufferp);
6115 lock_ReleaseMutex(&scp->mx);
6117 lock_ObtainRead(&scp->bufCreateLock);
6118 code = buf_Get(scp, &thyper, &bufferp);
6119 lock_ReleaseRead(&scp->bufCreateLock);
6121 lock_ObtainMutex(&scp->mx);
6122 if (code) goto done;
6123 bufferOffset = thyper;
6125 /* now get the data in the cache */
6127 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6128 CM_SCACHESYNC_NEEDCALLBACK |
6129 CM_SCACHESYNC_READ);
6130 if (code) goto done;
6132 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6134 /* otherwise, load the buffer and try again */
6135 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6139 buf_Release(bufferp);
6143 } /* if (wrong buffer) ... */
6145 /* now we have the right buffer loaded. Copy out the
6146 * data from here to the user's buffer.
6148 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6150 /* and figure out how many bytes we want from this buffer */
6151 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6152 if (nbytes > count) nbytes = count; /* don't go past EOF */
6154 /* now copy the data */
6157 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6160 memcpy(op, bufferp->datap + bufIndex, nbytes);
6162 /* adjust counters, pointers, etc. */
6165 thyper.LowPart = nbytes;
6166 thyper.HighPart = 0;
6167 offset = LargeIntegerAdd(thyper, offset);
6171 lock_ReleaseMutex(&scp->mx);
6173 buf_Release(bufferp);
6175 if (code == 0 && sequential)
6176 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6182 * smb_WriteData -- common code for Write and Raw Write
6185 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6186 cm_user_t *userp, long *writtenp)
6188 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6189 cm_user_t *userp, long *writtenp, int dosflag)
6196 osi_hyper_t fileLength; /* file's length at start of write */
6197 osi_hyper_t minLength; /* don't read past this */
6198 long nbytes; /* # of bytes to transfer this iteration */
6200 osi_hyper_t thyper; /* hyper tmp variable */
6201 osi_hyper_t bufferOffset;
6202 long bufIndex; /* index in buffer where our data is */
6204 osi_hyper_t writeBackOffset;/* offset of region to write back when
6209 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6210 fidp->fid, offsetp->LowPart, count);
6220 lock_ObtainMutex(&fidp->mx);
6221 /* make sure we have a writable FD */
6222 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6223 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6224 fidp->fid, fidp->flags);
6225 lock_ReleaseMutex(&fidp->mx);
6226 code = CM_ERROR_BADFDOP;
6232 lock_ReleaseMutex(&fidp->mx);
6234 lock_ObtainMutex(&scp->mx);
6235 /* start by looking up the file's end */
6236 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6237 CM_SCACHESYNC_NEEDCALLBACK
6238 | CM_SCACHESYNC_SETSTATUS
6239 | CM_SCACHESYNC_GETSTATUS);
6243 /* now we have the entry locked, look up the length */
6244 fileLength = scp->length;
6245 minLength = fileLength;
6246 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6247 minLength = scp->serverLength;
6249 /* adjust file length if we extend past EOF */
6250 thyper.LowPart = count;
6251 thyper.HighPart = 0;
6252 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6253 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6254 /* we'd write past EOF, so extend the file */
6255 scp->mask |= CM_SCACHEMASK_LENGTH;
6256 scp->length = thyper;
6257 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6259 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6261 /* now, if the new position (thyper) and the old (offset) are in
6262 * different storeback windows, remember to store back the previous
6263 * storeback window when we're done with the write.
6265 if ((thyper.LowPart & (-cm_chunkSize)) !=
6266 (offset.LowPart & (-cm_chunkSize))) {
6267 /* they're different */
6269 writeBackOffset.HighPart = offset.HighPart;
6270 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6275 /* now, copy the data one buffer at a time, until we've filled the
6278 /* if we've copied all the data requested, we're done */
6282 /* handle over quota or out of space */
6283 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6284 *writtenp = written;
6285 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6289 /* otherwise, load up a buffer of data */
6290 thyper.HighPart = offset.HighPart;
6291 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6292 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6295 lock_ReleaseMutex(&bufferp->mx);
6296 buf_Release(bufferp);
6299 lock_ReleaseMutex(&scp->mx);
6301 lock_ObtainRead(&scp->bufCreateLock);
6302 code = buf_Get(scp, &thyper, &bufferp);
6303 lock_ReleaseRead(&scp->bufCreateLock);
6305 lock_ObtainMutex(&bufferp->mx);
6306 lock_ObtainMutex(&scp->mx);
6307 if (code) goto done;
6309 bufferOffset = thyper;
6311 /* now get the data in the cache */
6313 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6314 CM_SCACHESYNC_NEEDCALLBACK
6315 | CM_SCACHESYNC_WRITE
6316 | CM_SCACHESYNC_BUFLOCKED);
6320 /* If we're overwriting the entire buffer, or
6321 * if we're writing at or past EOF, mark the
6322 * buffer as current so we don't call
6323 * cm_GetBuffer. This skips the fetch from the
6324 * server in those cases where we're going to
6325 * obliterate all the data in the buffer anyway,
6326 * or in those cases where there is no useful
6327 * data at the server to start with.
6329 * Use minLength instead of scp->length, since
6330 * the latter has already been updated by this
6333 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6334 || LargeIntegerEqualTo(offset, bufferp->offset)
6335 && (count >= cm_data.buf_blockSize
6336 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6337 ConvertLongToLargeInteger(count)),
6339 if (count < cm_data.buf_blockSize
6340 && bufferp->dataVersion == -1)
6341 memset(bufferp->datap, 0,
6342 cm_data.buf_blockSize);
6343 bufferp->dataVersion = scp->dataVersion;
6346 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6348 /* otherwise, load the buffer and try again */
6349 lock_ReleaseMutex(&bufferp->mx);
6350 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6352 lock_ReleaseMutex(&scp->mx);
6353 lock_ObtainMutex(&bufferp->mx);
6354 lock_ObtainMutex(&scp->mx);
6358 lock_ReleaseMutex(&bufferp->mx);
6359 buf_Release(bufferp);
6363 } /* if (wrong buffer) ... */
6365 /* now we have the right buffer loaded. Copy out the
6366 * data from here to the user's buffer.
6368 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6370 /* and figure out how many bytes we want from this buffer */
6371 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6373 nbytes = count; /* don't go past end of request */
6375 /* now copy the data */
6378 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6381 memcpy(bufferp->datap + bufIndex, op, nbytes);
6382 buf_SetDirty(bufferp);
6384 /* and record the last writer */
6385 if (bufferp->userp != userp) {
6388 cm_ReleaseUser(bufferp->userp);
6389 bufferp->userp = userp;
6392 /* adjust counters, pointers, etc. */
6396 thyper.LowPart = nbytes;
6397 thyper.HighPart = 0;
6398 offset = LargeIntegerAdd(thyper, offset);
6402 lock_ReleaseMutex(&scp->mx);
6405 lock_ReleaseMutex(&bufferp->mx);
6406 buf_Release(bufferp);
6409 lock_ObtainMutex(&fidp->mx);
6410 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6411 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6412 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6413 fidp->NTopen_dscp, fidp->NTopen_pathp,
6416 lock_ReleaseMutex(&fidp->mx);
6418 if (code == 0 && doWriteBack) {
6420 lock_ObtainMutex(&scp->mx);
6421 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6423 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6424 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6426 lock_ReleaseMutex(&scp->mx);
6427 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6428 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6431 cm_ReleaseSCache(scp);
6433 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6434 fidp->fid, code, *writtenp);
6438 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6441 unsigned short count;
6443 unsigned short hint;
6444 long written = 0, total_written = 0;
6449 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6451 int inDataBlockCount;
6453 fd = smb_GetSMBParm(inp, 0);
6454 count = smb_GetSMBParm(inp, 1);
6455 offset.HighPart = 0; /* too bad */
6456 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6457 hint = smb_GetSMBParm(inp, 4);
6459 op = smb_GetSMBData(inp, NULL);
6460 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6462 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6463 fd, offset.LowPart, count);
6465 fd = smb_ChainFID(fd, inp);
6466 fidp = smb_FindFID(vcp, fd, 0);
6468 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6469 return CM_ERROR_BADFD;
6472 lock_ObtainMutex(&fidp->mx);
6473 if (fidp->flags & SMB_FID_IOCTL) {
6474 lock_ReleaseMutex(&fidp->mx);
6475 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6476 smb_ReleaseFID(fidp);
6477 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6480 lock_ReleaseMutex(&fidp->mx);
6481 userp = smb_GetUserFromVCP(vcp, inp);
6485 LARGE_INTEGER LOffset;
6486 LARGE_INTEGER LLength;
6488 pid = ((smb_t *) inp)->pid;
6489 key = cm_GenerateKey(vcp->vcID, pid, fd);
6491 LOffset.HighPart = offset.HighPart;
6492 LOffset.LowPart = offset.LowPart;
6493 LLength.HighPart = 0;
6494 LLength.LowPart = count;
6496 lock_ObtainMutex(&fidp->scp->mx);
6497 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6498 lock_ReleaseMutex(&fidp->scp->mx);
6501 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6506 /* special case: 0 bytes transferred means truncate to this position */
6510 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6514 truncAttr.mask = CM_ATTRMASK_LENGTH;
6515 truncAttr.length.LowPart = offset.LowPart;
6516 truncAttr.length.HighPart = 0;
6517 lock_ObtainMutex(&fidp->mx);
6518 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6519 fidp->flags |= SMB_FID_LENGTHSETDONE;
6520 lock_ReleaseMutex(&fidp->mx);
6521 smb_SetSMBParm(outp, 0, 0 /* count */);
6522 smb_SetSMBDataLength(outp, 0);
6527 * Work around bug in NT client
6529 * When copying a file, the NT client should first copy the data,
6530 * then copy the last write time. But sometimes the NT client does
6531 * these in the wrong order, so the data copies would inadvertently
6532 * cause the last write time to be overwritten. We try to detect this,
6533 * and don't set client mod time if we think that would go against the
6536 lock_ObtainMutex(&fidp->mx);
6537 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6538 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6539 fidp->scp->clientModTime = time(NULL);
6541 lock_ReleaseMutex(&fidp->mx);
6544 while ( code == 0 && count > 0 ) {
6546 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6548 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6550 if (code == 0 && written == 0)
6551 code = CM_ERROR_PARTIALWRITE;
6553 offset = LargeIntegerAdd(offset,
6554 ConvertLongToLargeInteger(written));
6556 total_written += written;
6560 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6561 total_written, code);
6563 /* set the packet data length to 3 bytes for the data block header,
6564 * plus the size of the data.
6566 smb_SetSMBParm(outp, 0, total_written);
6567 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6568 smb_SetSMBParm(outp, 3, hint);
6569 smb_SetSMBDataLength(outp, 0);
6572 smb_ReleaseFID(fidp);
6573 cm_ReleaseUser(userp);
6578 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6579 NCB *ncbp, raw_write_cont_t *rwcp)
6592 fd = smb_GetSMBParm(inp, 0);
6593 fidp = smb_FindFID(vcp, fd, 0);
6595 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6596 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6598 userp = smb_GetUserFromVCP(vcp, inp);
6602 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6605 rawBuf = (dos_ptr) rwcp->buf;
6606 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6607 (unsigned char *) rawBuf, userp,
6611 if (rwcp->writeMode & 0x1) { /* synchronous */
6614 smb_FormatResponsePacket(vcp, inp, outp);
6615 op = (smb_t *) outp;
6616 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6617 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6618 smb_SetSMBDataLength(outp, 0);
6619 smb_SendPacket(vcp, outp);
6620 smb_FreePacket(outp);
6622 else { /* asynchronous */
6623 lock_ObtainMutex(&fidp->mx);
6624 fidp->raw_writers--;
6625 if (fidp->raw_writers == 0)
6626 thrd_SetEvent(fidp->raw_write_event);
6627 lock_ReleaseMutex(&fidp->mx);
6630 /* Give back raw buffer */
6631 lock_ObtainMutex(&smb_RawBufLock);
6633 *((char **)rawBuf) = smb_RawBufs;
6635 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6637 smb_RawBufs = rawBuf;
6638 lock_ReleaseMutex(&smb_RawBufLock);
6640 smb_ReleaseFID(fidp);
6641 cm_ReleaseUser(userp);
6644 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6649 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6652 long count, written = 0, total_written = 0;
6659 unsigned short writeMode;
6666 fd = smb_GetSMBParm(inp, 0);
6667 totalCount = smb_GetSMBParm(inp, 1);
6668 count = smb_GetSMBParm(inp, 10);
6669 writeMode = smb_GetSMBParm(inp, 7);
6671 op = (char *) inp->data;
6672 op += smb_GetSMBParm(inp, 11);
6674 offset.HighPart = 0;
6675 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6677 if (*inp->wctp == 14) {
6678 /* we received a 64-bit file offset */
6679 #ifdef AFS_LARGEFILES
6680 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6682 if (LargeIntegerLessThanZero(offset)) {
6684 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6685 offset.HighPart, offset.LowPart);
6686 return CM_ERROR_BADSMB;
6689 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6691 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6692 return CM_ERROR_BADSMB;
6695 offset.HighPart = 0;
6698 offset.HighPart = 0; /* 32-bit file offset */
6702 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6703 fd, offset.HighPart, offset.LowPart, count);
6705 " WriteRaw WriteMode 0x%x",
6708 fd = smb_ChainFID(fd, inp);
6709 fidp = smb_FindFID(vcp, fd, 0);
6711 return CM_ERROR_BADFD;
6717 LARGE_INTEGER LOffset;
6718 LARGE_INTEGER LLength;
6720 pid = ((smb_t *) inp)->pid;
6721 key = cm_GenerateKey(vcp->vcID, pid, fd);
6723 LOffset.HighPart = offset.HighPart;
6724 LOffset.LowPart = offset.LowPart;
6725 LLength.HighPart = 0;
6726 LLength.LowPart = count;
6728 lock_ObtainMutex(&fidp->scp->mx);
6729 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6730 lock_ReleaseMutex(&fidp->scp->mx);
6733 smb_ReleaseFID(fidp);
6738 userp = smb_GetUserFromVCP(vcp, inp);
6741 * Work around bug in NT client
6743 * When copying a file, the NT client should first copy the data,
6744 * then copy the last write time. But sometimes the NT client does
6745 * these in the wrong order, so the data copies would inadvertently
6746 * cause the last write time to be overwritten. We try to detect this,
6747 * and don't set client mod time if we think that would go against the
6750 lock_ObtainMutex(&fidp->mx);
6751 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6752 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6753 fidp->scp->clientModTime = time(NULL);
6755 lock_ReleaseMutex(&fidp->mx);
6758 while ( code == 0 && count > 0 ) {
6760 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6762 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6764 if (code == 0 && written == 0)
6765 code = CM_ERROR_PARTIALWRITE;
6767 offset = LargeIntegerAdd(offset,
6768 ConvertLongToLargeInteger(written));
6771 total_written += written;
6775 /* Get a raw buffer */
6778 lock_ObtainMutex(&smb_RawBufLock);
6780 /* Get a raw buf, from head of list */
6781 rawBuf = smb_RawBufs;
6783 smb_RawBufs = *(char **)smb_RawBufs;
6785 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6789 code = CM_ERROR_USESTD;
6791 lock_ReleaseMutex(&smb_RawBufLock);
6794 /* Don't allow a premature Close */
6795 if (code == 0 && (writeMode & 1) == 0) {
6796 lock_ObtainMutex(&fidp->mx);
6797 fidp->raw_writers++;
6798 thrd_ResetEvent(fidp->raw_write_event);
6799 lock_ReleaseMutex(&fidp->mx);
6802 smb_ReleaseFID(fidp);
6803 cm_ReleaseUser(userp);
6806 smb_SetSMBParm(outp, 0, total_written);
6807 smb_SetSMBDataLength(outp, 0);
6808 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6813 offset = LargeIntegerAdd(offset,
6814 ConvertLongToLargeInteger(count));
6818 rwcp->offset.HighPart = offset.HighPart;
6819 rwcp->offset.LowPart = offset.LowPart;
6820 rwcp->count = totalCount - count;
6821 rwcp->writeMode = writeMode;
6822 rwcp->alreadyWritten = total_written;
6824 /* set the packet data length to 3 bytes for the data block header,
6825 * plus the size of the data.
6827 smb_SetSMBParm(outp, 0, 0xffff);
6828 smb_SetSMBDataLength(outp, 0);
6833 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6836 long count, finalCount;
6844 fd = smb_GetSMBParm(inp, 0);
6845 count = smb_GetSMBParm(inp, 1);
6846 offset.HighPart = 0; /* too bad */
6847 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6849 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6850 fd, offset.LowPart, count);
6852 fd = smb_ChainFID(fd, inp);
6853 fidp = smb_FindFID(vcp, fd, 0);
6855 return CM_ERROR_BADFD;
6857 lock_ObtainMutex(&fidp->mx);
6858 if (fidp->flags & SMB_FID_IOCTL) {
6859 lock_ReleaseMutex(&fidp->mx);
6860 code = smb_IoctlRead(fidp, vcp, inp, outp);
6861 smb_ReleaseFID(fidp);
6864 lock_ReleaseMutex(&fidp->mx);
6867 LARGE_INTEGER LOffset, LLength;
6870 pid = ((smb_t *) inp)->pid;
6871 key = cm_GenerateKey(vcp->vcID, pid, fd);
6873 LOffset.HighPart = 0;
6874 LOffset.LowPart = offset.LowPart;
6875 LLength.HighPart = 0;
6876 LLength.LowPart = count;
6878 lock_ObtainMutex(&fidp->scp->mx);
6879 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6880 lock_ReleaseMutex(&fidp->scp->mx);
6883 smb_ReleaseFID(fidp);
6887 userp = smb_GetUserFromVCP(vcp, inp);
6889 /* remember this for final results */
6890 smb_SetSMBParm(outp, 0, count);
6891 smb_SetSMBParm(outp, 1, 0);
6892 smb_SetSMBParm(outp, 2, 0);
6893 smb_SetSMBParm(outp, 3, 0);
6894 smb_SetSMBParm(outp, 4, 0);
6896 /* set the packet data length to 3 bytes for the data block header,
6897 * plus the size of the data.
6899 smb_SetSMBDataLength(outp, count+3);
6901 /* get op ptr after putting in the parms, since otherwise we don't
6902 * know where the data really is.
6904 op = smb_GetSMBData(outp, NULL);
6906 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6907 *op++ = 1; /* data block marker */
6908 *op++ = (unsigned char) (count & 0xff);
6909 *op++ = (unsigned char) ((count >> 8) & 0xff);
6912 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6914 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6917 /* fix some things up */
6918 smb_SetSMBParm(outp, 0, finalCount);
6919 smb_SetSMBDataLength(outp, finalCount+3);
6921 smb_ReleaseFID(fidp);
6923 cm_ReleaseUser(userp);
6927 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6934 cm_scache_t *dscp; /* dir we're dealing with */
6935 cm_scache_t *scp; /* file we're creating */
6937 int initialModeBits;
6947 /* compute initial mode bits based on read-only flag in attributes */
6948 initialModeBits = 0777;
6950 tp = smb_GetSMBData(inp, NULL);
6951 pathp = smb_ParseASCIIBlock(tp, &tp);
6952 if (smb_StoreAnsiFilenames)
6953 OemToChar(pathp,pathp);
6955 if (strcmp(pathp, "\\") == 0)
6956 return CM_ERROR_EXISTS;
6958 spacep = inp->spacep;
6959 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6961 userp = smb_GetUserFromVCP(vcp, inp);
6963 caseFold = CM_FLAG_CASEFOLD;
6965 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6967 cm_ReleaseUser(userp);
6968 return CM_ERROR_NOSUCHPATH;
6971 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6972 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6973 userp, tidPathp, &req, &dscp);
6976 cm_ReleaseUser(userp);
6981 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6982 cm_ReleaseSCache(dscp);
6983 cm_ReleaseUser(userp);
6984 if ( WANTS_DFS_PATHNAMES(inp) )
6985 return CM_ERROR_PATH_NOT_COVERED;
6987 return CM_ERROR_BADSHARENAME;
6989 #endif /* DFS_SUPPORT */
6991 /* otherwise, scp points to the parent directory. Do a lookup, and
6992 * fail if we find it. Otherwise, we do the create.
6998 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6999 if (scp) cm_ReleaseSCache(scp);
7000 if (code != CM_ERROR_NOSUCHFILE) {
7001 if (code == 0) code = CM_ERROR_EXISTS;
7002 cm_ReleaseSCache(dscp);
7003 cm_ReleaseUser(userp);
7007 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7008 setAttr.clientModTime = time(NULL);
7009 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7010 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7011 smb_NotifyChange(FILE_ACTION_ADDED,
7012 FILE_NOTIFY_CHANGE_DIR_NAME,
7013 dscp, lastNamep, NULL, TRUE);
7015 /* we don't need this any longer */
7016 cm_ReleaseSCache(dscp);
7019 /* something went wrong creating or truncating the file */
7020 cm_ReleaseUser(userp);
7024 /* otherwise we succeeded */
7025 smb_SetSMBDataLength(outp, 0);
7026 cm_ReleaseUser(userp);
7031 BOOL smb_IsLegalFilename(char *filename)
7034 * Find the longest substring of filename that does not contain
7035 * any of the chars in illegalChars. If that substring is less
7036 * than the length of the whole string, then one or more of the
7037 * illegal chars is in filename.
7039 if (strcspn(filename, illegalChars) < strlen(filename))
7045 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7053 cm_scache_t *dscp; /* dir we're dealing with */
7054 cm_scache_t *scp; /* file we're creating */
7056 int initialModeBits;
7064 int created = 0; /* the file was new */
7069 excl = (inp->inCom == 0x03)? 0 : 1;
7071 attributes = smb_GetSMBParm(inp, 0);
7072 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7074 /* compute initial mode bits based on read-only flag in attributes */
7075 initialModeBits = 0666;
7076 if (attributes & SMB_ATTR_READONLY)
7077 initialModeBits &= ~0222;
7079 tp = smb_GetSMBData(inp, NULL);
7080 pathp = smb_ParseASCIIBlock(tp, &tp);
7081 if (smb_StoreAnsiFilenames)
7082 OemToChar(pathp,pathp);
7084 spacep = inp->spacep;
7085 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7087 userp = smb_GetUserFromVCP(vcp, inp);
7089 caseFold = CM_FLAG_CASEFOLD;
7091 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7093 cm_ReleaseUser(userp);
7094 return CM_ERROR_NOSUCHPATH;
7096 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7097 userp, tidPathp, &req, &dscp);
7100 cm_ReleaseUser(userp);
7105 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7106 cm_ReleaseSCache(dscp);
7107 cm_ReleaseUser(userp);
7108 if ( WANTS_DFS_PATHNAMES(inp) )
7109 return CM_ERROR_PATH_NOT_COVERED;
7111 return CM_ERROR_BADSHARENAME;
7113 #endif /* DFS_SUPPORT */
7115 /* otherwise, scp points to the parent directory. Do a lookup, and
7116 * truncate the file if we find it, otherwise we create the file.
7123 if (!smb_IsLegalFilename(lastNamep))
7124 return CM_ERROR_BADNTFILENAME;
7126 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7127 #ifdef DEBUG_VERBOSE
7130 hexp = osi_HexifyString( lastNamep );
7131 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7136 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7137 if (code && code != CM_ERROR_NOSUCHFILE) {
7138 cm_ReleaseSCache(dscp);
7139 cm_ReleaseUser(userp);
7143 /* if we get here, if code is 0, the file exists and is represented by
7144 * scp. Otherwise, we have to create it.
7148 /* oops, file shouldn't be there */
7149 cm_ReleaseSCache(dscp);
7150 cm_ReleaseSCache(scp);
7151 cm_ReleaseUser(userp);
7152 return CM_ERROR_EXISTS;
7155 setAttr.mask = CM_ATTRMASK_LENGTH;
7156 setAttr.length.LowPart = 0;
7157 setAttr.length.HighPart = 0;
7158 code = cm_SetAttr(scp, &setAttr, userp, &req);
7161 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7162 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7163 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7167 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7168 smb_NotifyChange(FILE_ACTION_ADDED,
7169 FILE_NOTIFY_CHANGE_FILE_NAME,
7170 dscp, lastNamep, NULL, TRUE);
7171 } else if (!excl && code == CM_ERROR_EXISTS) {
7172 /* not an exclusive create, and someone else tried
7173 * creating it already, then we open it anyway. We
7174 * don't bother retrying after this, since if this next
7175 * fails, that means that the file was deleted after
7176 * we started this call.
7178 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7181 setAttr.mask = CM_ATTRMASK_LENGTH;
7182 setAttr.length.LowPart = 0;
7183 setAttr.length.HighPart = 0;
7184 code = cm_SetAttr(scp, &setAttr, userp, &req);
7189 /* we don't need this any longer */
7190 cm_ReleaseSCache(dscp);
7193 /* something went wrong creating or truncating the file */
7194 if (scp) cm_ReleaseSCache(scp);
7195 cm_ReleaseUser(userp);
7199 /* make sure we only open files */
7200 if (scp->fileType != CM_SCACHETYPE_FILE) {
7201 cm_ReleaseSCache(scp);
7202 cm_ReleaseUser(userp);
7203 return CM_ERROR_ISDIR;
7206 /* now all we have to do is open the file itself */
7207 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7212 lock_ObtainMutex(&fidp->mx);
7213 /* always create it open for read/write */
7214 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7216 /* remember that the file was newly created */
7218 fidp->flags |= SMB_FID_CREATED;
7220 /* save a pointer to the vnode */
7223 fidp->userp = userp;
7224 lock_ReleaseMutex(&fidp->mx);
7226 smb_SetSMBParm(outp, 0, fidp->fid);
7227 smb_SetSMBDataLength(outp, 0);
7229 cm_Open(scp, 0, userp);
7231 smb_ReleaseFID(fidp);
7232 cm_ReleaseUser(userp);
7233 /* leave scp held since we put it in fidp->scp */
7237 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7240 osi_hyper_t new_offset;
7251 fd = smb_GetSMBParm(inp, 0);
7252 whence = smb_GetSMBParm(inp, 1);
7253 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7255 /* try to find the file descriptor */
7256 fd = smb_ChainFID(fd, inp);
7257 fidp = smb_FindFID(vcp, fd, 0);
7260 return CM_ERROR_BADFD;
7262 lock_ObtainMutex(&fidp->mx);
7263 if (fidp->flags & SMB_FID_IOCTL) {
7264 lock_ReleaseMutex(&fidp->mx);
7265 smb_ReleaseFID(fidp);
7266 return CM_ERROR_BADFD;
7268 lock_ReleaseMutex(&fidp->mx);
7270 userp = smb_GetUserFromVCP(vcp, inp);
7272 lock_ObtainMutex(&fidp->mx);
7275 lock_ReleaseMutex(&fidp->mx);
7276 lock_ObtainMutex(&scp->mx);
7277 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7278 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7281 /* offset from current offset */
7282 new_offset = LargeIntegerAdd(fidp->offset,
7283 ConvertLongToLargeInteger(offset));
7285 else if (whence == 2) {
7286 /* offset from current EOF */
7287 new_offset = LargeIntegerAdd(scp->length,
7288 ConvertLongToLargeInteger(offset));
7290 new_offset = ConvertLongToLargeInteger(offset);
7293 fidp->offset = new_offset;
7294 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7295 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7296 smb_SetSMBDataLength(outp, 0);
7298 lock_ReleaseMutex(&scp->mx);
7299 smb_ReleaseFID(fidp);
7300 cm_ReleaseSCache(scp);
7301 cm_ReleaseUser(userp);
7305 /* dispatch all of the requests received in a packet. Due to chaining, this may
7306 * be more than one request.
7308 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7309 NCB *ncbp, raw_write_cont_t *rwcp)
7313 unsigned long code = 0;
7314 unsigned char *outWctp;
7315 int nparms; /* # of bytes of parameters */
7317 int nbytes; /* bytes of data, excluding count */
7320 unsigned short errCode;
7321 unsigned long NTStatus;
7323 unsigned char errClass;
7324 unsigned int oldGen;
7325 DWORD oldTime, newTime;
7327 /* get easy pointer to the data */
7328 smbp = (smb_t *) inp->data;
7330 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7331 /* setup the basic parms for the initial request in the packet */
7332 inp->inCom = smbp->com;
7333 inp->wctp = &smbp->wct;
7335 inp->ncb_length = ncbp->ncb_length;
7340 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7341 /* log it and discard it */
7343 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7344 __FILE__, __LINE__, ncbp->ncb_length);
7346 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7350 /* We are an ongoing op */
7351 thrd_Increment(&ongoingOps);
7353 /* set up response packet for receiving output */
7354 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7355 smb_FormatResponsePacket(vcp, inp, outp);
7356 outWctp = outp->wctp;
7358 /* Remember session generation number and time */
7359 oldGen = sessionGen;
7360 oldTime = GetTickCount();
7362 while (inp->inCom != 0xff) {
7363 dp = &smb_dispatchTable[inp->inCom];
7365 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7366 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7367 code = outp->resumeCode;
7371 /* process each request in the packet; inCom, wctp and inCount
7372 * are already set up.
7374 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7377 /* now do the dispatch */
7378 /* start by formatting the response record a little, as a default */
7379 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7381 outWctp[1] = 0xff; /* no operation */
7382 outWctp[2] = 0; /* padding */
7387 /* not a chained request, this is a more reasonable default */
7388 outWctp[0] = 0; /* wct of zero */
7389 outWctp[1] = 0; /* and bcc (word) of zero */
7393 /* once set, stays set. Doesn't matter, since we never chain
7394 * "no response" calls.
7396 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7400 /* we have a recognized operation */
7402 if (inp->inCom == 0x1d)
7404 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7406 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7407 code = (*(dp->procp)) (vcp, inp, outp);
7408 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7410 if ( code == CM_ERROR_BADSMB ||
7411 code == CM_ERROR_BADOP )
7413 #endif /* LOG_PACKET */
7416 if (oldGen != sessionGen) {
7417 newTime = GetTickCount();
7419 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7420 newTime - oldTime, ncbp->ncb_length);
7422 osi_Log2(smb_logp, "Pkt straddled session startup, "
7423 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7427 /* bad opcode, fail the request, after displaying it */
7428 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7431 #endif /* LOG_PACKET */
7435 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7436 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7437 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7438 if (code == IDCANCEL)
7442 code = CM_ERROR_BADOP;
7445 /* catastrophic failure: log as much as possible */
7446 if (code == CM_ERROR_BADSMB) {
7448 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7453 #endif /* LOG_PACKET */
7454 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7457 code = CM_ERROR_INVAL;
7460 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7461 thrd_Decrement(&ongoingOps);
7466 /* now, if we failed, turn the current response into an empty
7467 * one, and fill in the response packet's error code.
7470 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7471 smb_MapNTError(code, &NTStatus);
7472 outWctp = outp->wctp;
7473 smbp = (smb_t *) &outp->data;
7474 if (code != CM_ERROR_PARTIALWRITE
7475 && code != CM_ERROR_BUFFERTOOSMALL
7476 && code != CM_ERROR_GSSCONTINUE) {
7477 /* nuke wct and bcc. For a partial
7478 * write or an in-process authentication handshake,
7479 * assume they're OK.
7485 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7486 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7487 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7488 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7489 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7493 smb_MapCoreError(code, vcp, &errCode, &errClass);
7494 outWctp = outp->wctp;
7495 smbp = (smb_t *) &outp->data;
7496 if (code != CM_ERROR_PARTIALWRITE) {
7497 /* nuke wct and bcc. For a partial
7498 * write, assume they're OK.
7504 smbp->errLow = (unsigned char) (errCode & 0xff);
7505 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7506 smbp->rcls = errClass;
7509 } /* error occurred */
7511 /* if we're here, we've finished one request. Look to see if
7512 * this is a chained opcode. If it is, setup things to process
7513 * the chained request, and setup the output buffer to hold the
7514 * chained response. Start by finding the next input record.
7516 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7517 break; /* not a chained req */
7518 tp = inp->wctp; /* points to start of last request */
7519 /* in a chained request, the first two
7520 * parm fields are required, and are
7521 * AndXCommand/AndXReserved and
7523 if (tp[0] < 2) break;
7524 if (tp[1] == 0xff) break; /* no more chained opcodes */
7526 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7529 /* and now append the next output request to the end of this
7530 * last request. Begin by finding out where the last response
7531 * ends, since that's where we'll put our new response.
7533 outWctp = outp->wctp; /* ptr to out parameters */
7534 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7535 nparms = outWctp[0] << 1;
7536 tp = outWctp + nparms + 1; /* now points to bcc field */
7537 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7538 tp += 2 /* for the count itself */ + nbytes;
7539 /* tp now points to the new output record; go back and patch the
7540 * second parameter (off2) to point to the new record.
7542 temp = (unsigned int)(tp - outp->data);
7543 outWctp[3] = (unsigned char) (temp & 0xff);
7544 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7545 outWctp[2] = 0; /* padding */
7546 outWctp[1] = inp->inCom; /* next opcode */
7548 /* finally, setup for the next iteration */
7551 } /* while loop over all requests in the packet */
7553 /* now send the output packet, and return */
7555 smb_SendPacket(vcp, outp);
7556 thrd_Decrement(&ongoingOps);
7562 /* Wait for Netbios() calls to return, and make the results available to server
7563 * threads. Note that server threads can't wait on the NCBevents array
7564 * themselves, because NCB events are manual-reset, and the servers would race
7565 * each other to reset them.
7567 void smb_ClientWaiter(void *parmp)
7572 while (smbShutdownFlag == 0) {
7573 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7575 if (code == WAIT_OBJECT_0)
7578 /* error checking */
7579 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7581 int abandonIdx = code - WAIT_ABANDONED_0;
7582 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7585 if (code == WAIT_IO_COMPLETION)
7587 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7591 if (code == WAIT_TIMEOUT)
7593 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7596 if (code == WAIT_FAILED)
7598 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7601 idx = code - WAIT_OBJECT_0;
7603 /* check idx range! */
7604 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7606 /* this is fatal - log as much as possible */
7607 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7611 thrd_ResetEvent(NCBevents[idx]);
7612 thrd_SetEvent(NCBreturns[0][idx]);
7618 * Try to have one NCBRECV request waiting for every live session. Not more
7619 * than one, because if there is more than one, it's hard to handle Write Raw.
7621 void smb_ServerWaiter(void *parmp)
7624 int idx_session, idx_NCB;
7630 while (smbShutdownFlag == 0) {
7632 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7634 if (code == WAIT_OBJECT_0)
7637 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7639 int abandonIdx = code - WAIT_ABANDONED_0;
7640 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7643 if (code == WAIT_IO_COMPLETION)
7645 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7649 if (code == WAIT_TIMEOUT)
7651 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7654 if (code == WAIT_FAILED)
7656 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7659 idx_session = code - WAIT_OBJECT_0;
7661 /* check idx range! */
7662 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7664 /* this is fatal - log as much as possible */
7665 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7671 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7673 if (code == WAIT_OBJECT_0) {
7674 if (smbShutdownFlag == 1)
7680 /* error checking */
7681 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7683 int abandonIdx = code - WAIT_ABANDONED_0;
7684 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7687 if (code == WAIT_IO_COMPLETION)
7689 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7693 if (code == WAIT_TIMEOUT)
7695 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7698 if (code == WAIT_FAILED)
7700 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7703 idx_NCB = code - WAIT_OBJECT_0;
7705 /* check idx range! */
7706 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7708 /* this is fatal - log as much as possible */
7709 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7713 /* Link them together */
7714 NCBsessions[idx_NCB] = idx_session;
7717 ncbp = NCBs[idx_NCB];
7718 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7719 ncbp->ncb_command = NCBRECV | ASYNCH;
7720 ncbp->ncb_lana_num = lanas[idx_session];
7722 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7723 ncbp->ncb_event = NCBevents[idx_NCB];
7724 ncbp->ncb_length = SMB_PACKETSIZE;
7727 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7728 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7729 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7730 ncbp->ncb_length = SMB_PACKETSIZE;
7731 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7732 Netbios(ncbp, dos_ncb);
7738 * The top level loop for handling SMB request messages. Each server thread
7739 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7740 * NCB and buffer for the incoming request are loaned to us.
7742 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7743 * to immediately send a request for the rest of the data. This must come
7744 * before any other traffic for that session, so we delay setting the session
7745 * event until that data has come in.
7747 void smb_Server(VOID *parmp)
7749 INT_PTR myIdx = (INT_PTR) parmp;
7753 smb_packet_t *outbufp;
7755 int idx_NCB, idx_session;
7757 smb_vc_t *vcp = NULL;
7763 rx_StartClientThread();
7766 outbufp = GetPacket();
7767 outbufp->ncbp = outncbp;
7775 smb_ResetServerPriority();
7777 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7780 /* terminate silently if shutdown flag is set */
7781 if (code == WAIT_OBJECT_0) {
7782 if (smbShutdownFlag == 1) {
7783 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7789 /* error checking */
7790 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7792 int abandonIdx = code - WAIT_ABANDONED_0;
7793 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7796 if (code == WAIT_IO_COMPLETION)
7798 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7802 if (code == WAIT_TIMEOUT)
7804 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7807 if (code == WAIT_FAILED)
7809 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7812 idx_NCB = code - WAIT_OBJECT_0;
7814 /* check idx range! */
7815 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7817 /* this is fatal - log as much as possible */
7818 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7822 ncbp = NCBs[idx_NCB];
7824 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7826 idx_session = NCBsessions[idx_NCB];
7827 rc = ncbp->ncb_retcode;
7829 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7830 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7834 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7838 /* Can this happen? Or is it just my UNIX paranoia? */
7839 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7845 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7849 /* Client closed session */
7850 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7852 lock_ObtainMutex(&vcp->mx);
7853 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7854 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7856 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7857 lock_ReleaseMutex(&vcp->mx);
7858 lock_ObtainWrite(&smb_globalLock);
7859 dead_sessions[vcp->session] = TRUE;
7860 lock_ReleaseWrite(&smb_globalLock);
7861 smb_CleanupDeadVC(vcp);
7865 lock_ReleaseMutex(&vcp->mx);
7871 /* Treat as transient error */
7873 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7877 "dispatch smb recv failed, message incomplete, ncb_length %d",
7880 "SMB message incomplete, "
7881 "length %d", ncbp->ncb_length);
7884 * We used to discard the packet.
7885 * Instead, try handling it normally.
7889 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7893 /* A weird error code. Log it, sleep, and continue. */
7894 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7896 lock_ObtainMutex(&vcp->mx);
7897 if (vcp && vcp->errorCount++ > 3) {
7898 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7899 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7900 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7902 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7903 lock_ReleaseMutex(&vcp->mx);
7904 lock_ObtainWrite(&smb_globalLock);
7905 dead_sessions[vcp->session] = TRUE;
7906 lock_ReleaseWrite(&smb_globalLock);
7907 smb_CleanupDeadVC(vcp);
7911 lock_ReleaseMutex(&vcp->mx);
7917 lock_ReleaseMutex(&vcp->mx);
7919 thrd_SetEvent(SessionEvents[idx_session]);
7924 /* Success, so now dispatch on all the data in the packet */
7926 smb_concurrentCalls++;
7927 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7928 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7931 * If at this point vcp is NULL (implies that packet was invalid)
7932 * then we are in big trouble. This means either :
7933 * a) we have the wrong NCB.
7934 * b) Netbios screwed up the call.
7935 * c) The VC was already marked dead before we were able to
7937 * Obviously this implies that
7938 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7939 * lanas[idx_session] != ncbp->ncb_lana_num )
7940 * Either way, we can't do anything with this packet.
7941 * Log, sleep and resume.
7944 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7948 ncbp->ncb_lana_num);
7950 /* Also log in the trace log. */
7951 osi_Log4(smb_logp, "Server: VCP does not exist!"
7952 "LSNs[idx_session]=[%d],"
7953 "lanas[idx_session]=[%d],"
7954 "ncbp->ncb_lsn=[%d],"
7955 "ncbp->ncb_lana_num=[%d]",
7959 ncbp->ncb_lana_num);
7961 /* thrd_Sleep(1000); Don't bother sleeping */
7962 thrd_SetEvent(SessionEvents[idx_session]);
7963 smb_concurrentCalls--;
7967 smb_SetRequestStartTime();
7969 vcp->errorCount = 0;
7970 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7972 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7973 /* copy whole packet to virtual memory */
7974 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7976 bufp->dos_pkt / 16, bufp);*/
7978 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7980 smbp = (smb_t *)bufp->data;
7983 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7987 if (smbp->com == 0x1d) {
7988 /* Special handling for Write Raw */
7989 raw_write_cont_t rwc;
7990 EVENT_HANDLE rwevent;
7991 char eventName[MAX_PATH];
7993 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7994 if (rwc.code == 0) {
7995 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7996 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7997 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7998 ncbp->ncb_command = NCBRECV | ASYNCH;
7999 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8000 ncbp->ncb_lana_num = vcp->lana;
8001 ncbp->ncb_buffer = rwc.buf;
8002 ncbp->ncb_length = 65535;
8003 ncbp->ncb_event = rwevent;
8007 Netbios(ncbp, dos_ncb);
8009 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8010 thrd_CloseHandle(rwevent);
8012 thrd_SetEvent(SessionEvents[idx_session]);
8014 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8016 else if (smbp->com == 0xa0) {
8018 * Serialize the handling for NT Transact
8021 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8022 thrd_SetEvent(SessionEvents[idx_session]);
8024 thrd_SetEvent(SessionEvents[idx_session]);
8025 /* TODO: what else needs to be serialized? */
8026 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8028 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8030 __except( smb_ServerExceptionFilter() ) {
8034 smb_concurrentCalls--;
8037 thrd_SetEvent(NCBavails[idx_NCB]);
8044 * Exception filter for the server threads. If an exception occurs in the
8045 * dispatch routines, which is where exceptions are most common, then do a
8046 * force trace and give control to upstream exception handlers. Useful for
8049 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8050 DWORD smb_ServerExceptionFilter(void) {
8051 /* While this is not the best time to do a trace, if it succeeds, then
8052 * we have a trace (assuming tracing was enabled). Otherwise, this should
8053 * throw a second exception.
8055 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8056 afsd_ForceTrace(TRUE);
8057 buf_ForceTrace(TRUE);
8058 return EXCEPTION_CONTINUE_SEARCH;
8063 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8064 * If the number of server threads is M, and the number of live sessions is
8065 * N, then the number of NCB's in use at any time either waiting for, or
8066 * holding, received messages is M + N, so that is how many NCB's get created.
8068 void InitNCBslot(int idx)
8070 struct smb_packet *bufp;
8071 EVENT_HANDLE retHandle;
8073 char eventName[MAX_PATH];
8075 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
8077 NCBs[idx] = GetNCB();
8078 sprintf(eventName,"NCBavails[%d]", idx);
8079 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8080 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8081 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8083 sprintf(eventName,"NCBevents[%d]", idx);
8084 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8085 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8086 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8088 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8089 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8090 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8091 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8092 for (i=0; i<smb_NumServerThreads; i++)
8093 NCBreturns[i][idx] = retHandle;
8095 bufp->spacep = cm_GetSpace();
8099 /* listen for new connections */
8100 void smb_Listener(void *parmp)
8106 int session, thread;
8107 smb_vc_t *vcp = NULL;
8109 char rname[NCBNAMSZ+1];
8110 char cname[MAX_COMPUTERNAME_LENGTH+1];
8111 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8116 INT_PTR lana = (INT_PTR) parmp;
8120 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8123 /* retrieve computer name */
8124 GetComputerName(cname, &cnamelen);
8128 memset(ncbp, 0, sizeof(NCB));
8131 ncbp->ncb_command = NCBLISTEN;
8132 ncbp->ncb_rto = 0; /* No receive timeout */
8133 ncbp->ncb_sto = 0; /* No send timeout */
8135 /* pad out with spaces instead of null termination */
8136 len = (long)strlen(smb_localNamep);
8137 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8138 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8140 strcpy(ncbp->ncb_callname, "*");
8141 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8143 ncbp->ncb_lana_num = (UCHAR)lana;
8146 code = Netbios(ncbp);
8148 code = Netbios(ncbp, dos_ncb);
8157 /* terminate silently if shutdown flag is set */
8158 if (smbShutdownFlag == 1) {
8167 "NCBLISTEN lana=%d failed with code %d",
8168 ncbp->ncb_lana_num, code);
8170 "Client exiting due to network failure. Please restart client.\n");
8174 "Client exiting due to network failure. Please restart client.\n"
8175 "NCBLISTEN lana=%d failed with code %d",
8176 ncbp->ncb_lana_num, code);
8178 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8179 MB_OK|MB_SERVICE_NOTIFICATION);
8180 osi_assert(tbuffer);
8183 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8184 ncbp->ncb_lana_num, code);
8185 fprintf(stderr, "\nClient exiting due to network failure "
8186 "(possibly due to power-saving mode)\n");
8187 fprintf(stderr, "Please restart client.\n");
8188 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8192 /* check for remote conns */
8193 /* first get remote name and insert null terminator */
8194 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8195 for (i=NCBNAMSZ; i>0; i--) {
8196 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8202 /* compare with local name */
8204 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8205 flags |= SMB_VCFLAG_REMOTECONN;
8208 lock_ObtainMutex(&smb_ListenerLock);
8210 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8211 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8213 /* now ncbp->ncb_lsn is the connection ID */
8214 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8215 if (vcp->session == 0) {
8216 /* New generation */
8217 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8220 /* Log session startup */
8222 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8223 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8224 #endif /* NOTSERVICE */
8225 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8226 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8228 if (reportSessionStartups) {
8230 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8233 fprintf(stderr, "%s: New session %d starting from host %s\n",
8234 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8239 lock_ObtainMutex(&vcp->mx);
8240 strcpy(vcp->rname, rname);
8241 vcp->flags |= flags;
8242 lock_ReleaseMutex(&vcp->mx);
8244 /* Allocate slot in session arrays */
8245 /* Re-use dead session if possible, otherwise add one more */
8246 /* But don't look at session[0], it is reserved */
8247 lock_ObtainWrite(&smb_globalLock);
8248 for (session = 1; session < numSessions; session++) {
8249 if (dead_sessions[session]) {
8250 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8251 dead_sessions[session] = FALSE;
8255 lock_ReleaseWrite(&smb_globalLock);
8257 /* We are re-using an existing VC because the lsn and lana
8259 session = vcp->session;
8261 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8263 /* Log session startup */
8265 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8266 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8267 #endif /* NOTSERVICE */
8268 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8269 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8271 if (reportSessionStartups) {
8273 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8276 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8277 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8283 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8284 unsigned long code = CM_ERROR_ALLBUSY;
8285 smb_packet_t * outp = GetPacket();
8286 unsigned char *outWctp;
8289 smb_FormatResponsePacket(vcp, NULL, outp);
8292 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8293 unsigned long NTStatus;
8294 smb_MapNTError(code, &NTStatus);
8295 outWctp = outp->wctp;
8296 smbp = (smb_t *) &outp->data;
8300 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8301 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8302 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8303 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8304 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8306 unsigned short errCode;
8307 unsigned char errClass;
8308 smb_MapCoreError(code, vcp, &errCode, &errClass);
8309 outWctp = outp->wctp;
8310 smbp = (smb_t *) &outp->data;
8314 smbp->errLow = (unsigned char) (errCode & 0xff);
8315 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8316 smbp->rcls = errClass;
8318 smb_SendPacket(vcp, outp);
8319 smb_FreePacket(outp);
8321 lock_ObtainMutex(&vcp->mx);
8322 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8323 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8325 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8326 lock_ReleaseMutex(&vcp->mx);
8327 lock_ObtainWrite(&smb_globalLock);
8328 dead_sessions[vcp->session] = TRUE;
8329 lock_ReleaseWrite(&smb_globalLock);
8330 smb_CleanupDeadVC(vcp);
8332 lock_ReleaseMutex(&vcp->mx);
8335 /* assert that we do not exceed the maximum number of sessions or NCBs.
8336 * we should probably want to wait for a session to be freed in case
8339 osi_assert(session < SESSION_MAX - 1);
8340 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8342 lock_ObtainMutex(&vcp->mx);
8343 vcp->session = session;
8344 lock_ReleaseMutex(&vcp->mx);
8345 lock_ObtainWrite(&smb_globalLock);
8346 LSNs[session] = ncbp->ncb_lsn;
8347 lanas[session] = ncbp->ncb_lana_num;
8348 lock_ReleaseWrite(&smb_globalLock);
8350 if (session == numSessions) {
8351 /* Add new NCB for new session */
8352 char eventName[MAX_PATH];
8354 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8356 InitNCBslot(numNCBs);
8357 lock_ObtainWrite(&smb_globalLock);
8359 lock_ReleaseWrite(&smb_globalLock);
8360 thrd_SetEvent(NCBavails[0]);
8361 thrd_SetEvent(NCBevents[0]);
8362 for (thread = 0; thread < smb_NumServerThreads; thread++)
8363 thrd_SetEvent(NCBreturns[thread][0]);
8364 /* Also add new session event */
8365 sprintf(eventName, "SessionEvents[%d]", session);
8366 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8367 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8368 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8369 lock_ObtainWrite(&smb_globalLock);
8371 lock_ReleaseWrite(&smb_globalLock);
8372 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8373 thrd_SetEvent(SessionEvents[0]);
8375 thrd_SetEvent(SessionEvents[session]);
8381 lock_ReleaseMutex(&smb_ListenerLock);
8382 } /* dispatch while loop */
8385 /* initialize Netbios */
8386 void smb_NetbiosInit()
8392 int i, lana, code, l;
8394 int delname_tried=0;
8397 OSVERSIONINFO Version;
8399 /* Get the version of Windows */
8400 memset(&Version, 0x00, sizeof(Version));
8401 Version.dwOSVersionInfoSize = sizeof(Version);
8402 GetVersionEx(&Version);
8404 /* setup the NCB system */
8407 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8411 if (smb_LANadapter == -1) {
8412 ncbp->ncb_command = NCBENUM;
8413 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8414 ncbp->ncb_length = sizeof(lana_list);
8415 code = Netbios(ncbp);
8417 afsi_log("Netbios NCBENUM error code %d", code);
8418 osi_panic(s, __FILE__, __LINE__);
8422 lana_list.length = 1;
8423 lana_list.lana[0] = smb_LANadapter;
8426 for (i = 0; i < lana_list.length; i++) {
8427 /* reset the adaptor: in Win32, this is required for every process, and
8428 * acts as an init call, not as a real hardware reset.
8430 ncbp->ncb_command = NCBRESET;
8431 ncbp->ncb_callname[0] = 100;
8432 ncbp->ncb_callname[2] = 100;
8433 ncbp->ncb_lana_num = lana_list.lana[i];
8434 code = Netbios(ncbp);
8436 code = ncbp->ncb_retcode;
8438 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8439 lana_list.lana[i] = 255; /* invalid lana */
8441 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8445 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8446 we will just fake the LANA list */
8447 if (smb_LANadapter == -1) {
8448 for (i = 0; i < 8; i++)
8449 lana_list.lana[i] = i;
8450 lana_list.length = 8;
8453 lana_list.length = 1;
8454 lana_list.lana[0] = smb_LANadapter;
8458 /* and declare our name so we can receive connections */
8459 memset(ncbp, 0, sizeof(*ncbp));
8460 len=lstrlen(smb_localNamep);
8461 memset(smb_sharename,' ',NCBNAMSZ);
8462 memcpy(smb_sharename,smb_localNamep,len);
8463 afsi_log("lana_list.length %d", lana_list.length);
8465 /* Keep the name so we can unregister it later */
8466 for (l = 0; l < lana_list.length; l++) {
8467 lana = lana_list.lana[l];
8469 ncbp->ncb_command = NCBADDNAME;
8470 ncbp->ncb_lana_num = lana;
8471 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8473 code = Netbios(ncbp);
8475 code = Netbios(ncbp, dos_ncb);
8478 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8479 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8481 char name[NCBNAMSZ+1];
8483 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8484 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8487 if (code == 0) code = ncbp->ncb_retcode;
8489 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8491 /* we only use one LANA with djgpp */
8492 lana_list.lana[0] = lana;
8493 lana_list.length = 1;
8497 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8498 if (code == NRC_BRIDGE) { /* invalid LANA num */
8499 lana_list.lana[l] = 255;
8502 else if (code == NRC_DUPNAME) {
8503 afsi_log("Name already exists; try to delete it");
8504 memset(ncbp, 0, sizeof(*ncbp));
8505 ncbp->ncb_command = NCBDELNAME;
8506 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8507 ncbp->ncb_lana_num = lana;
8509 code = Netbios(ncbp);
8511 code = Netbios(ncbp, dos_ncb);
8514 code = ncbp->ncb_retcode;
8516 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8518 if (code != 0 || delname_tried) {
8519 lana_list.lana[l] = 255;
8521 else if (code == 0) {
8522 if (!delname_tried) {
8530 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8531 lana_list.lana[l] = 255; /* invalid lana */
8532 osi_panic(s, __FILE__, __LINE__);
8536 lana_found = 1; /* at least one worked */
8543 osi_assert(lana_list.length >= 0);
8545 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8548 /* we're done with the NCB now */
8552 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8569 EVENT_HANDLE retHandle;
8570 char eventName[MAX_PATH];
8572 smb_TlsRequestSlot = TlsAlloc();
8575 smb_MBfunc = aMBfunc;
8579 smb_LANadapter = LANadapt;
8581 /* Initialize smb_localZero */
8582 myTime.tm_isdst = -1; /* compute whether on DST or not */
8583 myTime.tm_year = 70;
8589 smb_localZero = mktime(&myTime);
8591 #ifndef USE_NUMERIC_TIME_CONV
8592 /* Initialize kludge-GMT */
8593 smb_CalculateNowTZ();
8594 #endif /* USE_NUMERIC_TIME_CONV */
8595 #ifdef AFS_FREELANCE_CLIENT
8596 /* Make sure the root.afs volume has the correct time */
8597 cm_noteLocalMountPointChange();
8600 /* initialize the remote debugging log */
8603 /* remember the name */
8604 len = (int)strlen(snamep);
8605 smb_localNamep = malloc(len+1);
8606 strcpy(smb_localNamep, snamep);
8607 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8609 /* and the global lock */
8610 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8611 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8613 /* Raw I/O data structures */
8614 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8616 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8618 /* 4 Raw I/O buffers */
8620 smb_RawBufs = calloc(65536,1);
8621 *((char **)smb_RawBufs) = NULL;
8622 for (i=0; i<3; i++) {
8623 char *rawBuf = calloc(65536,1);
8624 *((char **)rawBuf) = smb_RawBufs;
8625 smb_RawBufs = rawBuf;
8628 npar = 65536 >> 4; /* number of paragraphs */
8629 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8631 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8633 osi_panic("",__FILE__,__LINE__);
8636 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8639 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8641 _farpokel(_dos_ds, smb_RawBufs, NULL);
8642 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8643 npar = 65536 >> 4; /* number of paragraphs */
8644 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8646 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8648 osi_panic("",__FILE__,__LINE__);
8651 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8654 rawBuf = (seg * 16) + 0; /* DOS physical address */
8655 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8656 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8657 smb_RawBufs = rawBuf;
8661 /* global free lists */
8662 smb_ncbFreeListp = NULL;
8663 smb_packetFreeListp = NULL;
8667 /* Initialize listener and server structures */
8669 memset(dead_sessions, 0, sizeof(dead_sessions));
8670 sprintf(eventName, "SessionEvents[0]");
8671 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8672 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8673 afsi_log("Event Object Already Exists: %s", eventName);
8675 smb_NumServerThreads = nThreads;
8676 sprintf(eventName, "NCBavails[0]");
8677 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8678 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8679 afsi_log("Event Object Already Exists: %s", eventName);
8680 sprintf(eventName, "NCBevents[0]");
8681 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8682 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8683 afsi_log("Event Object Already Exists: %s", eventName);
8684 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8685 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8686 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8687 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8688 afsi_log("Event Object Already Exists: %s", eventName);
8689 for (i = 0; i < smb_NumServerThreads; i++) {
8690 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8691 NCBreturns[i][0] = retHandle;
8694 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8695 for (i = 0; i < smb_NumServerThreads; i++) {
8696 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8697 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8698 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8699 afsi_log("Event Object Already Exists: %s", eventName);
8700 InitNCBslot((int)(i+1));
8702 numNCBs = smb_NumServerThreads + 1;
8704 /* Initialize dispatch table */
8705 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8706 /* Prepare the table for unknown operations */
8707 for(i=0; i<= SMB_NOPCODES; i++) {
8708 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8710 /* Fill in the ones we do know */
8711 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8712 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8713 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8714 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8715 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8716 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8717 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8718 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8719 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8720 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8721 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8722 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8723 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8724 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8725 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8726 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8727 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8728 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8729 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8730 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8731 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8732 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8733 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8734 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8735 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8736 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8737 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8738 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8739 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8740 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8741 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8742 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8743 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8744 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8745 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8746 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8747 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8748 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8749 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8750 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8751 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8752 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8753 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8754 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8755 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8756 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8757 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8758 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8759 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8760 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8761 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8762 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8763 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8764 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8765 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8766 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8767 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8768 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8769 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8770 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8771 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8772 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8773 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8774 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8775 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8776 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8777 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8778 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8779 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8780 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8781 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8782 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8783 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8784 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8786 /* setup tran 2 dispatch table */
8787 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8788 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8789 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8790 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8791 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8792 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8793 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8794 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8795 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8796 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8797 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8798 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8799 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8800 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8801 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8802 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8803 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8804 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8806 /* setup the rap dispatch table */
8807 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8808 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8809 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8810 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8811 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8815 /* if we are doing SMB authentication we have register outselves as a logon process */
8816 if (smb_authType != SMB_AUTH_NONE) {
8817 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8818 LSA_STRING afsProcessName;
8819 LSA_OPERATIONAL_MODE dummy; /*junk*/
8821 afsProcessName.Buffer = "OpenAFSClientDaemon";
8822 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8823 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8825 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8827 if (nts == STATUS_SUCCESS) {
8828 LSA_STRING packageName;
8829 /* we are registered. Find out the security package id */
8830 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8831 packageName.Length = (USHORT)strlen(packageName.Buffer);
8832 packageName.MaximumLength = packageName.Length + 1;
8833 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8834 if (nts == STATUS_SUCCESS) {
8836 * This code forces Windows to authenticate against the Logon Cache
8837 * first instead of attempting to authenticate against the Domain
8838 * Controller. When the Windows logon cache is enabled this improves
8839 * performance by removing the network access and works around a bug
8840 * seen at sites which are using a MIT Kerberos principal to login
8841 * to machines joined to a non-root domain in a multi-domain forest.
8843 PVOID pResponse = NULL;
8844 ULONG cbResponse = 0;
8845 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8847 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8848 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8849 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8850 OptionsRequest.DisableOptions = FALSE;
8852 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8855 sizeof(OptionsRequest),
8861 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8863 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8865 OutputDebugString(message);
8868 OutputDebugString("MsV1_0SetProcessOption success");
8869 afsi_log("MsV1_0SetProcessOption success");
8871 /* END - code from Larry */
8873 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8874 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8875 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8877 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8879 /* something went wrong. We report the error and revert back to no authentication
8880 because we can't perform any auth requests without a successful lsa handle
8881 or sec package id. */
8882 afsi_log("Reverting to NO SMB AUTH");
8883 smb_authType = SMB_AUTH_NONE;
8886 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8888 /* something went wrong. We report the error and revert back to no authentication
8889 because we can't perform any auth requests without a successful lsa handle
8890 or sec package id. */
8891 afsi_log("Reverting to NO SMB AUTH");
8892 smb_authType = SMB_AUTH_NONE;
8896 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8897 * time prevents the failure of authentication when logged into Windows with an
8898 * external Kerberos principal mapped to a local account.
8900 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8901 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8902 * then the only option is NTLMSSP anyway; so just fallback.
8907 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8908 if (secBlobLength == 0) {
8909 smb_authType = SMB_AUTH_NTLM;
8910 afsi_log("Reverting to SMB AUTH NTLM");
8919 /* Now get ourselves a domain name. */
8920 /* For now we are using the local computer name as the domain name.
8921 * It is actually the domain for local logins, and we are acting as
8922 * a local SMB server.
8924 bufsize = sizeof(smb_ServerDomainName) - 1;
8925 GetComputerName(smb_ServerDomainName, &bufsize);
8926 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8927 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8930 /* Start listeners, waiters, servers, and daemons */
8932 for (i = 0; i < lana_list.length; i++) {
8933 if (lana_list.lana[i] == 255)
8935 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8936 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8937 osi_assert(phandle != NULL);
8938 thrd_CloseHandle(phandle);
8942 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8943 NULL, 0, &lpid, "smb_ClientWaiter");
8944 osi_assert(phandle != NULL);
8945 thrd_CloseHandle(phandle);
8948 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8949 NULL, 0, &lpid, "smb_ServerWaiter");
8950 osi_assert(phandle != NULL);
8951 thrd_CloseHandle(phandle);
8953 for (i=0; i<smb_NumServerThreads; i++) {
8954 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8955 (void *) i, 0, &lpid, "smb_Server");
8956 osi_assert(phandle != NULL);
8957 thrd_CloseHandle(phandle);
8960 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8961 NULL, 0, &lpid, "smb_Daemon");
8962 osi_assert(phandle != NULL);
8963 thrd_CloseHandle(phandle);
8965 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8966 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8967 osi_assert(phandle != NULL);
8968 thrd_CloseHandle(phandle);
8977 void smb_Shutdown(void)
8987 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8989 /* setup the NCB system */
8992 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8995 /* Block new sessions by setting shutdown flag */
8996 smbShutdownFlag = 1;
8998 /* Hang up all sessions */
8999 memset((char *)ncbp, 0, sizeof(NCB));
9000 for (i = 1; i < numSessions; i++)
9002 if (dead_sessions[i])
9005 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9006 ncbp->ncb_command = NCBHANGUP;
9007 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9008 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9010 code = Netbios(ncbp);
9012 code = Netbios(ncbp, dos_ncb);
9014 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9015 if (code == 0) code = ncbp->ncb_retcode;
9017 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9018 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9022 /* Trigger the shutdown of all SMB threads */
9023 for (i = 0; i < smb_NumServerThreads; i++)
9024 thrd_SetEvent(NCBreturns[i][0]);
9026 thrd_SetEvent(NCBevents[0]);
9027 thrd_SetEvent(SessionEvents[0]);
9028 thrd_SetEvent(NCBavails[0]);
9030 for (i = 0;i < smb_NumServerThreads; i++) {
9031 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9032 if (code == WAIT_OBJECT_0) {
9035 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9036 thrd_SetEvent(NCBreturns[i--][0]);
9040 /* Delete Netbios name */
9041 memset((char *)ncbp, 0, sizeof(NCB));
9042 for (i = 0; i < lana_list.length; i++) {
9043 if (lana_list.lana[i] == 255) continue;
9044 ncbp->ncb_command = NCBDELNAME;
9045 ncbp->ncb_lana_num = lana_list.lana[i];
9046 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9048 code = Netbios(ncbp);
9050 code = Netbios(ncbp, dos_ncb);
9053 code = ncbp->ncb_retcode;
9055 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9056 ncbp->ncb_lana_num, code);
9061 /* Release the reference counts held by the VCs */
9062 lock_ObtainWrite(&smb_rctLock);
9063 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9068 if (vcp->magic != SMB_VC_MAGIC)
9069 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9070 __FILE__, __LINE__);
9072 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9074 if (fidp->scp != NULL) {
9077 lock_ObtainMutex(&fidp->mx);
9078 if (fidp->scp != NULL) {
9081 cm_ReleaseSCache(scp);
9083 lock_ReleaseMutex(&fidp->mx);
9087 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9089 smb_ReleaseVCNoLock(tidp->vcp);
9091 cm_user_t *userp = tidp->userp;
9093 lock_ReleaseWrite(&smb_rctLock);
9094 cm_ReleaseUser(userp);
9095 lock_ObtainWrite(&smb_rctLock);
9099 lock_ReleaseWrite(&smb_rctLock);
9101 TlsFree(smb_TlsRequestSlot);
9104 /* Get the UNC \\<servername>\<sharename> prefix. */
9105 char *smb_GetSharename()
9109 /* Make sure we have been properly initialized. */
9110 if (smb_localNamep == NULL)
9113 /* Allocate space for \\<servername>\<sharename>, plus the
9116 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9117 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9123 void smb_LogPacket(smb_packet_t *packet)
9126 unsigned length, paramlen, datalen, i, j;
9128 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9130 if (!packet) return;
9132 osi_Log0(smb_logp, "*** SMB packet dump ***");
9134 vp = (BYTE *) packet->data;
9136 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9137 length = paramlen + 2 + datalen;
9140 for (i=0;i < length; i+=16)
9142 memset( buf, ' ', 80 );
9147 buf[strlen(buf)] = ' ';
9149 cp = (BYTE*) buf + 7;
9151 for (j=0;j < 16 && (i+j)<length; j++)
9153 *(cp++) = hex[vp[i+j] >> 4];
9154 *(cp++) = hex[vp[i+j] & 0xf];
9164 for (j=0;j < 16 && (i+j)<length;j++)
9166 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9177 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9180 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9182 #endif /* LOG_PACKET */
9185 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9193 lock_ObtainRead(&smb_rctLock);
9195 sprintf(output, "begin dumping smb_vc_t\n");
9196 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9198 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9202 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9203 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9204 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9206 sprintf(output, "begin dumping smb_fid_t\n");
9207 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9209 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9211 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",
9212 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9213 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9214 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9215 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9218 sprintf(output, "done dumping smb_fid_t\n");
9219 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9222 sprintf(output, "done dumping smb_vc_t\n");
9223 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9225 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9226 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9228 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9232 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9233 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9234 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9236 sprintf(output, "begin dumping smb_fid_t\n");
9237 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9239 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9241 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",
9242 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9243 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9244 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9245 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9248 sprintf(output, "done dumping smb_fid_t\n");
9249 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9252 sprintf(output, "done dumping DEAD smb_vc_t\n");
9253 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9255 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9256 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9258 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9262 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9263 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9264 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9266 sprintf(output, "begin dumping smb_fid_t\n");
9267 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9269 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9271 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",
9272 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9273 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9274 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9275 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9278 sprintf(output, "done dumping smb_fid_t\n");
9279 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9282 sprintf(output, "done dumping DEAD smb_vc_t\n");
9283 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9286 lock_ReleaseRead(&smb_rctLock);