* @copyright 2018 The FreeRADIUS server project.
* @copyright 2018 Alan DeKok (aland@deployingradius.com)
*/
+#include <freeradius-devel/server/main_config.h>
+
#include <freeradius-devel/io/application.h>
#include <freeradius-devel/io/listen.h>
#include <freeradius-devel/io/schedule.h>
#include <freeradius-devel/util/perm.h>
#include <freeradius-devel/util/trie.h>
#include <freeradius-devel/util/file.h>
+
#include <netdb.h>
#include "proto_control.h"
+#include <freeradius-devel/bio/fd.h>
+
#ifdef HAVE_SYS_STAT_H
#endif
int sockfd;
+ fr_bio_t *fd_bio;
+
fr_stats_t stats; //!< statistics for this socket
fr_io_address_t *connection; //!< for connected sockets.
bool recv_buff_is_set; //!< Whether we were provided with a receive
//!< buffer value.
- bool peercred; //!< whether we use peercred or not
+ char const *peer_uid_name; //!< name of UID to require
+ char const *peer_gid_name; //!< name of GID to require
+ uid_t peer_uid; //!< UID value
+ gid_t peer_gid; //!< GID value
+
} proto_control_unix_t;
+static const conf_parser_t peercred_config[] = {
+ { FR_CONF_OFFSET("uid", proto_control_unix_t, peer_uid_name) },
+ { FR_CONF_OFFSET("gid", proto_control_unix_t, peer_gid_name) },
+
+ CONF_PARSER_TERMINATOR
+};
+
static const conf_parser_t unix_listen_config[] = {
{ FR_CONF_OFFSET_FLAGS("filename", CONF_FLAG_REQUIRED, proto_control_unix_t, filename),
.dflt = "${run_dir}/radiusd.sock}" },
{ FR_CONF_OFFSET("uid", proto_control_unix_t, uid_name) },
{ FR_CONF_OFFSET("gid", proto_control_unix_t, gid_name) },
{ FR_CONF_OFFSET("mode", proto_control_unix_t, mode_name) },
- { FR_CONF_OFFSET("peercred", proto_control_unix_t, peercred), .dflt = "yes" },
{ FR_CONF_OFFSET_IS_SET("recv_buff", FR_TYPE_UINT32, 0, proto_control_unix_t, recv_buff) },
{ FR_CONF_OFFSET("max_packet_size", proto_control_unix_t, max_packet_size), .dflt = "4096" } ,
+ { FR_CONF_POINTER("peercred", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) peercred_config },
+
CONF_PARSER_TERMINATOR
};
*trie = NULL;
}
-/** Initialise a socket for use with peercred authentication
- *
- * This function initialises a socket and path in a way suitable for use with
- * peercred.
- *
- * @param path to socket.
- * @param uid that should own the socket (linux only).
- * @param gid that should own the socket (linux only).
- * @return 0 on success -1 on failure.
- */
-#ifdef __linux__
-static int fr_server_domain_socket_peercred(char const *path, uid_t uid, gid_t gid)
-#else
-static int fr_server_domain_socket_peercred(char const *path, uid_t UNUSED uid, UNUSED gid_t gid)
-#endif
-{
- int sockfd;
- int dirfd;
- char const *r;
- size_t len;
- socklen_t socklen;
- struct sockaddr_un salocal;
- struct stat buf;
-
- if (!path) {
- fr_strerror_const("No path provided, was NULL");
- return -1;
- }
-
- len = strlen(path);
- if (len >= sizeof(salocal.sun_path)) {
- fr_strerror_const("Path too long in socket filename");
- return -1;
- }
-
- if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- fr_strerror_printf("Failed creating socket: %s", fr_syserror(errno));
- return -1;
- }
-
- memset(&salocal, 0, sizeof(salocal));
- salocal.sun_family = AF_UNIX;
- memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
-
- socklen = SUN_LEN(&salocal);
-
- /*
- * Find and open the directory containing path so we can use the "at"
- * functions to avoid time of check/time of use insecurities.
- */
- if (fr_dirfd(&dirfd, &r, path) < 0) {
- close(sockfd);
- fr_strerror_printf("Failed to open directory containing %s", path);
- return -1;
- }
-
- /*
- * Check the path.
- */
- if (fstatat(dirfd, r, &buf, 0) < 0) {
- if (errno != ENOENT) {
- fr_strerror_printf("Failed to stat %s: %s", path, fr_syserror(errno));
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- /*
- * FIXME: Check the enclosing directory?
- */
- } else { /* it exists */
- int client_fd;
-
- if (!S_ISREG(buf.st_mode)
-#ifdef S_ISSOCK
- && !S_ISSOCK(buf.st_mode)
-#endif
- ) {
- fr_strerror_printf("Cannot turn %s into socket", path);
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- /*
- * Refuse to open sockets not owned by us.
- */
- if (buf.st_uid != geteuid()) {
- fr_strerror_printf("We do not own %s", path);
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- /*
- * Check if a server is already listening on the
- * socket?
- */
- client_fd = fr_socket_client_unix(path, false);
- if (client_fd >= 0) {
- fr_strerror_printf("Control socket '%s' is already in use", path);
- close(client_fd);
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- if (unlinkat(dirfd, r, 0) < 0) {
- fr_strerror_printf("Failed to delete %s: %s", path, fr_syserror(errno));
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
- }
-
- if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
- fr_strerror_printf("Failed binding to %s: %s", path, fr_syserror(errno));
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- /*
- * FIXME: There's a race condition here. But Linux
- * doesn't seem to permit fchmod on domain sockets.
- */
- if (fchmodat(dirfd, r, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0) < 0) {
- fr_strerror_printf("Failed setting permissions on %s: %s", path, fr_syserror(errno));
- close(sockfd);
- if (dirfd != AT_FDCWD) close(dirfd);
- return -1;
- }
-
- if (dirfd != AT_FDCWD) close(dirfd);
-
- if (listen(sockfd, 8) < 0) {
- fr_strerror_printf("Failed listening to %s: %s", path, fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
-#ifdef O_NONBLOCK
- {
- int flags;
-
- if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
- fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
- flags |= O_NONBLOCK;
- if( fcntl(sockfd, F_SETFL, flags) < 0) {
- fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
- close(sockfd);
- return -1;
- }
- }
-#endif
-
- /*
- * Changing socket permissions only works on linux.
- * BSDs ignore socket permissions.
- */
-#ifdef __linux__
- /*
- * Don't chown it from (possibly) non-root to root.
- * Do chown it from (possibly) root to non-root.
- */
- if ((uid != (uid_t) -1) || (gid != (gid_t) -1)) {
- /*
- * Don't do chown if it's already owned by us.
- */
- if (fstat(sockfd, &buf) < 0) {
- fr_strerror_printf("Failed reading %s: %s", path, fr_syserror(errno));
- close(sockfd);
- return -1;
- }
-
- if ((buf.st_uid != uid) || (buf.st_gid != gid)) {
- rad_suid_up();
- if (fchown(sockfd, uid, gid) < 0) {
- fr_strerror_printf("Failed setting ownership of %s to (%d, %d): %s",
- path, uid, gid, fr_syserror(errno));
- rad_suid_down();
- close(sockfd);
- return -1;
- }
- rad_suid_down();
- }
- }
-#endif
-
- return sockfd;
-}
-
-#if !defined(HAVE_OPENAT) || !defined(HAVE_MKDIRAT) || !defined(HAVE_UNLINKAT)
-static int fr_server_domain_socket_perm(UNUSED char const *path, UNUSED uid_t uid, UNUSED gid_t gid)
-{
- fr_strerror_printf("Unable to initialise control socket. Set peercred = yes or update to "
- "POSIX-2008 compliant libc");
- return -1;
-}
-#else
-/** Alternative function for creating Unix domain sockets and enforcing permissions
- *
- * Unlike fr_server_unix_socket which is intended to be used with peercred auth
- * this function relies on the file system to enforce access.
- *
- * The way it does this depends on the operating system. On Linux systems permissions
- * can be set on the socket directly and the system will enforce them.
- *
- * On most other systems fchown and fchmod fail when called with socket descriptors,
- * and although permissions can be changed in other ways, they're not enforced.
- *
- * For these systems we use the permissions on the parent directory to enforce
- * permissions on the socket. It's not safe to modify these permissions ourselves
- * due to TOCTOU attacks, so if they don't match what we require, we error out and
- * get the user to change them (which arguably isn't any safer, but releases us of
- * the responsibility).
- *
- * @note must be called without effective root permissions (fr_suid_down).
- *
- * @param[in] path where domain socket should be created.
- * @param[in] uid Owner of the socket.
- * @param[in] gid Group of the socket.
- * @return a file descriptor for the bound socket on success, -1 on failure.
- */
-static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid)
-{
- int dir_fd = -1, sock_fd = -1, parent_fd = -1;
- char const *name;
- char *buff = NULL, *dir = NULL, *p;
-
- uid_t euid;
- gid_t egid;
-
- mode_t perm = 0;
- struct stat st;
-
-
- size_t len;
-
- socklen_t socklen;
- struct sockaddr_un salocal;
-
- fr_assert(path);
-
- euid = geteuid();
- egid = getegid();
-
- /*
- * Determine the correct permissions for the socket, or its
- * containing directory.
- */
- perm |= S_IREAD | S_IWRITE | S_IEXEC;
- if (gid != (gid_t) -1) perm |= S_IRGRP | S_IWGRP | S_IXGRP;
-
- buff = talloc_strdup(NULL, path);
- if (!buff) return -1;
-
- /*
- * Some implementations modify it in place others use internal
- * storage *sigh*. dirname also formats the path else we wouldn't
- * be using it.
- */
- dir = dirname(buff);
- if (dir != buff) {
- dir = talloc_strdup(NULL, dir);
- if (!dir) return -1;
- talloc_free(buff);
- }
-
- p = strrchr(dir, FR_DIR_SEP);
- if (!p) {
- fr_strerror_const("Failed determining parent directory");
- error:
- talloc_free(dir);
- if (sock_fd >= 0) close(sock_fd);
- if (dir_fd >= 0) close(dir_fd);
- if (parent_fd >= 0) close(parent_fd);
- return -1;
- }
-
- *p = '\0';
-
- /*
- * Ensure the parent of the control socket directory exists,
- * and the euid we're running under has access to it.
- */
- parent_fd = open(dir, O_DIRECTORY);
- if (parent_fd < 0) {
- struct passwd *user;
- struct group *group;
-
- if (fr_perm_getpwuid(NULL, &user, euid) < 0) goto error;
- if (fr_perm_getgrgid(NULL, &group, egid) < 0) {
- talloc_free(user);
- goto error;
- }
- fr_strerror_printf("Can't open directory \"%s\": %s. Must be created manually, or modified, "
- "with permissions that allow writing by user %s or group %s", dir,
- user->pw_name, group->gr_name, fr_syserror(errno));
- talloc_free(user);
- talloc_free(group);
- goto error;
- }
-
- *p = FR_DIR_SEP;
-
- dir_fd = openat(parent_fd, p + 1, O_NOFOLLOW | O_DIRECTORY);
- if (dir_fd < 0) {
- int ret = 0;
-
- if (errno != ENOENT) {
- fr_strerror_printf("Failed opening control socket directory: %s", fr_syserror(errno));
- goto error;
- }
-
- /*
- * This fails if the radius user can't write
- * to the parent directory.
- */
- if (mkdirat(parent_fd, p + 1, 0700) < 0) {
- fr_strerror_printf("Failed creating control socket directory: %s", fr_syserror(errno));
- goto error;
- }
-
- dir_fd = openat(parent_fd, p + 1, O_NOFOLLOW | O_DIRECTORY);
- if (dir_fd < 0) {
- fr_strerror_printf("Failed opening the control socket directory we created: %s",
- fr_syserror(errno));
- goto error;
- }
- if (fchmod(dir_fd, perm) < 0) {
- fr_strerror_printf("Failed setting permissions on control socket directory: %s",
- fr_syserror(errno));
- goto error;
- }
-
- rad_suid_up();
- if ((uid != (uid_t)-1) || (gid != (gid_t)-1)) ret = fchown(dir_fd, uid, gid);
- rad_suid_down();
- if (ret < 0) {
- fr_strerror_printf("Failed changing ownership of control socket directory: %s",
- fr_syserror(errno));
- goto error;
- }
- /*
- * Control socket dir already exists, but we still need to
- * check the permissions are what we expect.
- */
- } else {
- int ret;
- int client_fd;
-
- ret = fstat(dir_fd, &st);
- if (ret < 0) {
- fr_strerror_printf("Failed checking permissions of control socket directory: %s",
- fr_syserror(errno));
- goto error;
- }
-
- if ((uid != (uid_t)-1) && (st.st_uid != uid)) {
- struct passwd *need_user, *have_user;
-
- if (fr_perm_getpwuid(NULL, &need_user, uid) < 0) goto error;
- if (fr_perm_getpwuid(NULL, &have_user, st.st_uid) < 0) {
- talloc_free(need_user);
- goto error;
- }
- fr_strerror_printf("Control socket directory must be owned by user %s, "
- "currently owned by %s", need_user->pw_name, have_user->pw_name);
- talloc_free(need_user);
- talloc_free(have_user);
- goto error;
- }
-
- if ((gid != (gid_t)-1) && (st.st_gid != gid)) {
- struct group *need_group, *have_group;
-
- if (fr_perm_getgrgid(NULL, &need_group, gid) < 0) goto error;
- if (fr_perm_getgrgid(NULL, &have_group, st.st_gid) < 0) {
- talloc_free(need_group);
- goto error;
- }
- fr_strerror_printf("Control socket directory \"%s\" must be owned by group %s, "
- "currently owned by %s", dir, need_group->gr_name, have_group->gr_name);
- talloc_free(need_group);
- talloc_free(have_group);
- goto error;
- }
-
- if ((perm & 0x0c) != (st.st_mode & 0x0c)) {
- char str_need[10], oct_need[5];
- char str_have[10], oct_have[5];
-
- fr_perm_mode_to_str(str_need, perm);
- fr_perm_mode_to_oct(oct_need, perm);
- fr_perm_mode_to_str(str_have, st.st_mode);
- fr_perm_mode_to_oct(oct_have, st.st_mode);
- fr_strerror_printf("Control socket directory must have permissions %s (%s), current "
- "permissions are %s (%s)", str_need, oct_need, str_have, oct_have);
- goto error;
- }
-
- /*
- * Check if a server is already listening on the
- * socket?
- */
- client_fd = fr_socket_client_unix(path, false);
- if (client_fd >= 0) {
- fr_strerror_printf("Control socket '%s' is already in use", path);
- close(client_fd);
- goto error;
- }
- }
-
- name = strrchr(path, FR_DIR_SEP);
- if (!name) {
- fr_strerror_const("Can't determine socket name");
- goto error;
- }
- name++;
-
- /*
- * We've checked the containing directory has the permissions
- * we expect, and as we have the FD, and aren't following
- * symlinks no one can trick us into changing or creating a
- * file elsewhere.
- *
- * It's possible an attacker may still be able to create hard
- * links, for the socket file. But they would need write
- * access to the directory we just created or verified, so
- * this attack vector is unlikely.
- */
- if ((uid != (uid_t)-1) && (rad_seuid(uid) < 0)) goto error;
- if ((gid != (gid_t)-1) && (rad_segid(gid) < 0)) {
- rad_seuid(euid);
- goto error;
- }
-
- /*
- * The original code, did openat, used fstat to figure out
- * what type the file was and then used unlinkat to unlink
- * it. Except on OSX (at least) openat refuses to open
- * socket files. So we now rely on the fact that unlinkat
- * has sane and consistent behaviour, and will not unlink
- * directories. unlinkat should also fail if the socket user
- * hasn't got permission to modify the socket.
- */
- if ((unlinkat(dir_fd, name, 0) < 0) && (errno != ENOENT)) {
- fr_strerror_printf("Failed removing stale socket: %s", fr_syserror(errno));
- sock_error:
- if (uid != (uid_t)-1) rad_seuid(euid);
- if (gid != (gid_t)-1) rad_segid(egid);
-
- goto error;
- }
-
- /*
- * At this point we should have established a secure directory
- * to house our socket, and cleared out any stale sockets.
- */
- sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock_fd < 0) {
- fr_strerror_printf("Failed creating socket: %s", fr_syserror(errno));
- goto sock_error;
- }
-
-#ifdef HAVE_BINDAT
- len = strlen(name);
-#else
- len = strlen(path);
-#endif
- if (len >= sizeof(salocal.sun_path)) {
- fr_strerror_const("Path too long in socket filename");
- goto error;
- }
-
- memset(&salocal, 0, sizeof(salocal));
- salocal.sun_family = AF_UNIX;
-
-#ifdef HAVE_BINDAT
- memcpy(salocal.sun_path, name, len + 1); /* SUN_LEN does strlen */
-#else
- memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
-#endif
- socklen = SUN_LEN(&salocal);
-
- /*
- * Direct socket permissions are only useful on Linux which
- * actually enforces them. BSDs don't. They also need to be
- * set before binding the socket to a file.
- */
-#ifdef __linux__
- if (fchmod(sock_fd, perm) < 0) {
- char str_need[10], oct_need[5];
-
- fr_perm_mode_to_str(str_need, perm);
- fr_perm_mode_to_oct(oct_need, perm);
- fr_strerror_printf("Failed changing socket permissions to %s (%s)", str_need, oct_need);
-
- goto sock_error;
- }
-
- if (fchown(sock_fd, uid, gid) < 0) {
- struct passwd *user;
- struct group *group;
-
- if (fr_perm_getpwuid(NULL, &user, uid) < 0) goto sock_error;
- if (fr_perm_getgrgid(NULL, &group, gid) < 0) {
- talloc_free(user);
- goto sock_error;
- }
-
- fr_strerror_printf("Failed changing ownership of socket to %s:%s", user->pw_name, group->gr_name);
- talloc_free(user);
- talloc_free(group);
- goto sock_error;
- }
-#endif
- /*
- * The correct function to use here is bindat(), but only
- * quite recent versions of FreeBSD actually have it, and
- * it's definitely not POSIX.
- */
-#ifdef HAVE_BINDAT
- if (bindat(dir_fd, sock_fd, (struct sockaddr *)&salocal, socklen) < 0) {
-#else
- if (bind(sock_fd, (struct sockaddr *)&salocal, socklen) < 0) {
-#endif
- fr_strerror_printf("Failed binding socket: %s", fr_syserror(errno));
- goto sock_error;
- }
-
- if (listen(sock_fd, 8) < 0) {
- fr_strerror_printf("Failed listening on socket: %s", fr_syserror(errno));
- goto sock_error;
- }
-
-#ifdef O_NONBLOCK
- {
- int flags;
-
- flags = fcntl(sock_fd, F_GETFL, NULL);
- if (flags < 0) {
- fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno));
- goto sock_error;
- }
-
- flags |= O_NONBLOCK;
- if (fcntl(sock_fd, F_SETFL, flags) < 0) {
- fr_strerror_printf("Failed setting nonblocking socket flag: %s", fr_syserror(errno));
- goto sock_error;
- }
- }
-#endif
-
- if (uid != (uid_t)-1) rad_seuid(euid);
- if (gid != (gid_t)-1) rad_segid(egid);
-
- if (dir_fd >= 0) close(dir_fd);
- if (parent_fd >= 0) close(parent_fd);
-
- return sock_fd;
-}
-#endif
-
/** Open a UNIX listener for control sockets
*
*/
proto_control_unix_t const *inst = talloc_get_type_abort_const(li->app_io_instance, proto_control_unix_t);
proto_control_unix_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_control_unix_thread_t);
- int sockfd ;
CONF_ITEM *ci;
CONF_SECTION *server_cs;
- fr_assert(!thread->connection);
-
- if (inst->peercred) {
- sockfd = fr_server_domain_socket_peercred(inst->filename, inst->uid, inst->gid);
- } else {
- uid_t uid = inst->uid;
- gid_t gid = inst->gid;
+ fr_bio_fd_info_t const *info;
+ fr_bio_fd_config_t cfg;
- if (uid == ((uid_t)-1)) uid = 0;
- if (gid == ((gid_t)-1)) gid = 0;
+ fr_assert(!thread->connection);
- sockfd = fr_server_domain_socket_perm(inst->filename, uid, gid);
- }
- if (sockfd < 0) {
- PERROR("Failed opening UNIX path %s", inst->filename);
+ cfg = (fr_bio_fd_config_t) {
+ .type = FR_BIO_FD_ACCEPT,
+ .socket_type = SOCK_STREAM,
+ .path = inst->filename,
+ .uid = inst->uid,
+ .gid = inst->gid,
+ .perm = 0x700,
+ .async = true,
+ };
+
+ thread->fd_bio = fr_bio_fd_alloc(thread, NULL, &cfg, 0);
+ if (!thread->fd_bio) {
+ PERROR("Failed allocating UNIX path %s", inst->filename);
return -1;
}
- li->fd = thread->sockfd = sockfd;
+ info = fr_bio_fd_info(thread->fd_bio);
+ fr_assert(info != NULL);
+
+ li->fd = thread->sockfd = info->socket.fd;
ci = cf_parent(inst->cs); /* listen { ... } */
fr_assert(ci != NULL);
return 0;
}
-
#if !defined(HAVE_GETPEEREID) && defined(SO_PEERCRED)
static int getpeereid(int s, uid_t *euid, gid_t *egid)
{
cookie_io_functions_t io;
- thread->name = NULL;
-
#ifdef HAVE_GETPEEREID
/*
* Perform user authentication.
+ *
+ * @todo - this really belongs in the accept() callback,
+ * so that we don't create an entirely new listener and
+ * then close it.
*/
- if (inst->peercred) {
+ if (inst->peer_uid || inst->peer_gid) {
uid_t uid;
gid_t gid;
if (getpeereid(fd, &uid, &gid) < 0) {
ERROR("Failed getting peer credentials for %s: %s",
- inst->filename, fr_syserror(errno));
+ inst->filename, fr_syserror(errno));
return -1;
}
* we might as well let them do anything.
*/
if (uid != 0) do {
- /*
- * Allow entry if UID or GID matches.
- */
- if (inst->uid_name && (inst->uid == uid)) break;
- if (inst->gid_name && (inst->gid == gid)) break;
-
- if (inst->uid_name && (inst->uid != uid)) {
- ERROR("Unauthorized connection to %s from uid %ld",
- inst->filename, (long int) uid);
- return -1;
- }
-
- if (inst->gid_name && (inst->gid != gid)) {
- ERROR("Unauthorized connection to %s from gid %ld",
- inst->filename, (long int) gid);
- return -1;
- }
-
- } while (0);
+ /*
+ * Allow entry if UID or GID matches.
+ */
+ if (inst->peer_uid_name && (inst->peer_uid == uid)) break;
+ if (inst->peer_gid_name && (inst->peer_gid == gid)) break;
+
+ if (inst->peer_uid_name && (inst->peer_uid != uid)) {
+ ERROR("Unauthorized connection to %s from uid %ld",
+ inst->filename, (long int) uid);
+ return -1;
+ }
+
+ if (inst->peer_gid_name && (inst->peer_gid != gid)) {
+ ERROR("Unauthorized connection to %s from gid %ld",
+ inst->filename, (long int) gid);
+ return -1;
+ }
+
+ } while (0);
thread->name = talloc_typed_asprintf(thread, "proto unix filename %s from peer UID %u GID %u",
inst->filename,
(unsigned int) uid, (unsigned int) gid);
- }
+ } else
#endif
- if (!thread->name) thread->name = talloc_typed_asprintf(thread, "proto unix filename %s", inst->filename);
+
+ thread->name = talloc_typed_asprintf(thread, "proto unix filename %s", inst->filename);
thread->sockfd = fd;
thread->read = mod_read_init;
FR_INTEGER_BOUND_CHECK("recv_buff", inst->recv_buff, <=, INT_MAX);
}
-#ifndef HAVE_GETPEEREID
- if (inst->peercred && (inst->uid_name || inst->gid_name)) {
- ERROR("System does not support uid or gid authentication for sockets");
- return -1;
- }
-#endif
-
if (inst->uid_name) {
struct passwd *pwd;
}
inst->uid = pwd->pw_uid;
talloc_free(pwd);
+
+ } else if (main_config->server_uid) {
+ inst->uid = main_config->server_uid;
+
} else {
- inst->uid = -1;
+ inst->uid = getuid();
+ }
+ if (!inst->uid) {
+ ERROR("Cannot open domain sockets as UID root. uid must be set");
+ return -1;
}
if (inst->gid_name) {
PERROR("Failed getting gid for %s", inst->gid_name);
return -1;
}
+
+ } else if (main_config->server_gid) {
+ inst->gid = main_config->server_gid;
+
} else {
- inst->gid = -1;
+ inst->gid = getgid();
+ }
+ if (!inst->gid) {
+ ERROR("Cannot open domain sockets as GID root. gid must be set");
+ return -1;
+ }
+
+ /*
+ * And for peer creds
+ */
+ if (inst->peer_uid_name) {
+ struct passwd *pwd;
+
+ if (fr_perm_getpwnam(conf, &pwd, inst->peer_uid_name) < 0) {
+ PERROR("Failed getting peer uid for %s", inst->peer_uid_name);
+ return -1;
+ }
+ inst->peer_uid = pwd->pw_uid;
+ talloc_free(pwd);
+ }
+
+ if (inst->peer_gid_name) {
+ if (fr_perm_gid_from_str(conf, &inst->peer_gid, inst->peer_gid_name) < 0) {
+ PERROR("Failed getting peer gid for %s", inst->peer_gid_name);
+ return -1;
+ }
}
if (!inst->mode_name) {