char const *uid_name;
char const *gid_name;
char const *mode_name;
+ bool peercred;
char user[256];
/*
{ "uid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, uid_name), NULL },
{ "gid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, gid_name), NULL },
{ "mode", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, mode_name), NULL },
-
+ { "peercred", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_command_socket_t, peercred), "yes" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
}
#endif /* HAVE_GETPEEREID */
-#if defined(__linux__) && (defined(HAVE_GETPEEREID) || defined(SO_PEERCRED))
-static int fr_server_domain_socket(char const *path, uid_t uid, gid_t gid)
+/** 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(char const *path, uid_t UNUSED uid, UNUSED gid_t gid)
+static int fr_server_domain_socket_peercred(char const *path, uid_t UNUSED uid, UNUSED gid_t gid)
#endif
{
int sockfd;
struct stat buf;
if (!path) {
- ERROR("No path provided, was NULL");
+ fr_strerror_printf("No path provided, was NULL");
return -1;
}
len = strlen(path);
if (len >= sizeof(salocal.sun_path)) {
- ERROR("Path too long in socket filename");
+ fr_strerror_printf("Path too long in socket filename");
return -1;
}
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- ERROR("Failed creating socket: %s",
- fr_syserror(errno));
+ fr_strerror_printf("Failed creating socket: %s", fr_syserror(errno));
return -1;
}
*/
if (stat(path, &buf) < 0) {
if (errno != ENOENT) {
- ERROR("Failed to stat %s: %s",
- path, fr_syserror(errno));
+ fr_strerror_printf("Failed to stat %s: %s", path, fr_syserror(errno));
close(sockfd);
return -1;
}
&& !S_ISSOCK(buf.st_mode)
#endif
) {
- ERROR("Cannot turn %s into socket", path);
+ fr_strerror_printf("Cannot turn %s into socket", path);
close(sockfd);
return -1;
}
* Refuse to open sockets not owned by us.
*/
if (buf.st_uid != geteuid()) {
- ERROR("We do not own %s", path);
+ fr_strerror_printf("We do not own %s", path);
close(sockfd);
return -1;
}
if (unlink(path) < 0) {
- ERROR("Failed to delete %s: %s",
+ fr_strerror_printf("Failed to delete %s: %s",
path, fr_syserror(errno));
close(sockfd);
return -1;
}
if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
- ERROR("Failed binding to %s: %s",
- path, fr_syserror(errno));
+ fr_strerror_printf("Failed binding to %s: %s", path, fr_syserror(errno));
close(sockfd);
return -1;
}
* doesn't seem to permit fchmod on domain sockets.
*/
if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
- ERROR("Failed setting permissions on %s: %s",
- path, fr_syserror(errno));
+ fr_strerror_printf("Failed setting permissions on %s: %s", path, fr_syserror(errno));
close(sockfd);
return -1;
}
if (listen(sockfd, 8) < 0) {
- ERROR("Failed listening to %s: %s",
- path, fr_syserror(errno));
+ fr_strerror_printf("Failed listening to %s: %s", path, fr_syserror(errno));
close(sockfd);
return -1;
}
int flags;
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
- ERROR("Failure getting socket flags: %s",
- fr_syserror(errno));
+ 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) {
- ERROR("Failure setting socket flags: %s",
- fr_syserror(errno));
+ fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
close(sockfd);
return -1;
}
* Changing socket permissions only works on linux.
* BSDs ignore socket permissions.
*/
-#if defined(__linux__) && (defined(HAVE_GETPEEREID) || defined(SO_PEERCRED))
+#ifdef __linux__
/*
* Don't chown it from (possibly) non-root to root.
* Do chown it from (possibly) root to non-root.
* Don't do chown if it's already owned by us.
*/
if (fstat(sockfd, &buf) < 0) {
- ERROR("Failed reading %s: %s", path, fr_syserror(errno));
+ 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) {
- ERROR("Failed setting ownership of %s to (%d, %d): %s",
+ fr_strerror_printf("Failed setting ownership of %s to (%d, %d): %s",
path, uid, gid, fr_syserror(errno));
rad_suid_down();
close(sockfd);
fp = fopen(output_file, "w");
if (!fp) {
- ERROR("Failed to send injected file to %s: %s",
- output_file, fr_syserror(errno));
+ ERROR("Failed to send injected file to %s: %s", output_file, fr_syserror(errno));
return 0;
}
sock = this->data;
- if (cf_section_parse(cs, sock, command_config) < 0) {
+ if (cf_section_parse(cs, sock, command_config) < 0) return -1;
+
+ /*
+ * Can't get uid or gid of connecting user, so can't do
+ * peercred authentication.
+ */
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
+ if (sock->peercred && (sock->uid_name || sock->gid_name)) {
+ ERROR("System does not support uid or gid authentication for sockets");
return -1;
}
+#endif
sock->magic = COMMAND_SOCKET_MAGIC;
sock->copy = NULL;
if (sock->path) sock->copy = talloc_typed_strdup(sock, sock->path);
-#if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
if (sock->uid_name) {
struct passwd *pwd;
sock->gid = -1;
}
-#else /* can't get uid or gid of connecting user */
-
- if (sock->uid_name || sock->gid_name) {
- ERROR("System does not support uid or gid authentication for sockets");
- return -1;
- }
-
-#endif
-
if (!sock->mode_name) {
sock->co.mode = FR_READ;
} else {
}
}
- /*
- * FIXME: check for absolute pathnames?
- * check for uid/gid on the other end...
- */
-
- this->fd = fr_server_domain_socket(sock->path, sock->uid, sock->gid);
+ this->fd = fr_server_domain_socket_peercred(sock->path, sock->uid, sock->gid);
if (this->fd < 0) {
+ ERROR("Failed creating control socket \"%s\": %s", sock->path, fr_strerror());
return -1;
}
-
return 0;
}