summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2014-06-23 19:45:34 -0400
committerLuke Shumaker <LukeShu@sbcglobal.net>2014-06-23 19:45:34 -0400
commit07bbca11bee7e0ddae32f9e5db8bf03b72def4ab (patch)
tree86d2cdf9da52edac090119a029d26126f22778b3
parente16a61a7cbd6ed720438b317525d0dc844b5f7ba (diff)
I'm a dummy, you can't SUID a shell script.
-rw-r--r--.gitignore1
-rw-r--r--Makefile15
-rw-r--r--parabolaweb-changepassword.c103
-rwxr-xr-x[-rw-r--r--]parabolaweb-changepassword.sh (renamed from parabolaweb-changepassword)37
4 files changed, 149 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index 9f66953..52f4d7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
depends.txt
*.service
+parabolaweb-changepassword
diff --git a/Makefile b/Makefile
index a761beb..4abd3a5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,16 @@
prefix = /usr
-sbindir = $(prefix)/sbin
+exec_prefix = $(prefix)
+sbindir = $(exec_prefix)/sbin
+libexecdir = $(exec_prefix)/lib
systemddir = $(prefix)/lib/systemd/system
confdir = /etc/conf.d
-all: depends.txt
+pkglibexecdir = $(libexecdir)/parabolaweb-utils
+
+CFLAGS += -std=c99 -Wall -Wextra -Werror -Wno-unused-parameter
+CPPFLAGS += -DSCRIPT_LOCATION='"$(pkglibexecdir)/parabolaweb-changepassword.real"'
+
+all: depends.txt parabolaweb-changepassword
install: \
$(DESTDIR)$(sbindir)/parabolaweb-changepassword \
@@ -11,6 +18,7 @@ install: \
$(DESTDIR)$(sbindir)/parabolaweb-reporead-inotify \
$(DESTDIR)$(sbindir)/parabolaweb-update \
$(DESTDIR)$(confdir)/parabolaweb \
+ $(DESTDIR)$(pkglibexecdir)/parabolaweb-changepassword.real \
$(DESTDIR)$(systemddir)/parabolaweb.service \
$(DESTDIR)$(systemddir)/parabolaweb-reporead-inotify.service
@@ -26,6 +34,9 @@ $(DESTDIR)$(sbindir)/%: %
$(DESTDIR)$(sbindir)/parabolaweb-changepassword: parabolaweb-changepassword
install -Dm6755 $< $@
+$(DESTDIR)$(pkglibexecdir)/parabolaweb-changepassword.real: parabolaweb-changepassword.sh
+ install -Dm755 $< $@
+
$(DESTDIR)$(systemddir)/%.service: %.service
install -Dm644 $< $@
diff --git a/parabolaweb-changepassword.c b/parabolaweb-changepassword.c
new file mode 100644
index 0000000..14ada37
--- /dev/null
+++ b/parabolaweb-changepassword.c
@@ -0,0 +1,103 @@
+/* just a "stupid" secure SUID wrapper for the parabolaweb-changepassword script */
+/* Copyright (C) 2014 Luke Shumaker <lukeshu@sbcglobal.net>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE /* for environment functions and asprintf(3) */
+#include <errno.h> /* for errno */
+#include <error.h> /* for error(3) */
+#include <pwd.h> /* for getpwuid(3) */
+#include <stdlib.h> /* for free(3) and environment functions */
+#include <unistd.h> /* for getuid(3), geteuid(3), execl(3) */
+#include <stdio.h> /* for asprintf(3) in atoi() */
+
+void
+mysetenv(const char *name, const char *value)
+{
+ if (value != NULL) {
+ if (setenv(name, value, 1) != 0) {
+ error(127, errno, "could not set %s", name);
+ }
+ }
+}
+
+void
+xfree(void *ptr) {
+ if (ptr != NULL)
+ free(ptr);
+}
+
+char *
+itoa(long i) {
+ char *a = NULL;
+ int r = asprintf(&a, "%ld", i);
+ if (r < 0) {
+ xfree(a);
+ return NULL;
+ }
+ return a;
+}
+
+void
+sanitize_environment()
+{
+ char *a = NULL;
+ struct passwd *user = NULL;
+
+ const char *env_term = getenv("TERM");
+ const char *env_lang = getenv("LANG");
+ const char *env_lc_all = getenv("LC_ALL");
+ const char *env_lc_collate = getenv("LC_COLLATE");
+ const char *env_lc_ctype = getenv("LC_CTIME");
+ const char *env_lc_messages = getenv("LC_MESSAGES");
+ const char *env_lc_monetary = getenv("LC_MONETARY");
+ const char *env_lc_numeric = getenv("LC_NUMERIC");
+ const char *env_lc_time = getenv("LC_TIME");
+
+ clearenv();
+
+ mysetenv("TERM" , env_term );
+ mysetenv("LANG" , env_lang );
+ mysetenv("LC_ALL" , env_lc_all );
+ mysetenv("LC_COLLATE" , env_lc_collate );
+ mysetenv("LC_CTIME" , env_lc_ctype );
+ mysetenv("LC_MESSAGES", env_lc_messages);
+ mysetenv("LC_MONETARY", env_lc_monetary);
+ mysetenv("LC_NUMERIC" , env_lc_numeric );
+ mysetenv("LC_TIME" , env_lc_time );
+
+ user = getpwuid(getuid());
+ /* similar to SUDO_* */
+ mysetenv("SUID_USER", user->pw_name );
+ mysetenv("SUID_UID" , a=itoa(user->pw_uid)); xfree(a);
+ mysetenv("SUID_GID" , a=itoa(user->pw_gid)); xfree(a);
+
+ setreuid(geteuid(), -1);
+
+ user = getpwuid(geteuid());
+ mysetenv("USER" , user->pw_name);
+ mysetenv("LOGNAME", user->pw_name);
+ mysetenv("HOME" , user->pw_dir );
+}
+
+int
+main(int argc, char **argv)
+{
+ if (getuid() != 0)
+ sanitize_environment();
+
+ execv(SCRIPT_LOCATION, argv);
+ error(127, errno, "could not exec actual program: %s", SCRIPT_LOCATION);
+}
diff --git a/parabolaweb-changepassword b/parabolaweb-changepassword.sh
index 96c285a..04627c8 100644..100755
--- a/parabolaweb-changepassword
+++ b/parabolaweb-changepassword.sh
@@ -15,10 +15,37 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-. /etc/conf.d/parabolaweb
+export PATH
-[[ -e "${WEBDIR}/manage.py" ]]
-[[ -n "${WEBUSER}" ]]
-[[ $# -eq 0 ]]
+usage() {
+ printf 'Usage: %s [USERNAME]\n' "${0##*/}"
+ printf 'A username may only be specified if run as root or WEBUSER.\n'
+}
-sudo -u "${WEBUSER}" python2 "${WEBDIR}/manage.py" changepassword "${USER}"
+main() {
+ . /etc/conf.d/parabolaweb
+
+ [[ -e "${WEBDIR}/manage.py" ]]
+ [[ -n "${WEBUSER}" ]]
+
+ RUSER=${SUDO_USER:-${SUID_USER:-$USER}}
+ EUSER=${USER}
+
+ if [[ $EUSER == root ]] || [[ $EUSER == "$WEBUSER" ]]; then
+ if [[ $# -gt 1 ]]; then
+ usage >&2
+ return 1
+ fi
+ username=${1:-$RUSER}
+ else
+ if [[ $# -gt 0 ]]; then
+ usage >&2
+ return 1
+ fi
+ username=$RUSER
+ fi
+
+ sudo -u "${WEBUSER}" python2 "${WEBDIR}/manage.py" changepassword "${username}"
+}
+
+main "$@"