* Solaris as well, but that path is untested.
*/
+#define MAX_USER_NAME_LEN 256
+
/*
* A single retry works for the LDAP case, but try more often in case NIS
* or something else has a related issue. Note that a bad username/uid won't
* restricted list for local usernames.
*/
size_t len;
- char *illegalChars = "<>/";
+ size_t i = 0;
+ int backSlashCnt = 0;
+ /*
+ * As user names are used to generate its alias store file name/path, it
+ * should not contain path traversal characters ('/' and '\').
+ */
+ char *illegalChars = "<>/\\";
len = strlen(userName);
- if (strcspn(userName, illegalChars) != len) {
+ if (len > MAX_USER_NAME_LEN) {
return FALSE;
}
+
+ while ((i += strcspn(userName + i, illegalChars)) < len) {
+ /*
+ * One backward slash is allowed for domain\username separator.
+ */
+ if (userName[i] != '\\' || ++backSlashCnt > 1) {
+ return FALSE;
+ }
+ ++i;
+ }
+
return TRUE;
}
#include "certverify.h"
#include "VGAuthProto.h"
#include "vmxlog.h"
+#include "VGAuthUtil.h"
// puts the identity store in an easy to find place
#undef WIN_TEST_MODE
#define ALIASSTORE_FILE_PREFIX "user-"
#define ALIASSTORE_FILE_SUFFIX ".xml"
+static gboolean allowSymlinks = FALSE;
static gchar *aliasStoreRootDir = DEFAULT_ALIASSTORE_ROOT_DIR;
#ifdef _WIN32
*/
+#ifdef _WIN32
+#define ISPATHSEP(c) ((c) == '\\' || (c) == '/')
+#else
+#define ISPATHSEP(c) ((c) == '/')
+#endif
+
/*
******************************************************************************
gunichar2 *fileNameW = NULL;
BOOL ok;
DWORD bytesRead;
+ gchar *realPath = NULL;
*fileSize = 0;
*contents = NULL;
goto done;
}
+ if (!allowSymlinks) {
+ /*
+ * Check if fileName is real path.
+ */
+ if ((realPath = ServiceFileGetPathByHandle(hFile)) == NULL) {
+ err = VGAUTH_E_FAIL;
+ goto done;
+ }
+ if (Util_Utf8CaseCmp(realPath, fileName) != 0) {
+ Warning("%s: Real path (%s) is not same as file path (%s)\n",
+ __FUNCTION__, realPath, fileName);
+ err = VGAUTH_E_FAIL;
+ goto done;
+ }
+ }
+
/*
* Now finally read the contents.
*/
CloseHandle(hFile);
}
g_free(fileNameW);
+ g_free(realPath);
return err;
}
gchar *buf;
gchar *bp;
int fd = -1;
+ gchar realPath[PATH_MAX] = { 0 };
*fileSize = 0;
*contents = NULL;
goto done;
}
+ if (!allowSymlinks) {
+ /*
+ * Check if fileName is real path.
+ */
+ if (realpath(fileName, realPath) == NULL) {
+ Warning("%s: realpath() failed. errno (%d)\n", __FUNCTION__, errno);
+ err = VGAUTH_E_FAIL;
+ goto done;
+ }
+ if (g_strcmp0(realPath, fileName) != 0) {
+ Warning("%s: Real path (%s) is not same as file path (%s)\n",
+ __FUNCTION__, realPath, fileName);
+ err = VGAUTH_E_FAIL;
+ goto done;
+ }
+ }
+
/*
* All confidence checks passed; read the bits.
*/
/*
* We don't verify the user exists in a Remove operation, to allow
- * cleanup of deleted user's stores.
+ * cleanup of deleted user's stores, but we do check whether the
+ * user name is legal or not.
*/
+ if (!Usercheck_UsernameIsLegal(userName)) {
+ Warning("%s: Illegal user name '%s'\n", __FUNCTION__, userName);
+ return VGAUTH_E_FAIL;
+ }
if (!CertVerify_IsWellFormedPEMCert(pemCert)) {
return VGAUTH_E_INVALID_CERTIFICATE;
}
#endif
+ /*
+ * We don't verify the user exists in a Query operation to allow
+ * cleaning up after a deleted user, but we do check whether the
+ * user name is legal or not.
+ */
+ if (!Usercheck_UsernameIsLegal(userName)) {
+ Warning("%s: Illegal user name '%s'\n", __FUNCTION__, userName);
+ return VGAUTH_E_FAIL;
+ }
+
err = AliasLoadAliases(userName, num, aList);
if (VGAUTH_E_OK != err) {
Warning("%s: failed to load Aliases for '%s'\n", __FUNCTION__, userName);
VGAuthError err = VGAUTH_E_OK;
gboolean saveBadDir = FALSE;
char *defaultDir = NULL;
+ size_t len;
#ifdef _WIN32
{
defaultDir = g_strdup(DEFAULT_ALIASSTORE_ROOT_DIR);
#endif
+ allowSymlinks = Pref_GetBool(gPrefs,
+ VGAUTH_PREF_ALLOW_SYMLINKS,
+ VGAUTH_PREF_GROUP_NAME_SERVICE,
+ FALSE);
/*
* Find the alias store directory. This allows an installer to put
* it somewhere else if necessary.
VGAUTH_PREF_GROUP_NAME_SERVICE,
defaultDir);
+ /*
+ * Remove the trailing separator if any from aliasStoreRootDir path.
+ */
+ len = strlen(aliasStoreRootDir);
+ if (ISPATHSEP(aliasStoreRootDir[len - 1])) {
+ aliasStoreRootDir[len - 1] = '\0';
+ }
+
Log("Using '%s' for alias store root directory\n", aliasStoreRootDir);
g_free(defaultDir);
#include "VGAuthUtil.h"
#ifdef _WIN32
#include "winUtil.h"
+#include <glib.h>
#endif
static ServiceStartListeningForIOFunc startListeningIOFunc = NULL;
ServiceUserNameToPipeName(const char *userName)
{
gchar *escapedName = ServiceEncodeUserName(userName);
+#ifdef _WIN32
+ /*
+ * Adding below pragma only in windows to suppress the compile time warning
+ * about unavailability of g_uuid_string_random() since compiler flag
+ * GLIB_VERSION_MAX_ALLOWED is defined to GLIB_VERSION_2_34.
+ * TODO: Remove below pragma when GLIB_VERSION_MAX_ALLOWED is bumped up to
+ * or greater than GLIB_VERSION_2_52.
+ */
+#pragma warning(suppress : 4996)
+ gchar *uuidStr = g_uuid_string_random();
+ /*
+ * Add a unique suffix to avoid a name collision with an existing named pipe
+ * created by someone else (intentionally or by accident).
+ * This is not needed for Linux; name collisions on sockets are already
+ * avoided there since (1) file system paths to VGAuthService sockets are in
+ * a directory that is writable only by root and (2) VGAuthService unlinks a
+ * socket path before binding it to a newly created socket.
+ */
+ gchar *pipeName = g_strdup_printf("%s-%s-%s",
+ SERVICE_PUBLIC_PIPE_NAME,
+ escapedName,
+ uuidStr);
+
+ g_free(uuidStr);
+#else
gchar *pipeName = g_strdup_printf("%s-%s",
SERVICE_PUBLIC_PIPE_NAME,
escapedName);
+#endif
g_free(escapedName);
return pipeName;