- merge auth.c into priv.c
- add function sig_pass_to_chld sig_got_chld from syslogd/OpenBSD. - change function name *_auth to priv_*
This commit is contained in:
parent
49c6605e29
commit
ffefc2f17d
6 changed files with 255 additions and 242 deletions
|
|
@ -32,7 +32,6 @@ exampledir = $(datadir)/examples/sj3
|
|||
sj3serv_SOURCES = \
|
||||
sj_string.h \
|
||||
sj3serv.h \
|
||||
auth.c \
|
||||
comuni.c \
|
||||
error.c \
|
||||
execute.c \
|
||||
|
|
|
|||
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <pwd.h>
|
||||
#include "sj3serv.h"
|
||||
|
||||
enum cmd_types {
|
||||
AUTH_GETUGID,
|
||||
AUTH_EXIT
|
||||
};
|
||||
|
||||
static int auth_fd = -1;
|
||||
|
||||
static int may_read(int, void *, size_t);
|
||||
static void must_read(int, void *, size_t);
|
||||
static void must_write(int, void *, size_t);
|
||||
|
||||
|
||||
int
|
||||
exec_auth()
|
||||
{
|
||||
int socks[2];
|
||||
int i;
|
||||
pid_t child_pid = -1;
|
||||
struct sigaction sa;
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
|
||||
fprintf(stderr, "socketpair() failed");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
fprintf(stderr, "fork() failed\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if (!child_pid) {
|
||||
auth_fd = socks[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
strlcpy(chroot_dir, "/", sizeof(chroot_dir));
|
||||
set_priv("[auth]");
|
||||
|
||||
while (1) {
|
||||
int cmd;
|
||||
size_t username_len;
|
||||
char username[BUFSIZ];
|
||||
int ret;
|
||||
struct passwd *pw;
|
||||
|
||||
if (may_read(socks[0], &cmd, sizeof(int)))
|
||||
break;
|
||||
switch (cmd) {
|
||||
case AUTH_GETUGID:
|
||||
/* length, user name */
|
||||
must_read(socks[0], &username_len, sizeof(size_t));
|
||||
if (username_len == 0 || username_len > sizeof(username))
|
||||
_exit(0);
|
||||
must_read(socks[0], username, username_len);
|
||||
username[username_len - 1] = '\0';
|
||||
pw = getpwnam(username);
|
||||
if (pw) {
|
||||
ret = 1;
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
must_write(socks[0], &pw->pw_uid, sizeof(uid_t));
|
||||
must_write(socks[0], &pw->pw_gid, sizeof(gid_t));
|
||||
} else {
|
||||
ret = 0;
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
}
|
||||
endpwent();
|
||||
break;
|
||||
case AUTH_EXIT:
|
||||
close(socks[0]);
|
||||
_exit(1);
|
||||
default:
|
||||
fprintf(stderr, "auth unknown command %d\n", cmd);
|
||||
close(socks[0]);
|
||||
_exit(255);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "auth fatal error\n");
|
||||
|
||||
close(socks[0]);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* Read all data or return 1 for error. */
|
||||
static int
|
||||
may_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (1);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read data with the assertion that it all must come through, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
fprintf(stderr, "must_read: internal protocol error\n");
|
||||
fflush(stderr);
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write data with the assertion that it all has to be written, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_write(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = write(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
fprintf(stderr, "must_write: internal protocol error\n");
|
||||
fflush(stderr);
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
auth_getugid(char *username, sj3_ugid *ugid)
|
||||
{
|
||||
size_t len;
|
||||
int cmd = AUTH_GETUGID;
|
||||
int ret;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (auth_fd < 0) {
|
||||
fprintf(stderr, "%s called from privileged portion", "auth_getpwnam");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
len = strlen(username) + 1;
|
||||
if (len == 0 || BUFSIZ < len)
|
||||
return NULL;
|
||||
|
||||
must_write(auth_fd, &cmd, sizeof(int));
|
||||
must_write(auth_fd, &len, sizeof(size_t));
|
||||
must_write(auth_fd, username, len);
|
||||
must_read(auth_fd, &ret, sizeof(int));
|
||||
if (ret) {
|
||||
must_read(auth_fd, &uid, sizeof(uid_t));
|
||||
must_read(auth_fd, &gid, sizeof(gid_t));
|
||||
ugid->uid = uid;
|
||||
ugid->gid = gid;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exit_auth()
|
||||
{
|
||||
int cmd = AUTH_EXIT;
|
||||
|
||||
must_write(auth_fd, &cmd, sizeof(int));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ exec_connect()
|
|||
if (!(wp = alloc_workarea()))
|
||||
longjmp(error_ret, SJ3_NotEnoughMemory);
|
||||
|
||||
if (auth_getugid(username, &ugid)) {
|
||||
if (priv_getugid(username, &ugid)) {
|
||||
struct sockaddr addr;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ server_terminate()
|
|||
{
|
||||
close_socket();
|
||||
sj_closeall();
|
||||
exit_auth();
|
||||
priv_exit();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ main(int argc, char **argv)
|
|||
|
||||
exec_daemon();
|
||||
|
||||
exec_auth();
|
||||
priv_init();
|
||||
|
||||
set_signals();
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ main(int argc, char **argv)
|
|||
open_socket();
|
||||
|
||||
if (chroot_enable == 1)
|
||||
set_priv(NULL);
|
||||
priv_set(NULL);
|
||||
|
||||
preload_dict();
|
||||
preopen_dict();
|
||||
|
|
@ -152,7 +152,7 @@ main(int argc, char **argv)
|
|||
close_socket();
|
||||
|
||||
sj_closeall();
|
||||
exit_auth();
|
||||
priv_exit();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2004 Iwata <iwata@quasiquote.org>
|
||||
* Copyright (c) 2008 Iwata <iwata@quasiquote.org>
|
||||
* Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -17,13 +18,37 @@
|
|||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <pwd.h>
|
||||
#include "sj3serv.h"
|
||||
|
||||
enum priv_state {
|
||||
STATE_INIT, /* just started up */
|
||||
STATE_QUIT /* shutting down */
|
||||
};
|
||||
|
||||
enum cmd_types {
|
||||
PRIV_GETUGID,
|
||||
PRIV_EXIT
|
||||
};
|
||||
|
||||
static int auth_fd = -1;
|
||||
static volatile pid_t child_pid = -1;
|
||||
static volatile sig_atomic_t cur_state = STATE_INIT;
|
||||
|
||||
static int may_read(int, void *, size_t);
|
||||
static void must_read(int, void *, size_t);
|
||||
static void must_write(int, void *, size_t);
|
||||
static void sig_pass_to_chld(int);
|
||||
static void sig_got_chld(int);
|
||||
|
||||
void
|
||||
set_priv(const char *title)
|
||||
priv_set(const char *title)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
|
|
@ -74,3 +99,223 @@ set_priv(const char *title)
|
|||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
priv_init()
|
||||
{
|
||||
int socks[2];
|
||||
int i;
|
||||
struct sigaction sa;
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
|
||||
fprintf(stderr, "socketpair() failed");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
fprintf(stderr, "fork() failed\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if (!child_pid) {
|
||||
auth_fd = socks[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Father */
|
||||
/* Pass TERM/HUP/INT/QUIT through to child, and accept CHLD */
|
||||
sa.sa_handler = sig_pass_to_chld;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sa.sa_handler = sig_got_chld;
|
||||
sa.sa_flags |= SA_NOCLDSTOP;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
strlcpy(chroot_dir, "/", sizeof(chroot_dir));
|
||||
priv_set("[priv]");
|
||||
|
||||
while (cur_state < STATE_QUIT) {
|
||||
int cmd;
|
||||
size_t username_len;
|
||||
char username[BUFSIZ];
|
||||
int ret;
|
||||
struct passwd *pw;
|
||||
|
||||
if (may_read(socks[0], &cmd, sizeof(int)))
|
||||
break;
|
||||
switch (cmd) {
|
||||
case PRIV_GETUGID:
|
||||
/* length, user name */
|
||||
must_read(socks[0], &username_len, sizeof(size_t));
|
||||
if (username_len == 0 || username_len > sizeof(username))
|
||||
_exit(0);
|
||||
must_read(socks[0], username, username_len);
|
||||
username[username_len - 1] = '\0';
|
||||
pw = getpwnam(username);
|
||||
if (pw) {
|
||||
ret = 1;
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
must_write(socks[0], &pw->pw_uid, sizeof(uid_t));
|
||||
must_write(socks[0], &pw->pw_gid, sizeof(gid_t));
|
||||
} else {
|
||||
ret = 0;
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
}
|
||||
endpwent();
|
||||
break;
|
||||
case PRIV_EXIT:
|
||||
close(socks[0]);
|
||||
_exit(1);
|
||||
default:
|
||||
fprintf(stderr, "auth unknown command %d\n", cmd);
|
||||
close(socks[0]);
|
||||
_exit(255);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "auth fatal error\n");
|
||||
|
||||
close(socks[0]);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* Read all data or return 1 for error. */
|
||||
static int
|
||||
may_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (1);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read data with the assertion that it all must come through, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
fprintf(stderr, "must_read: internal protocol error\n");
|
||||
fflush(stderr);
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write data with the assertion that it all has to be written, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_write(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = write(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
fprintf(stderr, "must_write: internal protocol error\n");
|
||||
fflush(stderr);
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass the signal through to child */
|
||||
static void
|
||||
sig_pass_to_chld(int sig)
|
||||
{
|
||||
int oerrno = errno;
|
||||
|
||||
if (child_pid != -1)
|
||||
kill(child_pid, sig);
|
||||
errno = oerrno;
|
||||
}
|
||||
|
||||
/* When child dies, move into the shutdown state */
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
sig_got_chld(int sig)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
do {
|
||||
pid = waitpid(WAIT_ANY, NULL, WNOHANG);
|
||||
if (pid == child_pid && cur_state < STATE_QUIT)
|
||||
cur_state = STATE_QUIT;
|
||||
} while (pid > 0 || (pid == -1 && errno == EINTR));
|
||||
}
|
||||
|
||||
int
|
||||
priv_getugid(char *username, sj3_ugid *ugid)
|
||||
{
|
||||
size_t len;
|
||||
int cmd = PRIV_GETUGID;
|
||||
int ret;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (auth_fd < 0) {
|
||||
fprintf(stderr, "%s called from privileged portion", "auth_getpwnam");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
len = strlen(username) + 1;
|
||||
if (len == 0 || BUFSIZ < len)
|
||||
return NULL;
|
||||
|
||||
must_write(auth_fd, &cmd, sizeof(int));
|
||||
must_write(auth_fd, &len, sizeof(size_t));
|
||||
must_write(auth_fd, username, len);
|
||||
must_read(auth_fd, &ret, sizeof(int));
|
||||
if (ret) {
|
||||
must_read(auth_fd, &uid, sizeof(uid_t));
|
||||
must_read(auth_fd, &gid, sizeof(gid_t));
|
||||
ugid->uid = uid;
|
||||
ugid->gid = gid;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
priv_exit()
|
||||
{
|
||||
int cmd = PRIV_EXIT;
|
||||
|
||||
must_write(auth_fd, &cmd, sizeof(int));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ typedef struct {
|
|||
|
||||
/* auth.c */
|
||||
|
||||
int exec_auth();
|
||||
void exit_auth();
|
||||
int priv_init();
|
||||
void priv_exit();
|
||||
|
||||
int auth_getugid(char *, sj3_ugid *);
|
||||
int priv_getugid(char *, sj3_ugid *);
|
||||
|
||||
/* comuni.c */
|
||||
extern int client_num;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue