author | Sebastian Harl <sh@tokkee.org> | |
Fri, 12 Dec 2014 07:55:39 +0000 (08:55 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Fri, 12 Dec 2014 07:57:51 +0000 (08:57 +0100) |
13 files changed:
diff --git a/configure.ac b/configure.ac
index 088a4b59fc994ad313dbd9540b1fc70901808b6d..baf1137b530197b1689be9106ff4f9751b70377b 100644 (file)
--- a/configure.ac
+++ b/configure.ac
m4_divert_once([HELP_ENABLE], [
Build dependencies:])
+AC_CHECK_HEADERS([ucred.h])
+dnl On OpenBSD, sys/param.h is required for sys/ucred.h.
+AC_CHECK_HEADERS([sys/ucred.h], [], [],
+ [[ #include <sys/param.h> ]])
+
+AC_CHECK_TYPES([struct ucred],
+ [have_struct_ucred="yes"], [have_struct_ucred="no"],
+ [[
+#include <sys/socket.h>
+#include <sys/param.h>
+#if HAVE_UCRED_H
+# include <ucred.h>
+#endif
+ ]])
+
+if test "x$have_struct_ucred" != "xyes"; then
+ AC_MSG_CHECKING([for struct ucred when using _GNU_SOURCE])
+ orig_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -D_GNU_SOURCE"
+ dnl Don't reuse AC_CHECK_HEADERS; for one it'll use the cached value
+ dnl but also, it will print the "checking for" message a second time.
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+#include <sys/socket.h>
+#include <sys/param.h>
+#if HAVE_UCRED_H
+# include <ucred.h>
+#endif
+ ]],
+ [if (sizeof(struct ucred)) return 0;]
+ )],
+ [have_struct_ucred="yes"], [have_struct_ucred="no"])
+ CFLAGS="$orig_CFLAGS"
+ if test "x$have_struct_ucred" = "xyes"; then
+ AC_DEFINE([_GNU_SOURCE], 1, [Define to enable GNU features.])
+ fi
+ AC_MSG_RESULT([$have_struct_ucred])
+fi
+
dnl Testing.
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4],
[unit_tests="yes"], [unit_tests="no"])
AC_MSG_CHECKING([for facter::facts::collection in -lfacter])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
- [[[ #include <facter/facts/collection.hpp> ]]],
- [[[
+ [[ #include <facter/facts/collection.hpp> ]],
+ [[
facter::facts::collection facts;
facts.add_default_facts();
- ]]]
+ ]]
)],
[TEST_LIBS=$TEST_LIBS -lfacter],
[have_libfacter="yes"],
diff --git a/src/Makefile.am b/src/Makefile.am
index 3472b6f527ed55068670db2cd99069e2f40ef0c7..ca558623722049c61fb8808d035aaf1867bdaa37 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
tools/sysdb/command.c tools/sysdb/command.h \
tools/sysdb/input.c tools/sysdb/input.h \
core/object.c include/core/object.h \
- utils/llist.c include/utils/llist.h
+ utils/llist.c include/utils/llist.h \
+ utils/os.c include/utils/os.h
sysdb_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \
$(AM_CFLAGS) @READLINE_CFLAGS@
sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la @READLINE_LIBS@
diff --git a/src/client/sock.c b/src/client/sock.c
index ef35166bab13162e84156facbd75d83fdd937b85..533e9e31b62c16457f36ae1e844a450251c26c51 100644 (file)
--- a/src/client/sock.c
+++ b/src/client/sock.c
"for server response");
if (rstatus == SDB_CONNECTION_ERROR) {
- sdb_log(SDB_LOG_ERR, "Access denied for user '%s'", username);
+ sdb_log(SDB_LOG_ERR, "Access denied for user '%s': %s",
+ username, sdb_strbuf_string(buf));
status = -((int)rstatus);
}
else if (rstatus != SDB_CONNECTION_OK) {
index e384bafa98297a7cf46c9283dee7b70a9c484dab..b27b3dd28bfbfd0324941d1861bc2bdd5d60a8ca 100644 (file)
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include "sysdb.h"
#include "core/object.h"
#include "core/plugin.h"
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef HAVE_UCRED_H
+# include <ucred.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+# include <sys/ucred.h>
+#endif
+
+#include <pwd.h>
+
#include <pthread.h>
/*
#define CONN_FD_PREFIX "conn#"
#define CONN_FD_PLACEHOLDER "XXXXXXX"
+/* XXX: only supports UNIX sockets so far */
+static char *
+peer(int sockfd)
+{
+ uid_t uid;
+
+ struct passwd pw_entry;
+ struct passwd *result = NULL;
+ char buf[1024];
+
+#ifdef SO_PEERCRED
+ struct ucred cred;
+ socklen_t len = sizeof(cred);
+
+ if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &len)
+ || (len != sizeof(cred)))
+ return NULL;
+ uid = cred.uid;
+#else /* SO_PEERCRED */
+ errno = ENOSYS;
+ return NULL;
+#endif
+
+ memset(&pw_entry, 0, sizeof(pw_entry));
+ if (getpwuid_r(uid, &pw_entry, buf, sizeof(buf), &result)
+ || (! result))
+ return NULL;
+ return strdup(result->pw_name);
+} /* peer */
+
static int
connection_init(sdb_object_t *obj, va_list ap)
{
return -1;
}
+ conn->username = peer(conn->fd);
+ if (! conn->username) {
+ char buf[1024];
+ sdb_log(SDB_LOG_ERR, "frontend: Failed to retrieve peer for "
+ "connection conn#%i: %s", conn->fd,
+ sdb_strerror(errno, buf, sizeof(buf)));
+ return -1;
+ }
+ conn->ready = 0;
+
sdb_log(SDB_LOG_DEBUG, "frontend: Accepted connection on fd=%i",
conn->fd);
diff --git a/src/frontend/session.c b/src/frontend/session.c
index b0fc7803e2a0e23ab53a05cc6a1c694c4251b824..ab45cdd17c30cb154a7cf051cf940ba11e47e4b0 100644 (file)
--- a/src/frontend/session.c
+++ b/src/frontend/session.c
int
sdb_fe_session_start(sdb_conn_t *conn)
{
- const char *username;
+ char username[sdb_strbuf_len(conn->buf) + 1];
+ const char *tmp;
- if ((! conn) || (conn->username))
+ if ((! conn) || (conn->cmd != SDB_CONNECTION_STARTUP))
return -1;
- if (conn->cmd != SDB_CONNECTION_STARTUP)
- return -1;
-
- username = sdb_strbuf_string(conn->buf);
- if ((! username) || (! conn->cmd_len) || (! *username)) {
+ tmp = sdb_strbuf_string(conn->buf);
+ if ((! tmp) || (! conn->cmd_len) || (! *tmp)) {
sdb_strbuf_sprintf(conn->errbuf, "Invalid empty username");
return -1;
}
+ strncpy(username, tmp, conn->cmd_len);
+ username[conn->cmd_len] = '\0';
- /* XXX: for now, simply accept all connections */
- conn->username = strndup(username, conn->cmd_len);
if (! conn->username) {
- sdb_strbuf_sprintf(conn->errbuf, "Authentication failed");
+ /* We couldn't determine the remote peer when setting up the
+ * connection; TODO: add support for password authentication */
+ sdb_strbuf_sprintf(conn->errbuf, "Password authentication "
+ "not supported");
return -1;
}
+ if (strcmp(conn->username, username)) {
+ sdb_strbuf_sprintf(conn->errbuf, "%s cannot act on behalf of %s",
+ conn->username, username);
+ return -1;
+ }
+
sdb_connection_send(conn, SDB_CONNECTION_OK, 0, NULL);
conn->ready = 1;
return 0;
diff --git a/src/include/utils/os.h b/src/include/utils/os.h
index 2e6c54776ede89ba35d2f70aacda889df89b7d75..07328dd11a2b0d9aaf96c82c0f920e1d88082070 100644 (file)
--- a/src/include/utils/os.h
+++ b/src/include/utils/os.h
int
sdb_remove_all(const char *pathname);
+/*
+ * sdb_get_current_user:
+ * Returns the name of the current user. The string is allocated dynamically
+ * and has to be freed by the caller.
+ *
+ * Returns:
+ * - the username on success
+ * - NULL else
+ */
+char *
+sdb_get_current_user(void);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
index b8501f472383cd454608c19aebcab8688e784c60..ba2b32d8d3553dad528bfda657d7f18f79b20234 100644 (file)
--- a/src/tools/sysdb/input.h
+++ b/src/tools/sysdb/input.h
typedef struct {
sdb_client_t *client;
- const char *user;
+ char *user;
sdb_strbuf_t *input;
size_t tokenizer_pos;
diff --git a/src/tools/sysdb/main.c b/src/tools/sysdb/main.c
index 6e10e8d9fd87d937a3d668566f9f4fccf7bbcd7d..357ef34827672d0033030eeefe8d85d059f98836 100644 (file)
--- a/src/tools/sysdb/main.c
+++ b/src/tools/sysdb/main.c
#include "utils/error.h"
#include "utils/llist.h"
#include "utils/strbuf.h"
+#include "utils/os.h"
#include <errno.h>
# define DEFAULT_SOCKET "unix:"LOCALSTATEDIR"/run/sysdbd.sock"
#endif
-static const char *
-get_current_user(void)
-{
- struct passwd pw_entry;
- struct passwd *result = NULL;
-
- uid_t uid;
-
- /* needs to be static because we return a pointer into this buffer
- * to the caller */
- static char buf[1024];
-
- int status;
-
- uid = geteuid();
-
- memset(&pw_entry, 0, sizeof(pw_entry));
- status = getpwuid_r(uid, &pw_entry, buf, sizeof(buf), &result);
-
- if (status || (! result)) {
- char errbuf[1024];
- sdb_log(SDB_LOG_ERR, "Failed to determine current username: %s",
- sdb_strerror(errno, errbuf, sizeof(errbuf)));
- return NULL;
- }
- return result->pw_name;
-} /* get_current_user */
-
static const char *
get_homedir(const char *username)
{
static void
exit_usage(char *name, int status)
{
+ char *user = sdb_get_current_user();
printf(
"Usage: %s <options>\n"
" -V display the version number and copyright\n"
"\nSysDB client "SDB_CLIENT_VERSION_STRING SDB_CLIENT_VERSION_EXTRA", "
-PACKAGE_URL"\n", basename(name), get_current_user());
+PACKAGE_URL"\n", basename(name), user);
+ free(user);
exit(status);
} /* exit_usage */
if (! host)
host = DEFAULT_SOCKET;
- if (! input.user) {
- input.user = get_current_user();
- if (! input.user)
- exit(1);
- }
+ if (! input.user)
+ input.user = sdb_get_current_user();
+ else
+ input.user = strdup(input.user);
+ if (! input.user)
+ exit(1);
input.client = sdb_client_create(host);
if (! input.client) {
sdb_log(SDB_LOG_ERR, "Failed to create client object");
+ free(input.user);
exit(1);
}
if (sdb_client_connect(input.client, input.user)) {
sdb_log(SDB_LOG_ERR, "Failed to connect to SysDBd");
sdb_client_destroy(input.client);
+ free(input.user);
exit(1);
}
int status = execute_commands(input.client, commands);
sdb_llist_destroy(commands);
sdb_client_destroy(input.client);
+ free(input.user);
if ((status != SDB_CONNECTION_OK) && (status != SDB_CONNECTION_DATA))
exit(1);
exit(0);
hist_file, sdb_strerror(errno, errbuf, sizeof(errbuf)));
}
}
+ free(input.user);
input.input = sdb_strbuf_create(2048);
sdb_input_init(&input);
diff --git a/src/utils/os.c b/src/utils/os.c
index 7858825e1c889ad040b028284b9c4725c29a8068..e3f1fe2d42bb61d072940949a7ddee345836d4f6 100644 (file)
--- a/src/utils/os.c
+++ b/src/utils/os.c
#endif /* HAVE_CONFIG_H */
#include "utils/os.h"
+#include "utils/error.h"
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
+#include <pwd.h>
/*
* public API
return remove(pathname);
} /* sdb_remove_all */
+char *
+sdb_get_current_user(void)
+{
+ struct passwd pw_entry;
+ struct passwd *result = NULL;
+
+ uid_t uid;
+
+ char buf[1024];
+ int status;
+
+ uid = geteuid();
+ memset(&pw_entry, 0, sizeof(pw_entry));
+ status = getpwuid_r(uid, &pw_entry, buf, sizeof(buf), &result);
+
+ if (status || (! result)) {
+ char errbuf[1024];
+ sdb_log(SDB_LOG_ERR, "Failed to determine current username: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ return NULL;
+ }
+ return strdup(result->pw_name);
+} /* sdb_get_current_user */
+
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
diff --git a/t/integration/query.sh b/t/integration/query.sh
index f8287b45a645adac6798dbb611b092279e070d4f..eb4ccd8814771f058f6a9a357f1b669f5803b5e5 100755 (executable)
--- a/t/integration/query.sh
+++ b/t/integration/query.sh
wait_for_sysdbd
sleep 3
+# Invalid user.
+output="$( run_sysdb_nouser -H "$SOCKET_FILE" \
+ -U $SYSDB_USER-invalid -c 'LIST hosts' 2>&1 )" && exit 1
+echo "$output" | grep -F 'Access denied'
+
# On parse errors, expect a non-zero exit code.
output="$( run_sysdb -H "$SOCKET_FILE" -c INVALID 2>&1 )" && exit 1
echo "$output" | grep "Failed to parse query 'INVALID'"
index 0cc1931770d15bb0b86a46c6a9f6ad23d3b479d1..f6898e4678a9359e7e3b78949e095f8d2f36e9fc 100644 (file)
SOCKET_FILE="$TESTDIR/sock"
PLUGIN_DIR="$TESTDIR"
+SYSDB_USER="$( id -un )"
+
function run_sysdb() {
- $MEMCHECK "$TESTDIR/sysdb" -U mockuser "$@"
+ $MEMCHECK "$TESTDIR/sysdb" -U $SYSDB_USER "$@"
+}
+
+function run_sysdb_nouser() {
+ $MEMCHECK "$TESTDIR/sysdb" "$@"
}
function run_sysdbd() {
index 77828e6a8c4220d482a1eaaf69c6ec03b142fca0..13ae221a0f509e6f8402c2c5c10e838f4df8b2ef 100644 (file)
#include "frontend/connection.h"
#include "frontend/connection-private.h"
#include "utils/proto.h"
+#include "utils/os.h"
#include "libsysdb_test.h"
#include "utils/strbuf.h"
+#include <assert.h>
#include <check.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
+static char username[1024];
+
/*
* private helper functions
*/
unlink(tmp_file);
+ conn->username = strdup(username);
+ assert(conn->username);
+
conn->cmd = SDB_CONNECTION_IDLE;
conn->cmd_len = 0;
return conn;
{
ssize_t check, expected;
- expected = 2 * sizeof(uint32_t) + strlen("fakeuser");
+ expected = 2 * sizeof(uint32_t) + strlen(username);
check = sdb_connection_send(conn, SDB_CONNECTION_STARTUP,
- (uint32_t)strlen("fakeuser"), "fakeuser");
+ (uint32_t)strlen(username), username);
fail_unless(check == expected,
- "sdb_connection_send(STARTUP, fakeuser) = %zi; expected: %zi",
- check, expected);
+ "sdb_connection_send(STARTUP, %s) = %zi; expected: %zi",
+ username, check, expected);
mock_conn_rewind(conn);
check = sdb_connection_read(conn);
fail_unless(sdb_strbuf_len(conn->errbuf) == 0,
"sdb_connection_read() left %zu bytes in the error "
- "buffer; expected: 0", sdb_strbuf_len(conn->errbuf));
+ "buffer (%s); expected: 0", sdb_strbuf_len(conn->errbuf),
+ sdb_strbuf_string(conn->errbuf));
mock_conn_truncate(conn);
} /* connection_startup */
{ UINT32_MAX, NULL, NULL },
{ SDB_CONNECTION_IDLE, "fakedata", "Authentication required" },
{ SDB_CONNECTION_PING, NULL, "Authentication required" },
- { SDB_CONNECTION_STARTUP, "fakeuser", NULL },
+ { SDB_CONNECTION_STARTUP, username, NULL },
{ SDB_CONNECTION_PING, NULL, NULL },
{ SDB_CONNECTION_IDLE, NULL, "Invalid command 0" },
{ SDB_CONNECTION_PING, "fakedata", NULL },
else
fail_unless(sdb_strbuf_len(conn->errbuf) == 0,
"sdb_connection_read() left %zu bytes in the error "
- "buffer; expected: 0", sdb_strbuf_len(conn->errbuf));
+ "buffer (%s); expected: 0", sdb_strbuf_len(conn->errbuf),
+ sdb_strbuf_string(conn->errbuf));
}
mock_conn_destroy(conn);
Suite *s = suite_create("frontend::connection");
TCase *tc;
+ char *tmp = sdb_get_current_user();
+ assert(tmp);
+ strcpy(username, tmp);
+ free(tmp);
+
tc = tcase_create("core");
tcase_add_test(tc, test_conn_accept);
tcase_add_test(tc, test_conn_setup);
index c28781ea051f815cd739fe3b4df23501904dbd00..82a1daf7b6986a4ae4746dcfd151947a6db39aa5 100644 (file)
#endif /* HAVE_CONFIG_H */
/* required for fopencookie support */
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include "utils/unixsock.h"
#include "libsysdb_test.h"