gboolean ToolsDaemonTcloMountHGFS(RpcInData *data) // IN { VixError err = VIX_OK; static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH]; #if defined(linux) /* * Look for a vmhgfs mount at /mnt/hgfs. If one exists, nothing * else needs to be done. If one doesn't exist, then mount at * that location. */ FILE *mtab; struct mntent *mnt; if ((mtab = setmntent(_PATH_MOUNTED, "r")) == NULL) { err = VIX_E_FAIL; } else { Bool vmhgfsMntFound = FALSE; while ((mnt = getmntent(mtab)) != NULL) { if ((strcmp(mnt->mnt_fsname, ".host:/") == 0) && (strcmp(mnt->mnt_type, HGFS_NAME) == 0) && (strcmp(mnt->mnt_dir, "/mnt/hgfs") == 0)) { vmhgfsMntFound = TRUE; break; } } endmntent(mtab); if (!vmhgfsMntFound) { /* * We need to call the mount program, not the mount system call. The * mount program does several additional things, like compute the mount * options from the contents of /etc/fstab, and invoke custom mount * programs like the one needed for HGFS. */ int ret = system("mount -t vmhgfs .host:/ /mnt/hgfs"); if (ret == -1 || WIFSIGNALED(ret) || (WIFEXITED(ret) && WEXITSTATUS(ret) != 0)) { err = VIX_E_HGFS_MOUNT_FAIL; } } } #endif /* * All tools commands return results that start with an error * and a guest-OS-specific error. */ Str_Sprintf(resultBuffer, sizeof(resultBuffer), "%"FMT64"d %d", err, Err_Errno()); RPCIN_SETRETVALS(data, resultBuffer, TRUE); return TRUE; } // ToolsDaemonTcloMountHGFS
void ToolsDaemonTcloReportProgramCompleted(const char *requestName, // IN VixError err, // IN int exitCode, // IN int64 pid, // IN void *clientData) // IN { Bool sentResult; ToolsAppCtx *ctx = clientData; gchar *msg = g_strdup_printf("%s %s %"FMT64"d %d %d %"FMT64"d", VIX_BACKDOORCOMMAND_RUN_PROGRAM_DONE, requestName, err, Err_Errno(), exitCode, (int64) pid); sentResult = RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL); g_free(msg); if (!sentResult) { Warning("Unable to send results from polling the result program.\n\n"); } } // ToolsDaemonTcloReportProgramCompleted
FileIOResult FileIO_AtomicTempFile(FileIODescriptor *fileFD, // IN: FileIODescriptor *tempFD) // OUT: { Unicode tempPath = NULL; int permissions; FileIOResult status; #if !defined(_WIN32) int ret; struct stat stbuf; #endif ASSERT(FileIO_IsValid(fileFD)); ASSERT(tempFD && !FileIO_IsValid(tempFD)); tempPath = FileIO_AtomicTempPath(FileIO_Filename(fileFD)); if (!tempPath) { status = FILEIO_ERROR; goto bail; } #if defined(_WIN32) permissions = 0; File_UnlinkIfExists(tempPath); #else if (fstat(fileFD->posix, &stbuf)) { Log("%s: Failed to fstat '%s', errno: %d.\n", __FUNCTION__, FileIO_Filename(fileFD), errno); status = FILEIO_ERROR; goto bail; } permissions = stbuf.st_mode; /* Clean up a previously created temp file; if one exists. */ ret = Posix_Unlink(tempPath); if (ret != 0 && errno != ENOENT) { Log("%s: Failed to unlink temporary file, errno: %d\n", __FUNCTION__, errno); /* Fall through; FileIO_Create will report the actual error. */ } #endif status = FileIO_Create(tempFD, tempPath, FILEIO_ACCESS_READ | FILEIO_ACCESS_WRITE, FILEIO_OPEN_CREATE_SAFE, permissions); if (!FileIO_IsSuccess(status)) { Log("%s: Failed to create temporary file, %s (%d). errno: %d\n", __FUNCTION__, FileIO_ErrorEnglish(status), status, Err_Errno()); goto bail; } #if !defined(_WIN32) /* * On ESX we always use the vmkernel atomic file swap primitive, so * there's no need to set the permissions and owner of the temp file. * * XXX this comment is not true for NFS on ESX -- we use rename rather * than "vmkernel atomic file swap primitive" -- but we do not care * because files are always owned by root. Sigh. Bug 839283. */ if (!HostType_OSIsVMK()) { if (fchmod(tempFD->posix, stbuf.st_mode)) { Log("%s: Failed to chmod temporary file, errno: %d\n", __FUNCTION__, errno); status = FILEIO_ERROR; goto bail; } if (fchown(tempFD->posix, stbuf.st_uid, stbuf.st_gid)) { Log("%s: Failed to chown temporary file, errno: %d\n", __FUNCTION__, errno); status = FILEIO_ERROR; goto bail; } } #endif Unicode_Free(tempPath); return FILEIO_SUCCESS; bail: ASSERT(!FileIO_IsSuccess(status)); if (FileIO_IsValid(tempFD)) { FileIO_Close(tempFD); #if defined(_WIN32) File_UnlinkIfExists(tempPath); #else ret = Posix_Unlink(tempPath); if (ret != 0) { Log("%s: Failed to clean up temporary file, errno: %d\n", __FUNCTION__, errno); } ASSERT(ret == 0); #endif } Unicode_Free(tempPath); return status; }
gboolean FoundryToolsDaemonGetToolsProperties(RpcInData *data) // IN { VixError err = VIX_OK; int additionalError = 0; static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH]; char *serializedBuffer = NULL; size_t serializedBufferLength = 0; char *base64Buffer = NULL; size_t base64BufferLength = 0; Bool success; char *returnBuffer = NULL; GKeyFile *confDictRef; /* * Collect some values about the host. */ confDictRef = data->clientData; err = VixTools_GetToolsPropertiesImpl(confDictRef, &serializedBuffer, &serializedBufferLength); if (VIX_OK == err) { base64BufferLength = Base64_EncodedLength(serializedBuffer, serializedBufferLength) + 1; base64Buffer = Util_SafeMalloc(base64BufferLength); success = Base64_Encode(serializedBuffer, serializedBufferLength, base64Buffer, base64BufferLength, &base64BufferLength); if (!success) { base64Buffer[0] = 0; err = VIX_E_FAIL; goto abort; } base64Buffer[base64BufferLength] = 0; } abort: returnBuffer = base64Buffer; if (NULL == base64Buffer) { returnBuffer = ""; } if (VIX_OK != err) { additionalError = Err_Errno(); } /* * All VMXI tools commands return results that start with a VMXI error * and a guest-OS-specific error. */ Str_Sprintf(resultBuffer, sizeof(resultBuffer), "%"FMT64"d %d %s", err, additionalError, returnBuffer); RPCIN_SETRETVALS(data, resultBuffer, TRUE); free(serializedBuffer); free(base64Buffer); return TRUE; } // FoundryToolsDaemonGetToolsProperties
gboolean FoundryToolsDaemonRunProgram(RpcInData *data) // IN { VixError err = VIX_OK; char *requestName = NULL; char *commandLine = NULL; char *commandLineArgs = NULL; char *credentialTypeStr = NULL; char *obfuscatedNamePassword = NULL; char *directoryPath = NULL; char *environmentVariables = NULL; static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH]; Bool impersonatingVMWareUser = FALSE; void *userToken = NULL; ProcMgr_Pid pid; GMainLoop *eventQueue = ((ToolsAppCtx *)data->appCtx)->mainLoop; /* * Parse the arguments. Some of these are optional, so they * may be NULL. */ requestName = ToolsDaemonTcloGetQuotedString(data->args, &data->args); err = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args, &commandLine); if (err != VIX_OK) { goto abort; } err = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args, &commandLineArgs); if (err != VIX_OK) { goto abort; } credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args); obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args); directoryPath = ToolsDaemonTcloGetQuotedString(data->args, &data->args); environmentVariables = ToolsDaemonTcloGetQuotedString(data->args, &data->args); /* * Make sure we are passed the correct arguments. * Some of these arguments (like credentialTypeStr and obfuscatedNamePassword) are optional, * so they may be NULL. */ if ((NULL == requestName) || (NULL == commandLine)) { err = VIX_E_INVALID_ARG; goto abort; } if ((NULL != credentialTypeStr) && (*credentialTypeStr) && (thisProcessRunsAsRoot)) { impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr, VIX_USER_CREDENTIAL_NONE, obfuscatedNamePassword, &userToken); if (!impersonatingVMWareUser) { err = VIX_E_GUEST_USER_PERMISSIONS; goto abort; } } err = VixToolsRunProgramImpl(requestName, commandLine, commandLineArgs, 0, userToken, eventQueue, (int64 *) &pid); abort: if (impersonatingVMWareUser) { VixToolsUnimpersonateUser(userToken); } VixToolsLogoutUser(userToken); /* * All VMXI tools commands return results that start with a VMXI error * and a guest-OS-specific error. */ Str_Sprintf(resultBuffer, sizeof(resultBuffer), "%"FMT64"d %d %"FMT64"d", err, Err_Errno(), (int64) pid); RPCIN_SETRETVALS(data, resultBuffer, TRUE); /* * These were allocated by ToolsDaemonTcloGetQuotedString. */ free(requestName); free(commandLine); free(credentialTypeStr); free(obfuscatedNamePassword); free(directoryPath); free(environmentVariables); free(commandLineArgs); return TRUE; } // FoundryToolsDaemonRunProgram
gboolean ToolsDaemonTcloReceiveVixCommand(RpcInData *data) // IN { VixError err = VIX_OK; char *requestName = NULL; VixCommandRequestHeader *requestMsg = NULL; size_t maxResultBufferSize; size_t tcloBufferLen; char *resultValue = NULL; size_t resultValueLength = 0; Bool deleteResultValue = FALSE; char *destPtr = NULL; int vixPrefixDataSize = (MAX64_DECIMAL_DIGITS * 2) + (sizeof(' ') * 2) + sizeof('\0') + sizeof(' ') * 10; // for RPC header /* * Our temporary buffer will be the same size as what the * Tclo/RPC system can handle, which is GUESTMSG_MAX_IN_SIZE. */ static char tcloBuffer[GUESTMSG_MAX_IN_SIZE]; ToolsAppCtx *ctx = data->appCtx; GMainLoop *eventQueue = ctx->mainLoop; GKeyFile *confDictRef = ctx->config; requestName = ToolsDaemonTcloGetQuotedString(data->args, &data->args); /* * Skip the NULL, char, and then the rest of the buffer should just * be a Vix command object. */ while (*data->args) { data->args += 1; } data->args += 1; err = VixMsg_ValidateMessage((char *) data->args, data->argsSize); if (VIX_OK != err) { goto abort; } requestMsg = (VixCommandRequestHeader *) data->args; maxResultBufferSize = sizeof(tcloBuffer) - vixPrefixDataSize; err = VixTools_ProcessVixCommand(requestMsg, requestName, maxResultBufferSize, confDictRef, eventQueue, &resultValue, &resultValueLength, &deleteResultValue); abort: tcloBufferLen = resultValueLength + vixPrefixDataSize; /* * If we generated a message larger than tclo/Rpc can handle, * we did something wrong. Our code should never have done this. */ if (tcloBufferLen > sizeof tcloBuffer) { ASSERT(0); resultValue[0] = 0; tcloBufferLen = tcloBufferLen - resultValueLength; err = VIX_E_OUT_OF_MEMORY; } /* * All Foundry tools commands return results that start with a foundry error * and a guest-OS-specific error. */ Str_Sprintf(tcloBuffer, sizeof tcloBuffer, "%"FMT64"d %d ", err, Err_Errno()); destPtr = tcloBuffer + strlen(tcloBuffer); /* * If this is a binary result, then we put a # at the end of the ascii to * mark the end of ascii and the start of the binary data. */ if ((NULL != requestMsg) && (requestMsg->commonHeader.commonFlags & VIX_COMMAND_GUEST_RETURNS_BINARY)) { *(destPtr++) = '#'; data->resultLen = destPtr - tcloBuffer + resultValueLength; } /* * Copy the result. Don't use a strcpy, since this may be a binary buffer. */ memcpy(destPtr, resultValue, resultValueLength); destPtr += resultValueLength; /* * If this is not binary data, then it should be a NULL terminated string. */ if ((NULL == requestMsg) || !(requestMsg->commonHeader.commonFlags & VIX_COMMAND_GUEST_RETURNS_BINARY)) { *(destPtr++) = 0; data->resultLen = strlen(tcloBuffer) + 1; } data->result = tcloBuffer; if (deleteResultValue) { free(resultValue); } free(requestName); Debug("<ToolsDaemonTcloReceiveVixCommand\n"); return TRUE; } // ToolsDaemonTcloReceiveVixCommand
static int ScanDirectory(ConstUnicode lockDir, // IN: int (*func)( // IN: ConstUnicode lockDir, ConstUnicode fileName, LockValues *memberValues, LockValues *myValues ), LockValues *myValues, // IN: Bool cleanUp) // IN: { uint32 i; int err; int numEntries; Unicode *fileList = NULL; char *myExecutionID = NULL; char *locationChecksum = NULL; ASSERT(lockDir); numEntries = FileListDirectoryRobust(lockDir, &fileList); if (numEntries == -1) { Log(LGPFX" %s: Could not read the directory '%s': %d\n", __FUNCTION__, UTF8(lockDir), Err_Errno()); return EDOM; // out of my domain } /* Pass 1: Validate entries and handle any 'D' entries */ for (i = 0, err = 0; i < numEntries; i++) { /* Remove any non-locking files */ if (!FileLockValidName(fileList[i])) { Log(LGPFX" %s discarding %s from %s'; invalid file name.\n", __FUNCTION__, UTF8(fileList[i]), UTF8(lockDir)); err = RemoveLockingFile(lockDir, fileList[i]); if (err != 0) { goto bail; } Unicode_Free(fileList[i]); fileList[i] = NULL; continue; } /* * Any lockers appear to be entering? * * This should be rather rare. If a locker dies while entering * this will cleaned-up. */ if (Unicode_StartsWith(fileList[i], "D")) { if (cleanUp) { err = ActivateLockList(fileList[i], myValues); if (err != 0) { goto bail; } } Unicode_Free(fileList[i]); fileList[i] = NULL; } } if (myValues->lockList != NULL) { goto bail; } myExecutionID = FileLockGetExecutionID(); locationChecksum = FileLockLocationChecksum(lockDir); /* Pass 2: Handle the 'M' entries */ for (i = 0, err = 0; i < numEntries; i++) { LockValues *ptr; Bool myLockFile; LockValues memberValues; char buffer[FILELOCK_DATA_SIZE]; if ((fileList[i] == NULL) || (Unicode_StartsWith(fileList[i], "E"))) { continue; } myLockFile = (Unicode_Compare(fileList[i], myValues->memberName) == 0) ? TRUE : FALSE; if (myLockFile) { /* It's me! No need to read or validate anything. */ ptr = myValues; } else { /* It's not me! Attempt to extract the member values. */ err = FileLockMemberValues(lockDir, fileList[i], buffer, FILELOCK_DATA_SIZE, &memberValues); if (err != 0) { if (err == ENOENT) { err = 0; /* Not there anymore; locker unlocked or timed out */ continue; } break; } /* Remove any stale locking files */ if (FileLockMachineIDMatch(myValues->machineID, memberValues.machineID)) { char *dispose = NULL; if (FileLockValidOwner(memberValues.executionID, memberValues.payload)) { /* If it's mine it better still be where I put it! */ if ((strcmp(myExecutionID, memberValues.executionID) == 0) && ((memberValues.locationChecksum != NULL) && (strcmp(memberValues.locationChecksum, locationChecksum) != 0))) { dispose = "lock file has been moved."; } } else { dispose = "invalid executionID."; } if (dispose) { Log(LGPFX" %s discarding %s from %s': %s\n", __FUNCTION__, UTF8(fileList[i]), UTF8(lockDir), dispose); Unicode_Free(memberValues.memberName); err = RemoveLockingFile(lockDir, fileList[i]); if (err != 0) { break; } continue; } } ptr = &memberValues; } /* Locking file looks good; see what happens */ err = (*func)(lockDir, fileList[i], ptr, myValues); if (ptr == &memberValues) { Unicode_Free(memberValues.memberName); } if (err != 0) { break; } } bail: for (i = 0; i < numEntries; i++) { Unicode_Free(fileList[i]); } free(fileList); free(locationChecksum); free(myExecutionID); return err; }
const char * Err_ErrString(void) { return Err_Errno2String(Err_Errno()); }
const char * Err_Errno2String(Err_Number errorNumber) // IN { HashTable *numTable; HashTable *ptrTable; ErrInfo *info; ErrInfo *oldInfo; Err_Number oldErrno = Err_Errno(); ASSERT(errorNumber != ERR_INVALID); /* * Look up the error in numTable. * Or insert it if it's not there. */ numTable = NUMTABLE(); if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber, (void **) &info)) { char buf[2048]; const char *p; size_t n; /* * Convert number to string and build the info structure. */ p = ErrErrno2String(errorNumber, buf, sizeof buf); info = Util_SafeMalloc(sizeof *info); info->number = errorNumber; info->string = Util_SafeStrdup(p); /* * To be safe, make sure the end of the string is at * a UTF-8 boundary, but we can only do this when the * string is in our buffer (it may not be). */ n = strlen(info->string); n = CodeSet_Utf8FindCodePointBoundary(info->string, n); info->string[n] = '\0'; /* * Try to insert new info into numTable. * If that fails, then we must have lost out to someone else. * Use theirs in that case. */ oldInfo = HashTable_LookupOrInsert(numTable, (void *) (uintptr_t) errorNumber, info); if (oldInfo != info) { ASSERT(oldInfo->number == info->number); ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0); free(info->string); free(info); info = oldInfo; } } /* * Try to insert info into ptrTable. * We need to do it even if we didn't create this entry, * because we may get here before the other guy (who created * the entry and inserted it into numTable). */ ptrTable = PTRTABLE(); oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info); ASSERT(oldInfo == info); #if defined VMX86_DEBUG && defined __linux__ { HashTable *strTable = STRTABLE(); ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info); ASSERT(i == info); } #endif Err_SetErrno(oldErrno); return info->string; }