int read_mainconfig(int reload);
int free_mainconfig(void);
+void fr_suid_down(void);
+void fr_suid_up(void);
+void fr_suid_down_permanent(void);
/* listen.c */
void listen_free(rad_listen_t **head);
}
-#if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
-static void fr_suid_up(void)
-{
- uid_t ruid, euid, suid;
-
- if (getresuid(&ruid, &euid, &suid) < 0) {
- radlog(L_ERR, "Failed getting saved UID's");
- _exit(1);
- }
-
- if (setresuid(-1, suid, -1) < 0) {
- radlog(L_ERR, "Failed switching to privileged user");
- _exit(1);
- }
-
- if (geteuid() != suid) {
- radlog(L_ERR, "Switched to unknown UID");
- _exit(1);
- }
-}
-
-extern uid_t server_uid;
-extern int did_setuid;
-static void fr_suid_down(void)
-{
- uid_t ruid, euid, suid;
-
- if (!did_setuid) return;
-
- if (getresuid(&ruid, &euid, &suid) < 0) {
- radlog(L_ERR, "Failed getting saved UID's");
- _exit(1);
- }
-
- if (setresuid(server_uid, server_uid, server_uid) < 0) {
- radlog(L_ERR, "Failed to permanently switch UID to %u: %s",
- server_uid, strerror(errno));
- _exit(1);
- }
-
- if (geteuid() != server_uid) {
- radlog(L_ERR, "Switched to unknown UID");
- _exit(1);
- }
-
-
- if (getresuid(&ruid, &euid, &suid) < 0) {
- radlog(L_ERR, "Failed getting saved UID's: %s",
- strerror(errno));
- _exit(1);
- }
-}
-#else
-/*
- * Much less secure...
- */
-#define fr_suid_up()
-#define fr_suid_down()
-#endif
-
-
/*
* Externally-visibly functions.
*/
DEBUG("%s: #### Opening IP addresses and Ports ####",
mainconfig.name);
- fr_suid_up(); /* sockets may bind to privileged ports */
-
+ /*
+ * The server temporarily switches to an unprivileged
+ * user very early in the bootstrapping process.
+ * However, some sockets MAY require privileged access
+ * (bind to device, or to port < 1024, or to raw
+ * sockets). Those sockets need to call suid up/down
+ * themselves around the functions that need a privileged
+ * uid.
+ */
if (listen_init(cs, &head) < 0) {
_exit(1);
}
- fr_suid_down();
+ /*
+ * At this point, no one has any business *ever* going
+ * back to root uid.
+ */
+ fr_suid_down_permanent();
/*
* Add all of the sockets to the event loop.
*/
static int listen_bind(rad_listen_t *this)
{
+ int rcode;
struct sockaddr_storage salocal;
socklen_t salen;
listen_socket_t *sock = this->data;
if (sock->interface) {
struct ifreq ifreq;
strcpy(ifreq.ifr_name, sock->interface);
-
- if (setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,
- (char *)&ifreq, sizeof(ifreq)) < 0) {
+
+ fr_suid_up();
+ rcode = setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *)&ifreq, sizeof(ifreq));
+ fr_suid_down();
+ if (rcode < 0) {
close(this->fd);
- radlog(L_ERR, "Failed opening to interface %s: %s",
+ radlog(L_ERR, "Failed binding to interface %s: %s",
sock->interface, strerror(errno));
return -1;
} /* else it worked. */
#endif /* IPV6_V6ONLY */
}
#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
-
- if (bind(this->fd, (struct sockaddr *) &salocal, salen) < 0) {
+
+ /*
+ * May be binding to priviledged ports.
+ */
+ fr_suid_up();
+ rcode = bind(this->fd, (struct sockaddr *) &salocal, salen);
+ fr_suid_down();
+ if (rcode < 0) {
close(this->fd);
radlog(L_ERR, "Failed binding to socket: %s\n",
strerror(errno));
#ifndef __MINGW32__
int did_setuid = FALSE;
+#if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
+void fr_suid_up(void)
+{
+ uid_t ruid, euid, suid;
+
+ if (getresuid(&ruid, &euid, &suid) < 0) {
+ radlog(L_ERR, "Failed getting saved UID's");
+ _exit(1);
+ }
+
+ if (setresuid(-1, suid, -1) < 0) {
+ radlog(L_ERR, "Failed switching to privileged user");
+ _exit(1);
+ }
+
+ if (geteuid() != suid) {
+ radlog(L_ERR, "Switched to unknown UID");
+ _exit(1);
+ }
+}
+
+void fr_suid_down(void)
+{
+ if (!did_setuid) return;
+
+ if (setresuid(-1, server_uid, geteuid()) < 0) {
+ fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
+ progname, uid_name, strerror(errno));
+ _exit(1);
+ }
+
+ if (geteuid() != server_uid) {
+ fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n",
+ progname);
+ _exit(1);
+ }
+}
+
+void fr_suid_down_permanent(void)
+{
+ uid_t ruid, euid, suid;
+
+ if (!did_setuid) return;
+
+ if (getresuid(&ruid, &euid, &suid) < 0) {
+ radlog(L_ERR, "Failed getting saved uid's");
+ _exit(1);
+ }
+
+ if (setresuid(server_uid, server_uid, server_uid) < 0) {
+ radlog(L_ERR, "Failed in permanent switch to uid %s: %s",
+ uid_name, strerror(errno));
+ _exit(1);
+ }
+
+ if (geteuid() != server_uid) {
+ radlog(L_ERR, "Switched to unknown uid");
+ _exit(1);
+ }
+
+
+ if (getresuid(&ruid, &euid, &suid) < 0) {
+ radlog(L_ERR, "Failed getting saved uid's: %s",
+ strerror(errno));
+ _exit(1);
+ }
+}
+#else
+/*
+ * Much less secure...
+ */
+void fr_suid_up(void)
+{
+}
+void fr_suid_down(void)
+{
+ if (!uid_name) return;
+
+ if (setuid(server_uid) < 0) {
+ fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
+ progname, uid_name, strerror(errno));
+ _exit(1);
+ }
+}
+void fr_suid_down_permanent(void)
+{
+}
+#endif
+
/*
* Do chroot, if requested.
*
#ifdef HAVE_PWD_H
if (uid_name) {
+ fr_suid_down();
-#ifndef HAVE_SETRESUID
-/*
- * Fake out setresuid with something that's close.
- */
-#define setresuid(_a, _b, _c) setuid(_b)
-#endif
-
- if (setresuid(-1, server_uid, geteuid()) < 0) {
- fprintf(stderr, "%s: Failed switching uid: %s\n",
- progname, strerror(errno));
- return 0;
- }
+ /*
+ * Now core dumps are disabled on most secure systems.
+ */
- if (geteuid() != server_uid) {
- fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n",
- progname);
- return 0;
- }
+ did_setuid = TRUE;
}
-
- /*
- * Now core dumps are disabled on most secure systems.
- */
- did_setuid = TRUE;
#endif
/*