cmdproxyd-0.2/000075500000000000000000000000001213375555700133775ustar00rootroot00000000000000cmdproxyd-0.2/.gitignore000064400000000000000000000000211213375555700153600ustar00rootroot00000000000000cmdproxyd *.[do] cmdproxyd-0.2/Makefile000064400000000000000000000031541213375555700150420ustar00rootroot00000000000000# # Copyright (C) 2004 Dmitry V. Levin # # Makefile for the cmdproxyd project. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # PROJECT = cmdproxyd TARGETS = $(PROJECT) sbindir = /usr/sbin DESTDIR = MKDIR_P = mkdir -p INSTALL = install CFLAGS = -pipe -Wall -Werror -W -O2 SRC = cmdproxyd.c OBJ = $(SRC:.c=.o) DEP = $(SRC:.c=.d) .PHONY: all install clean indent all: $(TARGETS) $(PROJECT): $(OBJ) $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ install: all $(MKDIR_P) -m755 $(DESTDIR)$(sbindir) $(INSTALL) -p -m755 cmdproxyd $(DESTDIR)$(sbindir)/ clean: $(RM) $(TARGETS) $(DEP) $(OBJ) core *~ indent: indent *.c # We need dependencies only if goal isn't "indent" or "clean". ifneq ($(MAKECMDGOALS),indent) ifneq ($(MAKECMDGOALS),clean) %.d: %.c @echo Making dependences for $< @$(SHELL) -ec "$(CC) -MM $(CPPFLAGS) $< | sed -e 's|\($*\)\.o[ :]*|\1.o $@ : |g' > $@; [ -s $@ ] || $(RM) $@" ifneq ($(DEP),) -include $(DEP) endif endif # clean endif # indent cmdproxyd-0.2/cmdproxyd.c000064400000000000000000000123661213375555700155640ustar00rootroot00000000000000 /* Copyright (C) 2004 Dmitry V. Levin The command proxy daemon. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void sigchld_handler( __attribute__ ((unused)) int signo) { while (waitpid(-1, 0, WNOHANG) > 0) ; } static void __attribute__ ((__noreturn__)) usage(int rc) { fprintf((rc == EXIT_SUCCESS) ? stdout : stderr, "Usage: %s bind_address.. runas program...\n", program_invocation_short_name); exit(rc); } static int bind_address(const char *address) { struct sockaddr_un sun; if (strlen(address) >= sizeof(sun)) error(EXIT_FAILURE, EINVAL, "cannot bind socket `%s'", address); memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; strcpy(sun.sun_path, address); int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) error(EXIT_FAILURE, errno, "cannot create socket `%s'", address); if (bind(fd, (struct sockaddr *) &sun, sizeof(sun))) { unlink(address); if (bind(fd, (struct sockaddr *) &sun, sizeof(sun))) error(EXIT_FAILURE, errno, "cannot bind socket `%s'", address); } if (chmod(address, 0666)) error(EXIT_FAILURE, errno, "cannot set permissions of socket `%s'", address); if (listen(fd, 5) < 0) error(EXIT_FAILURE, errno, "listen"); int flags; if ((flags = fcntl(fd, F_GETFD, 0)) == -1) error(EXIT_FAILURE, errno, "fcntl: F_GETFD"); flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) == -1) error(EXIT_FAILURE, errno, "fcntl: F_SETFD"); return fd; } static void handle_socket(int fd, const char *address, const char *const *args) { struct sockaddr_un sun; memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; socklen_t sunlen = sizeof(sun); int accfd = accept(fd, (struct sockaddr *) &sun, &sunlen); if (accfd < 0) { if (errno != EINTR) { syslog(LOG_ERR, "accept: %s[%d]: %m", address, fd); sleep(1); } return; } struct ucred sucred; socklen_t credlen = sizeof(struct ucred); if (getsockopt(accfd, SOL_SOCKET, SO_PEERCRED, &sucred, &credlen)) { close(accfd); syslog(LOG_ERR, "getsockopt: SO_PEERCRED: %s[%d]: %m", address, fd); sleep(1); return; } struct passwd *pw = getpwuid(sucred.uid); if (!pw) { close(accfd); syslog(LOG_ERR, "getsockopt: request from %s, uid=%u, unknown user rejected", address, sucred.uid); sleep(1); return; } pid_t pid = fork(); if (pid < 0) { close(accfd); syslog(LOG_ERR, "fork: %m"); sleep(1); return; } if (pid) { close(accfd); return; } if (setenv("REMOTE_USER", pw->pw_name, 1)) { syslog(LOG_ERR, "setenv: %m"); exit(EXIT_FAILURE); } dup2(accfd, 0); close(accfd); syslog(LOG_INFO, "request from %s by %s(%u), executing %s", address, pw->pw_name, sucred.uid, args[0]); execvp(args[0], (char *const *) args); syslog(LOG_ERR, "execvp: %s: %m", args[0]); exit(EXIT_FAILURE); } int main(int ac, const char *av[]) { signal(SIGCHLD, sigchld_handler); if (ac < 3) usage(EXIT_FAILURE); const char *runas = 0; const char *const *args = 0; int nsockets = 0; int i; for (i = 1; i < ac; ++i) { if (runas) { args = &av[i]; break; } if (av[i][0] == '/') { ++nsockets; continue; } if (!nsockets) usage(EXIT_FAILURE); runas = av[i]; } if (!nsockets || !runas || !args) usage(EXIT_FAILURE); struct passwd *pw = getpwnam(runas); if (!pw) error(EXIT_FAILURE, 0, "user `%s' lookup failed", runas); int sockfd[nsockets]; for (i = 1; i <= nsockets; ++i) sockfd[i - 1] = bind_address(av[i]); if (initgroups(runas, pw->pw_gid)) error(EXIT_FAILURE, errno, "initgroups"); if (setgid(pw->pw_gid)) error(EXIT_FAILURE, errno, "setgid"); if (setuid(pw->pw_uid)) error(EXIT_FAILURE, errno, "setuid"); if (daemon(0, 0)) error(EXIT_FAILURE, errno, "daemon"); openlog("cmdproxyd", LOG_PERROR | LOG_PID, LOG_DAEMON); for (;;) { int i, maxfd = 0; fd_set r; FD_ZERO(&r); for (i = 0; i < nsockets; ++i) { FD_SET(sockfd[i], &r); if (sockfd[i] > maxfd) maxfd = sockfd[i]; } int rc = select(1 + sockfd[nsockets - 1], &r, 0, 0, 0); if (rc < 0) { if (errno == EINTR) continue; syslog(LOG_ERR, "select: %m"); sleep(1); continue; } for (i = 0; i < nsockets; ++i) if (FD_ISSET(sockfd[i], &r)) handle_socket(sockfd[i], av[1 + i], args); } } cmdproxyd-0.2/cmdproxyd.init000075500000000000000000000021021213375555700162730ustar00rootroot00000000000000#!/bin/sh # # chkconfig: - 95 05 # description: \ # The command proxy daemon. # # processname: cmdproxyd WITHOUT_RC_COMPAT=1 # Source function library. . /etc/init.d/functions LOCKFILE=/var/lock/subsys/cmdproxyd RUN_AS=cmdproxyd BIND_ADDR= RUN_CMD= RETVAL=0 # Source config. SourceIfNotEmpty /etc/sysconfig/cmdproxyd start() { [ -n "$RUN_AS" -a -n "$BIND_ADDR" -a -n "$RUN_CMD" ] || return 0 start_daemon --lockfile "$LOCKFILE" --expect-user "$RUN_AS" -- cmdproxyd $BIND_ADDR "$RUN_AS" $RUN_CMD RETVAL=$? return $RETVAL } stop() { stop_daemon --lockfile "$LOCKFILE" --expect-user "$RUN_AS" cmdproxyd RETVAL=$? return $RETVAL } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; reload|restart) restart ;; condstop) if [ -e "$LOCKFILE" ]; then stop fi ;; condrestart|condreload) if [ -e "$LOCKFILE" ]; then restart fi ;; status) status --expect-user "$RUN_AS" cmdproxyd RETVAL=$? ;; *) msg_usage "${0##*/} {start|stop|restart|condstop|condrestart|status}" RETVAL=1 esac exit $RETVAL cmdproxyd-0.2/cmdproxyd.spec000064400000000000000000000017611213375555700162710ustar00rootroot00000000000000Name: cmdproxyd Version: 0.2 Release: alt1 Summary: A command proxy daemon License: GPLv2+ Group: System/Servers Source: %name-%version.tar PreReq: shadow-utils, service %description This is a command proxy daemon. %prep %setup %build %make_build CFLAGS="%optflags -Werror -W" %install %make_install install DESTDIR=%buildroot install -pD -m755 %name.init %buildroot%_initdir/%name install -pD -m644 %name.sysconfig %buildroot%_sysconfdir/sysconfig/%name %post /usr/sbin/groupadd -r -f %name /usr/sbin/useradd -r -g %name -d /dev/null -s /dev/null -n %name >/dev/null 2>&1 ||: %post_service %name %preun %preun_service %name %files %config %_initdir/* %config(noreplace) %_sysconfdir/sysconfig/%name %_sbindir/* %changelog * Wed Aug 11 2010 Dmitry V. Levin 0.2-alt1 - Minor fixes and enhancements. * Tue Apr 10 2007 Dmitry V. Levin 0.1-alt2 - Reduced macro abuse in specfile. * Wed May 26 2004 Dmitry V. Levin 0.1-alt1 - Initial revision. cmdproxyd-0.2/cmdproxyd.sysconfig000064400000000000000000000002401213375555700173320ustar00rootroot00000000000000# Username to use for executed commands. RUN_AS=cmdproxyd # List of unix domain sockets to bind. BIND_ADDR= # Command with its arguments to execute. RUN_CMD=