/** * Figure the type of a file/dir based on path and FS object info. * * @returns The type. * @param pszPath The path to the file/dir. * @param pObjInfo The object information, symlinks followed. */ static RTDBGSYMCACHEFILETYPE rtDbgSymCacheFigureType2(const char *pszPath, PCRTFSOBJINFO pObjInfo) { const char *pszName = RTPathFilename(pszPath); const char *pszExt = RTPathSuffix(pszName); if (pszExt) pszExt++; else pszExt = ""; if ( RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode) || (pObjInfo->Attr.fMode & RTFS_DOS_DIRECTORY)) /** @todo OS X samba reports reparse points in /Volumes/ that we cannot resolve. */ { /* Skip directories shouldn't bother with. */ if ( !RTStrICmp(pszName, ".Trashes") || !RTStrICmp(pszName, ".$RESCYCLE.BIN") || !RTStrICmp(pszName, "System.kext") /* Usually only plugins here, so skip it. */ ) return RTDBGSYMCACHEFILETYPE_IGNORE; /* Directories can also be bundles on the mac. */ if (!RTStrICmp(pszExt, "dSYM")) return RTDBGSYMCACHEFILETYPE_DEBUG_BUNDLE; for (unsigned i = 0; i < RT_ELEMENTS(g_apszBundleSuffixes) - 1; i++) if (!RTStrICmp(pszExt, &g_apszBundleSuffixes[i][1])) return RTDBGSYMCACHEFILETYPE_IMAGE_BUNDLE; return RTDBGSYMCACHEFILETYPE_DIR; } if (!RTFS_IS_FILE(pObjInfo->Attr.fMode)) return RTDBGSYMCACHEFILETYPE_INVALID; /* Select image vs debug info based on extension. */ if ( !RTStrICmp(pszExt, "pdb") || !RTStrICmp(pszExt, "dbg") || !RTStrICmp(pszExt, "sym") || !RTStrICmp(pszExt, "dwo") || !RTStrICmp(pszExt, "dwp") || !RTStrICmp(pszExt, "debug") || !RTStrICmp(pszExt, "dsym") || !RTStrICmp(pszExt, "dwarf") || !RTStrICmp(pszExt, "map") || !RTStrICmp(pszExt, "cv")) return RTDBGSYMCACHEFILETYPE_DEBUG_FILE; /* Filter out a bunch of files which obviously shouldn't be images. */ if ( !RTStrICmp(pszExt, "txt") || !RTStrICmp(pszExt, "html") || !RTStrICmp(pszExt, "htm") || !RTStrICmp(pszExt, "rtf") || !RTStrICmp(pszExt, "zip") || !RTStrICmp(pszExt, "doc") || !RTStrICmp(pszExt, "gz") || !RTStrICmp(pszExt, "bz2") || !RTStrICmp(pszExt, "xz") || !RTStrICmp(pszExt, "kmk") || !RTStrICmp(pszExt, "c") || !RTStrICmp(pszExt, "cpp") || !RTStrICmp(pszExt, "h") || !RTStrICmp(pszExt, "m") || !RTStrICmp(pszExt, "mm") || !RTStrICmp(pszExt, "asm") || !RTStrICmp(pszExt, "S") || !RTStrICmp(pszExt, "inc") || !RTStrICmp(pszExt, "sh") ) return RTDBGSYMCACHEFILETYPE_IGNORE; if ( !RTStrICmp(pszName, "Makefile") || !RTStrICmp(pszName, "GNUmakefile") || !RTStrICmp(pszName, "createsymbolfiles") || !RTStrICmp(pszName, "kgmacros") ) return RTDBGSYMCACHEFILETYPE_IGNORE; return RTDBGSYMCACHEFILETYPE_IMAGE_FILE; }
/** * Searches for a long option. * * @returns Pointer to a matching option. * @param pszOption The alleged long option. * @param paOptions Option array. * @param cOptions Number of items in the array. * @param fFlags Init flags. */ static PCRTGETOPTDEF rtGetOptSearchLong(const char *pszOption, PCRTGETOPTDEF paOptions, size_t cOptions, uint32_t fFlags) { PCRTGETOPTDEF pOpt = paOptions; while (cOptions-- > 0) { if (pOpt->pszLong) { if ((pOpt->fFlags & RTGETOPT_REQ_MASK) != RTGETOPT_REQ_NOTHING) { /* * A value is required with the argument. We're trying to be * understanding here and will permit any of the following: * --long12:value, --long12=value, --long12 value, * --long:value, --long=value, --long value, * * If the option is index, then all trailing chars must be * digits. For error reporting reasons we also match where * there is no index. */ size_t cchLong = strlen(pOpt->pszLong); if ( !strncmp(pszOption, pOpt->pszLong, cchLong) || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong))) { if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) while (RT_C_IS_DIGIT(pszOption[cchLong])) cchLong++; if ( pszOption[cchLong] == '\0' || pszOption[cchLong] == ':' || pszOption[cchLong] == '=') return pOpt; } } else if (pOpt->fFlags & RTGETOPT_FLAG_INDEX) { /* * The option takes an index but no value. * As above, we also match where there is no index. */ size_t cchLong = strlen(pOpt->pszLong); if ( !strncmp(pszOption, pOpt->pszLong, cchLong) || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE && !RTStrNICmp(pszOption, pOpt->pszLong, cchLong))) { while (RT_C_IS_DIGIT(pszOption[cchLong])) cchLong++; if (pszOption[cchLong] == '\0') return pOpt; } } else if ( !strcmp(pszOption, pOpt->pszLong) || ( pOpt->fFlags & RTGETOPT_FLAG_ICASE && !RTStrICmp(pszOption, pOpt->pszLong))) return pOpt; } pOpt++; } if (!(fFlags & RTGETOPTINIT_FLAGS_NO_STD_OPTS)) for (uint32_t i = 0; i < RT_ELEMENTS(g_aStdOptions); i++) if ( !strcmp(pszOption, g_aStdOptions[i].pszLong) || ( g_aStdOptions[i].fFlags & RTGETOPT_FLAG_ICASE && !RTStrICmp(pszOption, g_aStdOptions[i].pszLong))) return &g_aStdOptions[i]; return NULL; }
int main(int argc, char **argv) { RTEXITCODE rcExit; /* * Init globals and such. */ int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); g_pszProgName = RTPathFilename(argv[0]); #ifdef DEBUG rc = RTCritSectInit(&g_csLog); AssertRC(rc); #endif #ifdef VBOXSERVICE_TOOLBOX /* * Run toolbox code before all other stuff since these things are simpler * shell/file/text utility like programs that just happens to be inside * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and * global mutex restrictions. */ if (VBoxServiceToolboxMain(argc, argv, &rcExit)) return rcExit; #endif bool fUserSession = false; #ifdef VBOX_WITH_GUEST_CONTROL /* * Check if we're the specially spawned VBoxService.exe process that * handles a guest control session. */ if ( argc >= 2 && !RTStrICmp(argv[1], "guestsession")) fUserSession = true; #endif /* * Connect to the kernel part before daemonizing so we can fail and * complain if there is some kind of problem. We need to initialize the * guest lib *before* we do the pre-init just in case one of services needs * do to some initial stuff with it. */ if (fUserSession) rc = VbglR3InitUser(); else rc = VbglR3Init(); if (RT_FAILURE(rc)) { if (rc == VERR_ACCESS_DENIED) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n", g_pszProgName); return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc); } #ifdef RT_OS_WINDOWS /* * Check if we're the specially spawned VBoxService.exe process that * handles page fusion. This saves an extra executable. */ if ( argc == 2 && !RTStrICmp(argv[1], "pagefusion")) return VBoxServicePageSharingWorkerChild(); #endif #ifdef VBOX_WITH_GUEST_CONTROL /* * Check if we're the specially spawned VBoxService.exe process that * handles a guest control session. */ if (fUserSession) return VBoxServiceControlSessionForkInit(argc, argv); #endif /* * Parse the arguments. * * Note! This code predates RTGetOpt, thus the manual parsing. */ bool fDaemonize = true; bool fDaemonized = false; for (int i = 1; i < argc; i++) { const char *psz = argv[i]; if (*psz != '-') return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz); psz++; /* translate long argument to short */ if (*psz == '-') { psz++; size_t cch = strlen(psz); #define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \ && !memcmp(psz, strconst, sizeof(strconst) - 1) ) if (MATCHES("foreground")) psz = "f"; else if (MATCHES("verbose")) psz = "v"; else if (MATCHES("version")) psz = "V"; else if (MATCHES("help")) psz = "h"; else if (MATCHES("interval")) psz = "i"; #ifdef RT_OS_WINDOWS else if (MATCHES("register")) psz = "r"; else if (MATCHES("unregister")) psz = "u"; #endif else if (MATCHES("logfile")) psz = "l"; else if (MATCHES("daemonized")) { fDaemonized = true; continue; } else { bool fFound = false; if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-"))) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = true; if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-"))) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = false; if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-"))) for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName); if (g_aServices[j].fEnabled) fFound = true; } if (!fFound) { rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]); continue; } #undef MATCHES } /* handle the string of short options. */ do { switch (*psz) { case 'i': rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i, &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1); if (rc) return rc; psz = NULL; break; case 'f': fDaemonize = false; break; case 'v': g_cVerbosity++; break; case 'V': RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); return RTEXITCODE_SUCCESS; case 'h': case '?': return vboxServiceUsage(); #ifdef RT_OS_WINDOWS case 'r': return VBoxServiceWinInstall(); case 'u': return VBoxServiceWinUninstall(); #endif case 'l': { rc = VBoxServiceArgString(argc, argv, psz + 1, &i, g_szLogFile, sizeof(g_szLogFile)); if (rc) return rc; psz = NULL; break; } default: { rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; bool fFound = false; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]); break; } } } while (psz && *++psz); } /* Check that at least one service is enabled. */ if (vboxServiceCountEnabledServices() == 0) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n"); rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log \"%s\", rc=%Rrc\n", strlen(g_szLogFile) ? g_szLogFile : "<None>", rc); /* Call pre-init if we didn't do it already. */ rcExit = vboxServiceLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; #ifdef RT_OS_WINDOWS /* * Make sure only one instance of VBoxService runs at a time. Create a * global mutex for that. * * Note! The \\Global\ namespace was introduced with Win2K, thus the * version check. * Note! If the mutex exists CreateMutex will open it and set last error to * ERROR_ALREADY_EXISTS. */ OSVERSIONINFOEX OSInfoEx; RT_ZERO(OSInfoEx); OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); SetLastError(NO_ERROR); HANDLE hMutexAppRunning; if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx) && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT && OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */) hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME); else hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME); if (hMutexAppRunning == NULL) { DWORD dwErr = GetLastError(); if ( dwErr == ERROR_ALREADY_EXISTS || dwErr == ERROR_ACCESS_DENIED) { VBoxServiceError("%s is already running! Terminating.\n", g_pszProgName); return RTEXITCODE_FAILURE; } VBoxServiceError("CreateMutex failed with last error %u! Terminating.\n", GetLastError()); return RTEXITCODE_FAILURE; } #else /* !RT_OS_WINDOWS */ /** @todo Add PID file creation here? */ #endif /* !RT_OS_WINDOWS */ VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n", RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity); /* * Daemonize if requested. */ if (fDaemonize && !fDaemonized) { #ifdef RT_OS_WINDOWS VBoxServiceVerbose(2, "Starting service dispatcher ...\n"); rcExit = VBoxServiceWinEnterCtrlDispatcher(); #else VBoxServiceVerbose(1, "Daemonizing...\n"); rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, false /* fRespawn */, NULL /* pcRespawn */); if (RT_FAILURE(rc)) return VBoxServiceError("Daemon failed: %Rrc\n", rc); /* in-child */ #endif } #ifdef RT_OS_WINDOWS else #endif { /* * Windows: We're running the service as a console application now. Start the * services, enter the main thread's run loop and stop them again * when it returns. * * POSIX: This is used for both daemons and console runs. Start all services * and return immediately. */ #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /* Install console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */)) { VBoxServiceError("Unable to add console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #endif /* RT_OS_WINDOWS */ rc = VBoxServiceStartServices(); rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; if (RT_SUCCESS(rc)) VBoxServiceMainWait(); #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /* Uninstall console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */)) { VBoxServiceError("Unable to remove console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #else /* !RT_OS_WINDOWS */ /* On Windows - since we're running as a console application - we already stopped all services * through the console control handler. So only do the stopping of services here on other platforms * where the break/shutdown/whatever signal was just received. */ VBoxServiceStopServices(); #endif /* RT_OS_WINDOWS */ } VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated); #ifdef RT_OS_WINDOWS /* * Cleanup mutex. */ CloseHandle(hMutexAppRunning); #endif VBoxServiceVerbose(0, "Ended.\n"); #ifdef DEBUG RTCritSectDelete(&g_csLog); //RTMemTrackerDumpAllToStdOut(); #endif VBoxServiceLogDestroy(); return rcExit; }
/** * Value string -> Value union. * * @returns IPRT status code. * @param fFlags The value flags. * @param pszValue The value string. * @param pValueUnion Where to return the processed value. */ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion) { /* * Transform into a option value as requested. * If decimal conversion fails, we'll check for "0x<xdigit>" and * try a 16 based conversion. We will not interpret any of the * generic ints as octals. */ uint32_t const fSwitchValue = fFlags & ( RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_DEC | RTGETOPT_FLAG_OCT); switch (fSwitchValue) { case RTGETOPT_REQ_STRING: pValueUnion->psz = pszValue; break; case RTGETOPT_REQ_BOOL: if ( !RTStrICmp(pszValue, "true") || !RTStrICmp(pszValue, "t") || !RTStrICmp(pszValue, "yes") || !RTStrICmp(pszValue, "y") || !RTStrICmp(pszValue, "enabled") || !RTStrICmp(pszValue, "enable") || !RTStrICmp(pszValue, "en") || !RTStrICmp(pszValue, "e") || !RTStrICmp(pszValue, "on") || !RTStrCmp(pszValue, "1") ) pValueUnion->f = true; else if ( !RTStrICmp(pszValue, "false") || !RTStrICmp(pszValue, "f") || !RTStrICmp(pszValue, "no") || !RTStrICmp(pszValue, "n") || !RTStrICmp(pszValue, "disabled") || !RTStrICmp(pszValue, "disable") || !RTStrICmp(pszValue, "dis") || !RTStrICmp(pszValue, "d") || !RTStrICmp(pszValue, "off") || !RTStrCmp(pszValue, "0") ) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; case RTGETOPT_REQ_BOOL_ONOFF: if (!RTStrICmp(pszValue, "on")) pValueUnion->f = true; else if (!RTStrICmp(pszValue, "off")) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; #define MY_INT_CASE(req, type, memb, convfn) \ case req: \ { \ type Value; \ if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \ && ( pszValue[0] != '0' \ || (pszValue[1] != 'x' && pszValue[1] != 'X') \ || !RT_C_IS_XDIGIT(pszValue[2]) \ || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } #define MY_BASE_INT_CASE(req, type, memb, convfn, base) \ case req: \ { \ type Value; \ if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i8, RTStrToInt8Full) MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i16, RTStrToInt16Full) MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i32, RTStrToInt32Full) MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i64, RTStrToInt64Full) MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u8, RTStrToUInt8Full) MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full) MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full) MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i8, RTStrToInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i16, RTStrToInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i32, RTStrToInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i64, RTStrToInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u8, RTStrToUInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i8, RTStrToInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i16, RTStrToInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i32, RTStrToInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i64, RTStrToInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u8, RTStrToUInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i8, RTStrToInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i16, RTStrToInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i32, RTStrToInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i64, RTStrToInt64Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u8, RTStrToUInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8) #undef MY_INT_CASE #undef MY_BASE_INT_CASE case RTGETOPT_REQ_IPV4ADDR: { RTNETADDRIPV4 Addr; if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->IPv4Addr = Addr; break; } case RTGETOPT_REQ_IPV4CIDR: { RTNETADDRIPV4 network; RTNETADDRIPV4 netmask; if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->CidrIPv4.IPv4Network.u = network.u; pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; break; } case RTGETOPT_REQ_MACADDR: { RTMAC Addr; if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->MacAddr = Addr; break; } case RTGETOPT_REQ_UUID: { RTUUID Uuid; if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->Uuid = Uuid; break; } #define MY_INT_PAIR_CASE(a_fReqValue, a_fReqValueOptional, a_Type, a_MemberPrefix, a_fnConv, a_ConvBase, a_DefaultValue) \ case a_fReqValue: \ case a_fReqValueOptional: \ { \ /* First value: */ \ a_Type Value1; \ char *pszNext = NULL; \ unsigned uBase = pszValue[0] == '0' \ && (pszValue[1] == 'x' || pszValue[1] == 'X') \ && RT_C_IS_XDIGIT(pszValue[2]) \ ? 16 : a_ConvBase; \ int rc = a_fnConv(pszValue, &pszNext, uBase, &Value1); \ if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES) \ { \ /* The second value, could be optional: */ \ a_Type Value2 = a_DefaultValue; \ pszValue = pszNext;\ if (pszValue) \ { \ while (RT_C_IS_BLANK(*pszValue)) \ pszValue++; \ if (*pszValue == ':' || *pszValue == '/' || *pszValue == '|') \ do pszValue++; \ while (RT_C_IS_BLANK(*pszValue)); \ if (pszValue != pszNext) \ { \ uBase = pszValue[0] == '0' \ && (pszValue[1] == 'x' || pszValue[1] == 'X') \ && RT_C_IS_XDIGIT(pszValue[2]) \ ? 16 : a_ConvBase; \ rc = a_fnConv(pszValue, &pszNext, uBase, &Value2); \ if (rc == VINF_SUCCESS) \ { /* likely */ } \ else \ { RTAssertMsg2("z rc=%Rrc: '%s' '%s' uBase=%d\n", rc, pszValue, pszNext, uBase); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ } \ else if (fSwitchValue != (a_fReqValueOptional)) \ { RTAssertMsg2("x\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ } \ else if (fSwitchValue != (a_fReqValueOptional)) \ { RTAssertMsg2("y\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \ pValueUnion->a_MemberPrefix##Second = Value2; \ pValueUnion->a_MemberPrefix##First = Value1; \ break; \ } \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ } MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR, uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_DEC, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC, uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX, uint32_t, PairU32.u, RTStrToUInt32Ex, 16, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_OCT, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT, uint32_t, PairU32.u, RTStrToUInt32Ex, 8, UINT32_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR, uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_DEC, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC, uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_HEX, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX, uint64_t, PairU64.u, RTStrToUInt64Ex, 16, UINT64_MAX) MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_OCT, RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT, uint64_t, PairU64.u, RTStrToUInt64Ex, 8, UINT64_MAX) default: AssertMsgFailed(("f=%#x\n", fFlags)); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); RTDIGESTTYPE enmDigestType = RTDIGESTTYPE_INVALID; const char *pszDigestType = "NotSpecified"; enum { kMethod_Full, kMethod_Block, kMethod_File, kMethod_CVAS } enmMethod = kMethod_Block; uint64_t offStart = 0; uint64_t cbMax = UINT64_MAX; bool fTestcase = false; static const RTGETOPTDEF s_aOptions[] = { { "--type", 't', RTGETOPT_REQ_STRING }, { "--method", 'm', RTGETOPT_REQ_STRING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, { "--length", 'l', RTGETOPT_REQ_UINT64 }, { "--offset", 'o', RTGETOPT_REQ_UINT64 }, { "--testcase", 'x', RTGETOPT_REQ_NOTHING }, }; int ch; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); while ((ch = RTGetOpt(&GetState, &ValueUnion))) { switch (ch) { case 't': if (!RTStrICmp(ValueUnion.psz, "crc32")) { pszDigestType = "CRC32"; enmDigestType = RTDIGESTTYPE_CRC32; } else if (!RTStrICmp(ValueUnion.psz, "crc64")) { pszDigestType = "CRC64"; enmDigestType = RTDIGESTTYPE_CRC64; } else if (!RTStrICmp(ValueUnion.psz, "md2")) { pszDigestType = "MD2"; enmDigestType = RTDIGESTTYPE_MD2; } else if (!RTStrICmp(ValueUnion.psz, "md5")) { pszDigestType = "MD5"; enmDigestType = RTDIGESTTYPE_MD5; } else if (!RTStrICmp(ValueUnion.psz, "sha1")) { pszDigestType = "SHA-1"; enmDigestType = RTDIGESTTYPE_SHA1; } else if (!RTStrICmp(ValueUnion.psz, "sha224")) { pszDigestType = "SHA-224"; enmDigestType = RTDIGESTTYPE_SHA224; } else if (!RTStrICmp(ValueUnion.psz, "sha256")) { pszDigestType = "SHA-256"; enmDigestType = RTDIGESTTYPE_SHA256; } else if (!RTStrICmp(ValueUnion.psz, "sha384")) { pszDigestType = "SHA-384"; enmDigestType = RTDIGESTTYPE_SHA384; } else if (!RTStrICmp(ValueUnion.psz, "sha512")) { pszDigestType = "SHA-512"; enmDigestType = RTDIGESTTYPE_SHA512; } else if (!RTStrICmp(ValueUnion.psz, "sha512/224")) { pszDigestType = "SHA-512/224"; enmDigestType = RTDIGESTTYPE_SHA512T224; } else if (!RTStrICmp(ValueUnion.psz, "sha512/256")) { pszDigestType = "SHA-512/256"; enmDigestType = RTDIGESTTYPE_SHA512T256; } else { Error("Invalid digest type: %s\n", ValueUnion.psz); return 1; } break; case 'm': if (!RTStrICmp(ValueUnion.psz, "full")) enmMethod = kMethod_Full; else if (!RTStrICmp(ValueUnion.psz, "block")) enmMethod = kMethod_Block; else if (!RTStrICmp(ValueUnion.psz, "file")) enmMethod = kMethod_File; else if (!RTStrICmp(ValueUnion.psz, "cvas")) enmMethod = kMethod_CVAS; else { Error("Invalid digest method: %s\n", ValueUnion.psz); return 1; } break; case 'l': cbMax = ValueUnion.u64; break; case 'o': offStart = ValueUnion.u64; break; case 'x': fTestcase = true; break; case 'h': RTPrintf("usage: tstRTDigest -t <digest-type> [-o <offset>] [-l <length>] [-x] file [file2 [..]]\n"); return 1; case VINF_GETOPT_NOT_OPTION: { if (enmDigestType == RTDIGESTTYPE_INVALID) return Error("No digest type was specified\n"); switch (enmMethod) { case kMethod_Full: return Error("Full file method is not implemented\n"); case kMethod_File: if (offStart != 0 || cbMax != UINT64_MAX) return Error("The -l and -o options do not work with the 'file' method."); switch (enmDigestType) { case RTDIGESTTYPE_SHA1: { char *pszDigest; int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc); RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); RTStrFree(pszDigest); break; } case RTDIGESTTYPE_SHA256: { char *pszDigest; int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc); RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); RTStrFree(pszDigest); break; } default: return Error("The file method isn't implemented for this digest\n"); } break; case kMethod_Block: { RTFILE hFile; int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc); if (offStart != 0) { rc = RTFileSeek(hFile, offStart, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return Error("RTFileSeek(%s,%ull) -> %Rrc\n", ValueUnion.psz, offStart, rc); } uint64_t cbMaxLeft = cbMax; size_t cbRead; uint8_t abBuf[_64K]; char *pszDigest = (char *)&abBuf[0]; switch (enmDigestType) { case RTDIGESTTYPE_CRC32: { uint32_t uCRC32 = RTCrc32Start(); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead); } uCRC32 = RTCrc32Finish(uCRC32); RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32); break; } case RTDIGESTTYPE_CRC64: { uint64_t uCRC64 = RTCrc64Start(); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead); } uCRC64 = RTCrc64Finish(uCRC64); RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64); break; } case RTDIGESTTYPE_MD2: { RTMD2CONTEXT Ctx; RTMd2Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTMd2Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTMD2_HASH_SIZE]; RTMd2Final(&Ctx, abDigest); RTMd2ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_MD5: { RTMD5CONTEXT Ctx; RTMd5Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTMd5Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTMD5HASHSIZE]; RTMd5Final(abDigest, &Ctx); RTMd5ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA1: { RTSHA1CONTEXT Ctx; RTSha1Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha1Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA1_HASH_SIZE]; RTSha1Final(&Ctx, abDigest); RTSha1ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA256: { RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha256Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abDigest); RTSha256ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA512: { RTSHA512CONTEXT Ctx; RTSha512Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha512Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA512_HASH_SIZE]; RTSha512Final(&Ctx, abDigest); RTSha512ToString(abDigest, pszDigest, sizeof(abBuf)); break; } default: return Error("Internal error #1\n"); } RTFileClose(hFile); if (RT_FAILURE(rc) && rc != VERR_EOF) { RTPrintf("Partial: %s %s\n", pszDigest, ValueUnion.psz); return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc); } if (!fTestcase) RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); else if (offStart) RTPrintf(" { &g_abRandom72KB[%#4llx], %5llu, \"%s\", \"%s %llu bytes @%llu\" },\n", offStart, cbMax - cbMaxLeft, pszDigest, pszDigestType, offStart, cbMax - cbMaxLeft); else RTPrintf(" { &g_abRandom72KB[0], %5llu, \"%s\", \"%s %llu bytes\" },\n", cbMax - cbMaxLeft, pszDigest, pszDigestType, cbMax - cbMaxLeft); break; } /* * Process a SHS response file: * http://csrc.nist.gov/groups/STM/cavp/index.html#03 */ case kMethod_CVAS: { RTCRDIGEST hDigest; int rc = RTCrDigestCreateByType(&hDigest, enmDigestType); if (RT_FAILURE(rc)) return Error("Failed to create digest calculator for %s: %Rrc", pszDigestType, rc); uint32_t const cbDigest = RTCrDigestGetHashSize(hDigest); if (!cbDigest || cbDigest >= _1K) return Error("Unexpected hash size: %#x\n", cbDigest); PRTSTREAM pFile; rc = RTStrmOpen(ValueUnion.psz, "r", &pFile); if (RT_FAILURE(rc)) return Error("Failed to open CVAS file '%s': %Rrc", ValueUnion.psz, rc); /* * Parse the input file. * ASSUME order: Len, Msg, MD. */ static char s_szLine[_256K]; char *psz; uint32_t cPassed = 0; uint32_t cErrors = 0; uint32_t iLine = 1; for (;;) { psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) break; /* Skip [L = 20] stuff. */ if (*psz == '[') continue; /* Message length. */ uint64_t cMessageBits; if (RTStrNICmp(psz, RT_STR_TUPLE("Len ="))) return Error("%s(%d): Expected 'Len =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 5); rc = RTStrToUInt64Full(psz, 0, &cMessageBits); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing length '%s': %Rrc\n", ValueUnion.psz, iLine, psz, rc); /* The message text. */ psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) return Error("%s(%d): Expected message text not EOF.", ValueUnion.psz, iLine); if (RTStrNICmp(psz, RT_STR_TUPLE("Msg ="))) return Error("%s(%d): Expected 'Msg =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 5); size_t const cbMessage = (cMessageBits + 7) / 8; static uint8_t s_abMessage[sizeof(s_szLine) / 2]; if (cbMessage > 0) { rc = RTStrConvertHexBytes(psz, s_abMessage, cbMessage, 0 /*fFlags*/); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing message '%.10s...': %Rrc\n", ValueUnion.psz, iLine, psz, rc); } /* The message digest. */ psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) return Error("%s(%d): Expected message digest not EOF.", ValueUnion.psz, iLine); if (RTStrNICmp(psz, RT_STR_TUPLE("MD ="))) return Error("%s(%d): Expected 'MD =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 4); static uint8_t s_abExpectedDigest[_1K]; rc = RTStrConvertHexBytes(psz, s_abExpectedDigest, cbDigest, 0 /*fFlags*/); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing message digest '%.10s...': %Rrc\n", ValueUnion.psz, iLine, psz, rc); /* * Do the testing. */ rc = RTCrDigestReset(hDigest); if (rc != VINF_SUCCESS) return Error("RTCrDigestReset failed: %Rrc", rc); rc = RTCrDigestUpdate(hDigest, s_abMessage, cbMessage); if (rc != VINF_SUCCESS) return Error("RTCrDigestUpdate failed: %Rrc", rc); static uint8_t s_abActualDigest[_1K]; rc = RTCrDigestFinal(hDigest, s_abActualDigest, cbDigest); if (rc != VINF_SUCCESS) return Error("RTCrDigestFinal failed: %Rrc", rc); if (memcmp(s_abActualDigest, s_abExpectedDigest, cbDigest) == 0) cPassed++; else { Error("%s(%d): Message digest mismatch. Expected %.*RThxs, got %.*RThxs.", ValueUnion.psz, iLine, cbDigest, s_abExpectedDigest, cbDigest, s_abActualDigest); cErrors++; } } RTStrmClose(pFile); if (cErrors > 0) return Error("Failed: %u error%s (%u passed)", cErrors, cErrors == 1 ? "" : "s", cPassed); RTPrintf("Passed %u test%s.\n", cPassed, cPassed == 1 ? "" : "s"); if (RT_FAILURE(rc)) return Error("Failed: %Rrc", rc); break; } default: return Error("Internal error #2\n"); } break; } default: return RTGetOptPrintError(ch, &ValueUnion); } } return 0; }
DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader) { int rc = VINF_SUCCESS; char *pszTftpRRQRaw; size_t idxTftpRRQRaw = 0; int cbTftpRRQRaw = 0; int fWithArg = 0; int idxOptionArg = 0; AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER); AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER); AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER); LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader)); pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core; cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core); while(cbTftpRRQRaw) { idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1; if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0) { rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw); if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } } else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE) { int idxFmt = 0; rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw); if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR); return VERR_INTERNAL_ERROR; } AssertReturn( g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR); pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType; } else if (fWithArg) { if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName)) { rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize); if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX) rc = VERR_INVALID_PARAMETER; } if ( RT_SUCCESS(rc) && !RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName)) rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTSize); /* @todo: we don't use timeout, but its value in the range 0-255 */ if ( RT_SUCCESS(rc) && !RTStrICmp("timeout", g_TftpDesc[idxOptionArg].pszName)) rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTimeout); /* @todo: unknown option detection */ if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } fWithArg = 0; idxOptionArg = 0; } else { rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw); if (RT_SUCCESS(rc)) fWithArg = 1; else { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } } pszTftpRRQRaw += idxTftpRRQRaw; cbTftpRRQRaw -= idxTftpRRQRaw; } LogFlowFuncLeaveRC(rc); return rc; }
HRESULT HostDnsServiceWin::updateInfo() { HostDnsInformation info; LONG lrc; int rc; std::string strDomain; std::string strSearchList; /* NB: comma separated, no spaces */ /* * We ignore "DhcpDomain" key here since it's not stable. If * there are two active interfaces that use DHCP (in particular * when host uses OpenVPN) then DHCP ACKs will take turns updating * that key. Instead we call GetAdaptersAddresses() below (which * is what ipconfig.exe seems to do). */ for (DWORD regIndex = 0; /**/; ++regIndex) { char keyName[256]; DWORD cbKeyName = sizeof(keyName); DWORD keyType = 0; char keyData[1024]; DWORD cbKeyData = sizeof(keyData); lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex, keyName, &cbKeyName, 0, &keyType, (LPBYTE)keyData, &cbKeyData); if (lrc == ERROR_NO_MORE_ITEMS) break; if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */ continue; if (lrc != ERROR_SUCCESS) { LogRel2(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc)); return E_FAIL; } if (keyType != REG_SZ) continue; if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0') --cbKeyData; /* don't count trailing NUL if present */ if (RTStrICmp("Domain", keyName) == 0) { strDomain.assign(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: Domain=\"%s\"\n", strDomain.c_str())); } else if (RTStrICmp("DhcpDomain", keyName) == 0) { std::string strDhcpDomain(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: DhcpDomain=\"%s\"\n", strDhcpDomain.c_str())); } else if (RTStrICmp("SearchList", keyName) == 0) { strSearchList.assign(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: SearchList=\"%s\"\n", strSearchList.c_str())); } } /* statically configured domain name */ if (!strDomain.empty()) { info.domain = strDomain; info.searchList.push_back(strDomain); } /* statically configured search list */ if (!strSearchList.empty()) { vappend(info.searchList, strSearchList, ','); } /* * When name servers are configured statically it seems that the * value of Tcpip\Parameters\NameServer is NOT set, inly interface * specific NameServer value is (which triggers notification for * us to pick up the change). Fortunately, DnsApi seems to do the * right thing there. */ DNS_STATUS status; PIP4_ARRAY pIp4Array = NULL; // NB: must be set on input it seems, despite docs' claim to the contrary. DWORD cbBuffer = sizeof(&pIp4Array); status = DnsQueryConfig(DnsConfigDnsServerList, DNS_CONFIG_FLAG_ALLOC, NULL, NULL, &pIp4Array, &cbBuffer); if (status == NO_ERROR && pIp4Array != NULL) { for (DWORD i = 0; i < pIp4Array->AddrCount; ++i) { char szAddrStr[16] = ""; RTStrPrintf(szAddrStr, sizeof(szAddrStr), "%RTnaipv4", pIp4Array->AddrArray[i]); LogRel2(("HostDnsServiceWin: server %d: %s\n", i+1, szAddrStr)); info.servers.push_back(szAddrStr); } LocalFree(pIp4Array); } /** * DnsQueryConfig(DnsConfigSearchList, ...) is not implemented. * Call GetAdaptersAddresses() that orders the returned list * appropriately and collect IP_ADAPTER_ADDRESSES::DnsSuffix. */ do { PIP_ADAPTER_ADDRESSES pAddrBuf = NULL; ULONG cbAddrBuf = 8 * 1024; bool fReallocated = false; ULONG err; pAddrBuf = (PIP_ADAPTER_ADDRESSES) malloc(cbAddrBuf); if (pAddrBuf == NULL) { LogRel2(("HostDnsServiceWin: failed to allocate %zu bytes" " of GetAdaptersAddresses buffer\n", (size_t)cbAddrBuf)); break; } while (pAddrBuf != NULL) { ULONG cbAddrBufProvided = cbAddrBuf; err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, pAddrBuf, &cbAddrBuf); if (err == NO_ERROR) { break; } else if (err == ERROR_BUFFER_OVERFLOW) { LogRel2(("HostDnsServiceWin: provided GetAdaptersAddresses with %zu" " but asked again for %zu bytes\n", (size_t)cbAddrBufProvided, (size_t)cbAddrBuf)); if (RT_UNLIKELY(fReallocated)) /* what? again?! */ { LogRel2(("HostDnsServiceWin: ... not going to realloc again\n")); free(pAddrBuf); pAddrBuf = NULL; break; } PIP_ADAPTER_ADDRESSES pNewBuf = (PIP_ADAPTER_ADDRESSES) realloc(pAddrBuf, cbAddrBuf); if (pNewBuf == NULL) { LogRel2(("HostDnsServiceWin: failed to reallocate %zu bytes\n", (size_t)cbAddrBuf)); free(pAddrBuf); pAddrBuf = NULL; break; } /* try again */ pAddrBuf = pNewBuf; /* cbAddrBuf already updated */ fReallocated = true; } else { LogRel2(("HostDnsServiceWin: GetAdaptersAddresses error %d\n", err)); free(pAddrBuf); pAddrBuf = NULL; break; } } if (pAddrBuf == NULL) break; for (PIP_ADAPTER_ADDRESSES pAdp = pAddrBuf; pAdp != NULL; pAdp = pAdp->Next) { LogRel2(("HostDnsServiceWin: %ls (status %u) ...\n", pAdp->FriendlyName ? pAdp->FriendlyName : L"(null)", pAdp->OperStatus)); if (pAdp->OperStatus != IfOperStatusUp) continue; if (pAdp->DnsSuffix == NULL || *pAdp->DnsSuffix == L'\0') continue; char *pszDnsSuffix = NULL; rc = RTUtf16ToUtf8Ex(pAdp->DnsSuffix, RTSTR_MAX, &pszDnsSuffix, 0, /* allocate */ NULL); if (RT_FAILURE(rc)) { LogRel2(("HostDnsServiceWin: failed to convert DNS suffix \"%ls\": %Rrc\n", pAdp->DnsSuffix, rc)); continue; } AssertContinue(pszDnsSuffix != NULL); AssertContinue(*pszDnsSuffix != '\0'); LogRel2(("HostDnsServiceWin: ... suffix = \"%s\"\n", pszDnsSuffix)); vappend(info.searchList, pszDnsSuffix); RTStrFree(pszDnsSuffix); } free(pAddrBuf); } while (0); if (info.domain.empty() && !info.searchList.empty()) info.domain = info.searchList[0]; if (info.searchList.size() == 1) info.searchList.clear(); HostDnsMonitor::setInfo(info); return S_OK; }
int main(int argc, char **argv) { int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); /* * Parse arguments. */ static RTGETOPTDEF const s_aOptions[] = { { "--manifest", 'm', RTGETOPT_REQ_STRING }, { "--java", 'j', RTGETOPT_REQ_NOTHING }, { "--chdir", 'C', RTGETOPT_REQ_STRING }, { "--attribute", 'a', RTGETOPT_REQ_STRING }, { "--verify", 'v', RTGETOPT_REQ_NOTHING }, }; bool fVerify = false; bool fStdFormat = true; const char *pszManifest = NULL; const char *pszChDir = NULL; uint32_t fAttr = RTMANIFEST_ATTR_UNKNOWN; RTGETOPTSTATE GetState; rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc", rc); RTGETOPTUNION ValueUnion; while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0 && rc != VINF_GETOPT_NOT_OPTION) { switch (rc) { case 'a': { static struct { const char *pszAttr; uint32_t fAttr; } s_aAttributes[] = { { "size", RTMANIFEST_ATTR_SIZE }, { "md5", RTMANIFEST_ATTR_MD5 }, { "sha1", RTMANIFEST_ATTR_SHA1 }, { "sha256", RTMANIFEST_ATTR_SHA256 }, { "sha512", RTMANIFEST_ATTR_SHA512 } }; uint32_t fThisAttr = RTMANIFEST_ATTR_UNKNOWN; for (unsigned i = 0; i < RT_ELEMENTS(s_aAttributes); i++) if (!RTStrICmp(s_aAttributes[i].pszAttr, ValueUnion.psz)) { fThisAttr = s_aAttributes[i].fAttr; break; } if (fThisAttr == RTMANIFEST_ATTR_UNKNOWN) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown attribute type '%s'", ValueUnion.psz); if (fAttr == RTMANIFEST_ATTR_UNKNOWN) fAttr = fThisAttr; else fAttr |= fThisAttr; break; } case 'j': fStdFormat = false; break; case 'm': if (pszManifest) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one manifest can be specified"); pszManifest = ValueUnion.psz; break; case 'v': fVerify = true; break; case 'C': if (pszChDir) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one directory change can be specified"); pszChDir = ValueUnion.psz; break; case 'h': RTPrintf("Usage: %s [--manifest <file>] [--chdir <dir>] [--attribute <attrib-name> [..]] <files>\n" " or %s --verify [--manifest <file>] [--chdir <dir>]\n" "\n" "attrib-name: size, md5, sha1, sha256 or sha512\n" , RTProcShortName(), RTProcShortName()); return RTEXITCODE_SUCCESS; case 'V': RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision()); return RTEXITCODE_SUCCESS; default: return RTGetOptPrintError(rc, &ValueUnion); } } /* * Take action. */ RTEXITCODE rcExit; if (!fVerify) { if (rc != VINF_GETOPT_NOT_OPTION) RTMsgWarning("No files specified, the manifest will be empty."); if (fAttr == RTMANIFEST_ATTR_UNKNOWN) fAttr = RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_MD5 | RTMANIFEST_ATTR_SHA1 | RTMANIFEST_ATTR_SHA256 | RTMANIFEST_ATTR_SHA512; rcExit = rtManifestDoCreate(pszManifest, fStdFormat, pszChDir, fAttr, &GetState, &ValueUnion, rc); } else { if (rc == VINF_GETOPT_NOT_OPTION) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No files should be specified when verifying a manifest (--verfiy), " "only a manifest via the --manifest option"); if (fAttr != RTMANIFEST_ATTR_UNKNOWN) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --attribute (-a) option does not combine with --verify (-v)"); rcExit = rtManifestDoVerify(pszManifest, fStdFormat, pszChDir); } return rcExit; }
RTR3DECL(int) RTManifestVerifyFilesBuf(void *pvBuf, size_t cbSize, PRTMANIFESTTEST paTests, size_t cTests, size_t *piFailed) { /* Validate input */ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); AssertReturn(cbSize > 0, VERR_INVALID_PARAMETER); AssertPtrReturn(paTests, VERR_INVALID_POINTER); AssertReturn(cTests > 0, VERR_INVALID_PARAMETER); AssertPtrNullReturn(piFailed, VERR_INVALID_POINTER); int rc = VINF_SUCCESS; PRTMANIFESTFILEENTRY paFiles = (PRTMANIFESTFILEENTRY)RTMemTmpAllocZ(sizeof(RTMANIFESTFILEENTRY) * cTests); if (!paFiles) return VERR_NO_MEMORY; /* Fill our compare list */ for (size_t i = 0; i < cTests; ++i) paFiles[i].pTestPattern = &paTests[i]; char *pcBuf = (char*)pvBuf; size_t cbRead = 0; /* Parse the manifest file line by line */ for (;;) { if (cbRead >= cbSize) break; size_t cch = rtManifestIndexOfCharInBuf(pcBuf, cbSize - cbRead, '\n') + 1; /* Skip empty lines (UNIX/DOS format) */ if ( ( cch == 1 && pcBuf[0] == '\n') || ( cch == 2 && pcBuf[0] == '\r' && pcBuf[1] == '\n')) { pcBuf += cch; cbRead += cch; continue; } /** @todo r=bird: * -# Better deal with this EOF line platform dependency * -# The SHA1 and SHA256 tests should probably include a blank space check. * -# If there is a specific order to the elements in the string, it would be * good if the delimiter searching checked for it. * -# Deal with filenames containing delimiter characters. */ /* Check for the digest algorithm */ if ( cch < 4 || ( !( pcBuf[0] == 'S' && pcBuf[1] == 'H' && pcBuf[2] == 'A' && pcBuf[3] == '1') && !( pcBuf[0] == 'S' && pcBuf[1] == 'H' && pcBuf[2] == 'A' && pcBuf[3] == '2' && pcBuf[4] == '5' && pcBuf[5] == '6') ) ) { /* Digest unsupported */ rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE; break; } /* Try to find the filename */ char *pszNameStart = rtManifestPosOfCharInBuf(pcBuf, cch, '('); if (!pszNameStart) { rc = VERR_MANIFEST_WRONG_FILE_FORMAT; break; } char *pszNameEnd = rtManifestPosOfCharInBuf(pcBuf, cch, ')'); if (!pszNameEnd) { rc = VERR_MANIFEST_WRONG_FILE_FORMAT; break; } /* Copy the filename part */ size_t cchName = pszNameEnd - pszNameStart - 1; char *pszName = (char *)RTMemTmpAlloc(cchName + 1); if (!pszName) { rc = VERR_NO_MEMORY; break; } memcpy(pszName, pszNameStart + 1, cchName); pszName[cchName] = '\0'; /* Try to find the digest sum */ char *pszDigestStart = rtManifestPosOfCharInBuf(pcBuf, cch, '=') + 1; if (!pszDigestStart) { RTMemTmpFree(pszName); rc = VERR_MANIFEST_WRONG_FILE_FORMAT; break; } char *pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\r'); if (!pszDigestEnd) pszDigestEnd = rtManifestPosOfCharInBuf(pcBuf, cch, '\n'); if (!pszDigestEnd) { RTMemTmpFree(pszName); rc = VERR_MANIFEST_WRONG_FILE_FORMAT; break; } /* Copy the digest part */ size_t cchDigest = pszDigestEnd - pszDigestStart - 1; char *pszDigest = (char *)RTMemTmpAlloc(cchDigest + 1); if (!pszDigest) { RTMemTmpFree(pszName); rc = VERR_NO_MEMORY; break; } memcpy(pszDigest, pszDigestStart + 1, cchDigest); pszDigest[cchDigest] = '\0'; /* Check our file list against the extracted data */ bool fFound = false; for (size_t i = 0; i < cTests; ++i) { /** @todo r=bird: Using RTStrStr here looks bogus. */ if (RTStrStr(paFiles[i].pTestPattern->pszTestFile, RTStrStrip(pszName)) != NULL) { /* Add the data of the manifest file to the file list */ paFiles[i].pszManifestFile = RTStrDup(RTStrStrip(pszName)); paFiles[i].pszManifestDigest = RTStrDup(RTStrStrip(pszDigest)); fFound = true; break; } } RTMemTmpFree(pszName); RTMemTmpFree(pszDigest); if (!fFound) { /* There have to be an entry in the file list */ rc = VERR_MANIFEST_FILE_MISMATCH; break; } pcBuf += cch; cbRead += cch; } if ( rc == VINF_SUCCESS || rc == VERR_EOF) { rc = VINF_SUCCESS; for (size_t i = 0; i < cTests; ++i) { /* If there is an entry in the file list, which hasn't an * equivalent in the manifest file, its an error. */ if ( !paFiles[i].pszManifestFile || !paFiles[i].pszManifestDigest) { rc = VERR_MANIFEST_FILE_MISMATCH; break; } /* Do the manifest SHA digest match against the actual digest? */ if (RTStrICmp(paFiles[i].pszManifestDigest, paFiles[i].pTestPattern->pszTestDigest)) { if (piFailed) *piFailed = i; rc = VERR_MANIFEST_DIGEST_MISMATCH; break; } } } /* Cleanup */ for (size_t i = 0; i < cTests; ++i) { if (paFiles[i].pszManifestFile) RTStrFree(paFiles[i].pszManifestFile); if (paFiles[i].pszManifestDigest) RTStrFree(paFiles[i].pszManifestDigest); } RTMemTmpFree(paFiles); RTPrintf("rc = %Rrc\n", rc); return rc; }
int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); enum { kDigestType_NotSpecified, kDigestType_CRC32, kDigestType_CRC64, kDigestType_MD5, kDigestType_SHA1, kDigestType_SHA256, kDigestType_SHA512 } enmDigestType = kDigestType_NotSpecified; enum { kMethod_Full, kMethod_Block, kMethod_File } enmMethod = kMethod_Block; static const RTGETOPTDEF s_aOptions[] = { { "--type", 't', RTGETOPT_REQ_STRING }, { "--method", 'm', RTGETOPT_REQ_STRING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, }; int ch; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); while ((ch = RTGetOpt(&GetState, &ValueUnion))) { switch (ch) { case 't': if (!RTStrICmp(ValueUnion.psz, "crc32")) enmDigestType = kDigestType_CRC32; else if (!RTStrICmp(ValueUnion.psz, "crc64")) enmDigestType = kDigestType_CRC64; else if (!RTStrICmp(ValueUnion.psz, "md5")) enmDigestType = kDigestType_MD5; else if (!RTStrICmp(ValueUnion.psz, "sha1")) enmDigestType = kDigestType_SHA1; else if (!RTStrICmp(ValueUnion.psz, "sha256")) enmDigestType = kDigestType_SHA256; else if (!RTStrICmp(ValueUnion.psz, "sha512")) enmDigestType = kDigestType_SHA512; else { Error("Invalid digest type: %s\n", ValueUnion.psz); return 1; } break; case 'm': if (!RTStrICmp(ValueUnion.psz, "full")) enmMethod = kMethod_Full; else if (!RTStrICmp(ValueUnion.psz, "block")) enmMethod = kMethod_Block; else if (!RTStrICmp(ValueUnion.psz, "file")) enmMethod = kMethod_File; else { Error("Invalid digest method: %s\n", ValueUnion.psz); return 1; } break; case 'h': RTPrintf("syntax: tstRTDigest -t <digest-type> file [file2 [..]]\n"); return 1; case VINF_GETOPT_NOT_OPTION: { if (enmDigestType == kDigestType_NotSpecified) return Error("No digest type was specified\n"); switch (enmMethod) { case kMethod_Full: return Error("Full file method is not implemented\n"); case kMethod_File: switch (enmDigestType) { case kDigestType_SHA1: { char *pszDigest; int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc); RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); RTStrFree(pszDigest); break; } default: return Error("The file method isn't implemented for this digest\n"); } break; case kMethod_Block: { RTFILE hFile; int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc); size_t cbRead; uint8_t abBuf[_64K]; char *pszDigest = (char *)&abBuf[0]; switch (enmDigestType) { case kDigestType_CRC32: { uint32_t uCRC32 = RTCrc32Start(); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead); } uCRC32 = RTCrc32Finish(uCRC32); RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32); break; } case kDigestType_CRC64: { uint64_t uCRC64 = RTCrc64Start(); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead); } uCRC64 = RTCrc64Finish(uCRC64); RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64); break; } case kDigestType_MD5: { RTMD5CONTEXT Ctx; RTMd5Init(&Ctx); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTMd5Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTMD5HASHSIZE]; RTMd5Final(abDigest, &Ctx); RTMd5ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case kDigestType_SHA1: { RTSHA1CONTEXT Ctx; RTSha1Init(&Ctx); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTSha1Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA1_HASH_SIZE]; RTSha1Final(&Ctx, abDigest); RTSha1ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case kDigestType_SHA256: { RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTSha256Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abDigest); RTSha256ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case kDigestType_SHA512: { RTSHA512CONTEXT Ctx; RTSha512Init(&Ctx); for (;;) { rc = RTFileRead(hFile, abBuf, sizeof(abBuf), &cbRead); if (RT_FAILURE(rc) || !cbRead) break; RTSha512Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA512_HASH_SIZE]; RTSha512Final(&Ctx, abDigest); RTSha512ToString(abDigest, pszDigest, sizeof(abBuf)); break; } default: return Error("Internal error #1\n"); } RTFileClose(hFile); if (RT_FAILURE(rc) && rc != VERR_EOF) { RTPrintf("Partial: %s %s\n", pszDigest, ValueUnion.psz); return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc); } RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); break; } default: return Error("Internal error #2\n"); } break; } default: return RTGetOptPrintError(ch, &ValueUnion); } } return 0; }
static int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint, vbsf_mount_opts *pOpts) { AssertPtr(pOpts); int rc = VINF_SUCCESS; char szAlreadyMountedTo[RTPATH_MAX]; /* If a Shared Folder already is mounted but not to our desired mount point, * do an unmount first! */ if ( VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo)) && RTStrICmp(pszMountPoint, szAlreadyMountedTo)) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n", pszShareName, szAlreadyMountedTo); rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo); if (RT_FAILURE(rc)) VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n", szAlreadyMountedTo, strerror(errno), errno); } if (RT_SUCCESS(rc)) rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts); if (RT_SUCCESS(rc)) { #ifdef RT_OS_SOLARIS char achOptBuf[MAX_MNTOPT_STR] = { '\0', }; int flags = 0; if (pOpts->ronly) flags |= MS_RDONLY; RTStrPrintf(achOptBuf, sizeof(achOptBuf), "uid=%d,gid=%d", pOpts->uid, pOpts->gid); int r = mount(pszShareName, pszMountPoint, flags | MS_OPTIONSTR, "vboxfs", NULL, /* char *dataptr */ 0, /* int datalen */ achOptBuf, sizeof(achOptBuf)); if (r == 0) { VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint); } else { if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */ VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n", pszShareName, pszMountPoint, strerror(errno)); } #else /* !RT_OS_SOLARIS */ unsigned long flags = MS_NODEV; const char *szOptions = { "rw" }; struct vbsf_mount_info_new mntinf; mntinf.nullchar = '\0'; mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0; mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1; mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2; mntinf.length = sizeof(mntinf); mntinf.uid = pOpts->uid; mntinf.gid = pOpts->gid; mntinf.ttl = pOpts->ttl; mntinf.dmode = pOpts->dmode; mntinf.fmode = pOpts->fmode; mntinf.dmask = pOpts->dmask; mntinf.fmask = pOpts->fmask; strcpy(mntinf.name, pszShareName); strcpy(mntinf.nls_name, "\0"); int r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf); if (r == 0) { VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint); r = vbsfmount_complete(pszShareName, pszMountPoint, flags, pOpts); switch (r) { case 0: /* Success. */ errno = 0; /* Clear all errors/warnings. */ break; case 1: VBoxServiceError("VBoxServiceAutoMountWorker: Could not update mount table (failed to create memstream): %s\n", strerror(errno)); break; case 2: VBoxServiceError("VBoxServiceAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno)); break; case 3: /* VBoxServiceError("VBoxServiceAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno)); */ errno = 0; break; default: VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r); break; } } else /* r == -1, we got some error in errno. */ { if (errno == EPROTO) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Messed up share name, re-trying ...\n"); /* Sometimes the mount utility messes up the share name. Try to * un-mangle it again. */ char szCWD[4096]; size_t cchCWD; if (!getcwd(szCWD, sizeof(szCWD))) VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n"); cchCWD = strlen(szCWD); if (!strncmp(pszMountPoint, szCWD, cchCWD)) { while (pszMountPoint[cchCWD] == '/') ++cchCWD; /* We checked before that we have enough space */ strcpy(mntinf.name, pszMountPoint + cchCWD); } r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf); } if (errno == EPROTO) { VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Re-trying with old mounting structure ...\n"); /* New mount tool with old vboxsf module? Try again using the old * vbsf_mount_info_old structure. */ struct vbsf_mount_info_old mntinf_old; memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME); memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME); mntinf_old.uid = mntinf.uid; mntinf_old.gid = mntinf.gid; mntinf_old.ttl = mntinf.ttl; r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf_old); } if (r == -1) /* Was there some error from one of the tries above? */ { switch (errno) { /* If we get EINVAL here, the system already has mounted the Shared Folder to another * mount point. */ case EINVAL: VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already is mounted!\n", pszShareName); /* Ignore this error! */ break; case EBUSY: /* Ignore these errors! */ break; default: VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\": %s (%d)\n", pszShareName, pszMountPoint, strerror(errno), errno); rc = RTErrConvertFromErrno(errno); break; } } } #endif /* !RT_OS_SOLARIS */ } VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Mounting returned with rc=%Rrc\n", rc); return rc; }
/** * Corrects the casing of the final component * * @returns * @param pClient . * @param pszFullPath . * @param pszStartComponent . */ static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent) { Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent)); AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2); AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5); /* * Allocate a buffer that can hold really long file name entries as well as * the initial search pattern. */ size_t cchComponent = strlen(pszStartComponent); size_t cchParentDir = pszStartComponent - pszFullPath; size_t cchFullPath = cchParentDir + cchComponent; Assert(strlen(pszFullPath) == cchFullPath); size_t cbDirEntry = 4096; if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName)) cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4; PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry); if (pDirEntry == NULL) return VERR_NO_MEMORY; /* * Construct the search criteria in the szName member of pDirEntry. */ /** @todo This is quite inefficient, especially for directories with many * files. If any of the typically case sensitive host systems start * supporting opendir wildcard filters, it would make sense to build * one here with '?' for case foldable charaters. */ /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */ int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName), pszFullPath, cchParentDir, RT_STR_TUPLE("*")); AssertRC(rc); if (RT_SUCCESS(rc)) { PRTDIR hSearch = NULL; rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0); if (RT_SUCCESS(rc)) { for (;;) { size_t cbDirEntrySize = cbDirEntry; rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient)); if (rc == VERR_NO_MORE_FILES) break; if ( rc != VINF_SUCCESS && rc != VWRN_NO_DIRENT_INFO) { AssertFailed(); if ( rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING) continue; break; } Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0])); if ( pDirEntry->cbName == cchComponent && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0])) { Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent)); strcpy(pszStartComponent, &pDirEntry->szName[0]); rc = VINF_SUCCESS; break; } } RTDirClose(hSearch); } } if (RT_FAILURE(rc)) Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc)); RTMemFree(pDirEntry); return rc; }
DECLEXPORT(int) pam_sm_authenticate(pam_handle_t *hPAM, int iFlags, int argc, const char **argv) { RT_NOREF1(iFlags); /* Parse arguments. */ for (int i = 0; i < argc; i++) { if (!RTStrICmp(argv[i], "debug")) g_verbosity = 1; else pam_vbox_error(hPAM, "pam_vbox_authenticate: unknown command line argument \"%s\"\n", argv[i]); } pam_vbox_log(hPAM, "pam_vbox_authenticate called\n"); int rc = pam_vbox_init(hPAM); if (RT_FAILURE(rc)) return PAM_SUCCESS; /* Jump out as early as we can to not mess around. */ bool fFallback = true; #ifdef VBOX_WITH_GUEST_PROPS uint32_t uClientId; rc = VbglR3GuestPropConnect(&uClientId); if (RT_SUCCESS(rc)) { char szVal[256]; rc = pam_vbox_read_prop(hPAM, uClientId, "/VirtualBox/GuestAdd/PAM/CredsWait", true /* Read-only on guest */, szVal, sizeof(szVal)); if (RT_SUCCESS(rc)) { /* All calls which are checked against rc2 are not critical, e.g. it does * not matter if they succeed or not. */ uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */ int rc2 = pam_vbox_read_prop(hPAM, uClientId, "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout", true /* Read-only on guest */, szVal, sizeof(szVal)); if (RT_SUCCESS(rc2)) { uTimeoutMS = RTStrToUInt32(szVal); if (!uTimeoutMS) { pam_vbox_error(hPAM, "pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n"); uTimeoutMS = RT_INDEFINITE_WAIT; } else uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */ } rc2 = pam_vbox_read_prop(hPAM, uClientId, "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting", true /* Read-only on guest */, szVal, sizeof(szVal)); const char *pszWaitMsg = NULL; if (RT_SUCCESS(rc2)) pszWaitMsg = szVal; rc2 = vbox_set_msg(hPAM, 0 /* Info message */, pszWaitMsg ? pszWaitMsg : "Waiting for credentials ..."); if (RT_FAILURE(rc2)) /* Not critical. */ pam_vbox_error(hPAM, "pam_vbox_authenticate: error setting waiting information message, rc=%Rrc\n", rc2); if (RT_SUCCESS(rc)) { /* Before we actuall wait for credentials just make sure we didn't already get credentials * set so that we can skip waiting for them ... */ rc = pam_vbox_check_creds(hPAM); if (rc == VERR_NOT_FOUND) { rc = pam_vbox_wait_for_creds(hPAM, uClientId, uTimeoutMS); if (rc == VERR_TIMEOUT) { pam_vbox_log(hPAM, "pam_vbox_authenticate: no credentials given within time\n"); rc2 = pam_vbox_read_prop(hPAM, uClientId, "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout", true /* Read-only on guest */, szVal, sizeof(szVal)); if (RT_SUCCESS(rc2)) { rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal); AssertRC(rc2); } } else if (rc == VERR_CANCELLED) { pam_vbox_log(hPAM, "pam_vbox_authenticate: waiting aborted\n"); rc2 = pam_vbox_read_prop(hPAM, uClientId, "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort", true /* Read-only on guest */, szVal, sizeof(szVal)); if (RT_SUCCESS(rc2)) { rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal); AssertRC(rc2); } } } /* If we got here we don't need the fallback, so just deactivate it. */ fFallback = false; } } VbglR3GuestPropDisconnect(uClientId); } #endif /* VBOX_WITH_GUEST_PROPS */ if (fFallback) { pam_vbox_log(hPAM, "pam_vbox_authenticate: falling back to old method\n"); /* If anything went wrong in the code above we just do a credentials * check like it was before: Try retrieving the stuff and authenticating. */ int rc2 = pam_vbox_check_creds(hPAM); if (RT_SUCCESS(rc)) rc = rc2; } pam_vbox_shutdown(hPAM); pam_vbox_log(hPAM, "pam_vbox_authenticate: overall result rc=%Rrc\n", rc); /* Never report an error here because if no credentials from the host are available or something * went wrong we then let do the authentication by the next module in the stack. */ /* We report success here because this is all we can do right now -- we passed the credentials * to the next PAM module in the block above which then might do a shadow (like pam_unix/pam_unix2) * password verification to "really" authenticate the user. */ return PAM_SUCCESS; }
/** * Value string -> Value union. * * @returns IPRT status code. * @param fFlags The value flags. * @param pszValue The value string. * @param pValueUnion Where to return the processed value. */ static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion) { /* * Transform into a option value as requested. * If decimal conversion fails, we'll check for "0x<xdigit>" and * try a 16 based conversion. We will not interpret any of the * generic ints as octals. */ switch (fFlags & ( RTGETOPT_REQ_MASK | RTGETOPT_FLAG_HEX | RTGETOPT_FLAG_DEC | RTGETOPT_FLAG_OCT)) { case RTGETOPT_REQ_STRING: pValueUnion->psz = pszValue; break; case RTGETOPT_REQ_BOOL: if ( !RTStrICmp(pszValue, "true") || !RTStrICmp(pszValue, "t") || !RTStrICmp(pszValue, "yes") || !RTStrICmp(pszValue, "y") || !RTStrICmp(pszValue, "enabled") || !RTStrICmp(pszValue, "enable") || !RTStrICmp(pszValue, "en") || !RTStrICmp(pszValue, "e") || !RTStrICmp(pszValue, "on") || !RTStrCmp(pszValue, "1") ) pValueUnion->f = true; else if ( !RTStrICmp(pszValue, "false") || !RTStrICmp(pszValue, "f") || !RTStrICmp(pszValue, "no") || !RTStrICmp(pszValue, "n") || !RTStrICmp(pszValue, "disabled") || !RTStrICmp(pszValue, "disable") || !RTStrICmp(pszValue, "dis") || !RTStrICmp(pszValue, "d") || !RTStrICmp(pszValue, "off") || !RTStrCmp(pszValue, "0") ) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; case RTGETOPT_REQ_BOOL_ONOFF: if (!RTStrICmp(pszValue, "on")) pValueUnion->f = true; else if (!RTStrICmp(pszValue, "off")) pValueUnion->f = false; else { pValueUnion->psz = pszValue; return VERR_GETOPT_UNKNOWN_OPTION; } break; #define MY_INT_CASE(req, type, memb, convfn) \ case req: \ { \ type Value; \ if ( convfn(pszValue, 10, &Value) != VINF_SUCCESS \ && ( pszValue[0] != '0' \ || (pszValue[1] != 'x' && pszValue[1] != 'X') \ || !RT_C_IS_XDIGIT(pszValue[2]) \ || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } #define MY_BASE_INT_CASE(req, type, memb, convfn, base) \ case req: \ { \ type Value; \ if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \ return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \ pValueUnion->memb = Value; \ break; \ } MY_INT_CASE(RTGETOPT_REQ_INT8, int8_t, i8, RTStrToInt8Full) MY_INT_CASE(RTGETOPT_REQ_INT16, int16_t, i16, RTStrToInt16Full) MY_INT_CASE(RTGETOPT_REQ_INT32, int32_t, i32, RTStrToInt32Full) MY_INT_CASE(RTGETOPT_REQ_INT64, int64_t, i64, RTStrToInt64Full) MY_INT_CASE(RTGETOPT_REQ_UINT8, uint8_t, u8, RTStrToUInt8Full) MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full) MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full) MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_HEX, int8_t, i8, RTStrToInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_HEX, int16_t, i16, RTStrToInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_HEX, int32_t, i32, RTStrToInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_HEX, int64_t, i64, RTStrToInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_HEX, uint8_t, u8, RTStrToUInt8Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_DEC, int8_t, i8, RTStrToInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_DEC, int16_t, i16, RTStrToInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_DEC, int32_t, i32, RTStrToInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_DEC, int64_t, i64, RTStrToInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_DEC, uint8_t, u8, RTStrToUInt8Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10) MY_BASE_INT_CASE(RTGETOPT_REQ_INT8 | RTGETOPT_FLAG_OCT, int8_t, i8, RTStrToInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT16 | RTGETOPT_FLAG_OCT, int16_t, i16, RTStrToInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT32 | RTGETOPT_FLAG_OCT, int32_t, i32, RTStrToInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_INT64 | RTGETOPT_FLAG_OCT, int64_t, i64, RTStrToInt64Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8 | RTGETOPT_FLAG_OCT, uint8_t, u8, RTStrToUInt8Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8) MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8) #undef MY_INT_CASE #undef MY_BASE_INT_CASE case RTGETOPT_REQ_IPV4ADDR: { RTNETADDRIPV4 Addr; if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->IPv4Addr = Addr; break; } case RTGETOPT_REQ_IPV4CIDR: { RTNETADDRIPV4 network; RTNETADDRIPV4 netmask; if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->CidrIPv4.IPv4Network.u = network.u; pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u; break; } case RTGETOPT_REQ_MACADDR: { RTMAC Addr; if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->MacAddr = Addr; break; } case RTGETOPT_REQ_UUID: { RTUUID Uuid; if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; pValueUnion->Uuid = Uuid; break; } default: AssertMsgFailed(("f=%#x\n", fFlags)); return VERR_INTERNAL_ERROR; } return VINF_SUCCESS; }
/** * Checks if a testcase is include or should be skipped. * * @param pszTestcase The testcase (filename). * * @return true if the testcase is included. * false if the testcase should be skipped. */ static bool IsTestcaseIncluded(const char *pszTestcase) { /* exclude special modules based on extension. */ const char *pszExt = RTPathExt(pszTestcase); if ( !RTStrICmp(pszExt, ".r0") || !RTStrICmp(pszExt, ".gc") || !RTStrICmp(pszExt, ".sys") || !RTStrICmp(pszExt, ".ko") || !RTStrICmp(pszExt, ".o") || !RTStrICmp(pszExt, ".obj") || !RTStrICmp(pszExt, ".lib") || !RTStrICmp(pszExt, ".a") || !RTStrICmp(pszExt, ".so") || !RTStrICmp(pszExt, ".dll") || !RTStrICmp(pszExt, ".dylib") || !RTStrICmp(pszExt, ".tmp") || !RTStrICmp(pszExt, ".log") ) return false; /* check by name */ char *pszDup = RTStrDup(pszTestcase); if (pszDup) { RTPathStripExt(pszDup); for (unsigned i = 0; i < RT_ELEMENTS(g_apszExclude); i++) { if (!strcmp(g_apszExclude[i], pszDup)) { RTStrFree(pszDup); return false; } } RTStrFree(pszDup); return true; } RTPrintf("tstRunTestcases: Out of memory!\n"); return false; }
/** @copydoc VDIMAGEBACKEND::pfnProbe */ static DECLCALLBACK(int) rawProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, VDTYPE *penmType) { RT_NOREF1(pVDIfsDisk); LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage)); PVDIOSTORAGE pStorage = NULL; PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage); AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER); AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER); /* * Open the file and read the footer. */ int rc = vdIfIoIntFileOpen(pIfIo, pszFilename, VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY, false /* fCreate */), &pStorage); if (RT_SUCCESS(rc)) { uint64_t cbFile; const char *pszSuffix = RTPathSuffix(pszFilename); rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile); /* Try to guess the image type based on the extension. */ if ( RT_SUCCESS(rc) && pszSuffix) { if ( !RTStrICmp(pszSuffix, ".iso") || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */ { /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish * between raw floppy and CD images based on their size (and cannot be reliably done * based on contents, either). */ if (cbFile % 2048) rc = VERR_VD_RAW_SIZE_MODULO_2048; else if (cbFile <= 32768) rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL; else { *penmType = VDTYPE_DVD; rc = VINF_SUCCESS; } } else if ( !RTStrICmp(pszSuffix, ".img") || !RTStrICmp(pszSuffix, ".ima") || !RTStrICmp(pszSuffix, ".dsk") || !RTStrICmp(pszSuffix, ".flp") || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */ { if (cbFile % 512) rc = VERR_VD_RAW_SIZE_MODULO_512; else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE) rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG; else { *penmType = VDTYPE_FLOPPY; rc = VINF_SUCCESS; } } else rc = VERR_VD_RAW_INVALID_HEADER; } else rc = VERR_VD_RAW_INVALID_HEADER; } if (pStorage) vdIfIoIntFileClose(pIfIo, pStorage); LogFlowFunc(("returns %Rrc\n", rc)); return rc; }
/** * Handles the getregisters sub-command. * * @returns Suitable exit code. * @param pArgs The handler arguments. * @param pDebugger Pointer to the debugger interface. */ static RTEXITCODE handleDebugVM_GetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger) { /* * We take a list of register names (case insensitive). If 'all' is * encountered we'll dump all registers. */ ULONG idCpu = 0; unsigned cRegisters = 0; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; static const RTGETOPTDEF s_aOptions[] = { { "--cpu", 'c', RTGETOPT_REQ_UINT32 }, }; int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); AssertRCReturn(rc, RTEXITCODE_FAILURE); while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (rc) { case 'c': idCpu = ValueUnion.u32; break; case VINF_GETOPT_NOT_OPTION: if (!RTStrICmp(ValueUnion.psz, "all")) { com::SafeArray<BSTR> aBstrNames; com::SafeArray<BSTR> aBstrValues; CHECK_ERROR2I_RET(pDebugger, GetRegisters(idCpu, ComSafeArrayAsOutParam(aBstrNames), ComSafeArrayAsOutParam(aBstrValues)), RTEXITCODE_FAILURE); Assert(aBstrNames.size() == aBstrValues.size()); size_t cchMaxName = 8; for (size_t i = 0; i < aBstrNames.size(); i++) { size_t cchName = RTUtf16Len(aBstrNames[i]); if (cchName > cchMaxName) cchMaxName = cchName; } for (size_t i = 0; i < aBstrNames.size(); i++) RTPrintf("%-*ls = %ls\n", cchMaxName, aBstrNames[i], aBstrValues[i]); } else { com::Bstr bstrName = ValueUnion.psz; com::Bstr bstrValue; CHECK_ERROR2I_RET(pDebugger, GetRegister(idCpu, bstrName.raw(), bstrValue.asOutParam()), RTEXITCODE_FAILURE); RTPrintf("%s = %ls\n", ValueUnion.psz, bstrValue.raw()); } cRegisters++; break; default: return errorGetOpt(rc, &ValueUnion); } } if (!cRegisters) return errorSyntax("The getregisters sub-command takes at least one register name"); return RTEXITCODE_SUCCESS; }