Skip to content
Closed
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Vim swap files
.*.swp

# Object files
*.o
*.ko
Expand Down Expand Up @@ -32,3 +35,6 @@
*.dSYM/

su-exec
su-exec-static
su-exec-debug
license.inc
32 changes: 26 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@

CFLAGS ?= -Wall -Werror -g
CFLAGS ?= -Wall -Werror
LDFLAGS ?=

PROG := su-exec
SRCS := $(PROG).c
INCS := license.inc

PREFIX := /usr/local
INSTALL_DIR := $(PREFIX)/bin
MAN_DIR := $(PREFIX)/share/man/man8

all: $(PROG)

$(PROG): $(SRCS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
license.inc: LICENSE
xxd -i $^ > $@

$(PROG): $(SRCS) $(INCS)
$(CC) $(CFLAGS) -o $@ $(SRCS) $(LDFLAGS)
strip $@

$(PROG)-static: $(SRCS) $(INCS)
$(CC) $(CFLAGS) -o $@ $(SRCS) -static $(LDFLAGS)
strip $@

$(PROG)-static: $(SRCS)
$(CC) $(CFLAGS) -o $@ $^ -static $(LDFLAGS)
$(PROG)-debug: $(SRCS) $(INCS)
$(CC) -g $(CFLAGS) -o $@ $(SRCS) $(LDFLAGS)

install:
install -d 0755 $(DESTDIR)$(INSTALL_DIR)
install -m 0755 $(PROG) $(DESTDIR)$(INSTALL_DIR)
install -d 0755 $(DESTDIR)$(MAN_DIR)
install -m 0644 su-exec.1 $(DESTDIR)$(MAN_DIR)

clean:
rm -f $(PROG) $(PROG)-static
rm -f $(PROG) $(PROG)-static $(PROG)-debug $(INCS)

69 changes: 69 additions & 0 deletions su-exec.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.TH SU-EXEC 8 "14 Oct 2017"

.SH NAME
su-exec \- change user id and group id before executing a program

.SH SYNOPSIS
\fBsu-exec\fP \fIuser-spec\fP \fIcommand\fP [ \fIarguments...\fP ]

\fBsu-exec\fP \fI-l\fP

.SH DESCRIPTION
\fBsu-exec\fP executes a program with modified privileges. The program
will be exceuted directly and not run as a child, like su and sudo does,
which avoids TTY and signal issues.

Notice that su-exec depends on being run by the root user, non-root
users do not have permission to change uid/gid.

.SH OPTIONS
.TP
\fIuser-spec\fP
is either a user name (e.g. \fBnobody\fP) or user name and group name
separated with colon (e.g. \fBnobody:ftp\fP). Numeric uid/gid values
can be used instead of names.

.TP
\fIcommand\fP
is the program to execute. Can be either absolute or relative path.

.TP
\fI-l\fP
Print license information and exits.

.SH EXAMPLES

.TP
Execute httpd as user \fIapache\fP and gid value 1000 with the two specified arguments:

$ \fBsu-exec apache:1000 /usr/sbin/httpd -f /opt/www/httpd.conf\fP

.SH ENVIRONMENT VARIABLES

.TP
\fBHOME\fP
Is updated to the value matching the user entry in \fC/etc/passwd\fP.

.TP
\fBPATH\fP
Is used for searching for the program to execute.

Since su-exec is not running as a suid binary, the dynamic linker or
libc will not strip or ignore variables like LD_LIBRARY_PATH etc.

.SH EXIT STATUS
.TP
\fB0\fP
When printing license information.

.TP
\fB1\fP
If \fbsu-exec\fR fails to change priveledges or execute the program it
will return \fB1\fP. In the successfull case the exit value will be
whatever the executed program returns.

.SH "SEE ALSO"
su(1), runuser(8), sudo(8), gosu(1)

.SH BUGS
\fBUSER\fP and \fBLOGNAME\fP environmental variables are not updated.
14 changes: 14 additions & 0 deletions su-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,24 @@
#include <string.h>
#include <unistd.h>


static char *argv0;

static void usage(int exitcode)
{
printf("Usage: %s user-spec command [args]\n", argv0);
printf("Usage: %s -l\n\tShows license.\n", argv0);
exit(exitcode);
}

#include "license.inc"
static void print_license()
{
unsigned int i;
for (i=0; i<LICENSE_len; i++)
putchar(LICENSE[i]);
}

int main(int argc, char *argv[])
{
char *user, *group, **cmdargv;
Expand All @@ -28,6 +38,10 @@ int main(int argc, char *argv[])
gid_t gid = getgid();

argv0 = argv[0];
if (argc == 2 && strcmp(argv[1], "-l") == 0) {
print_license();
return 0;
}
if (argc < 3)
usage(0);

Expand Down