summaryrefslogtreecommitdiff
path: root/parabolaweb-changepassword.c
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 /parabolaweb-changepassword.c
parente16a61a7cbd6ed720438b317525d0dc844b5f7ba (diff)
I'm a dummy, you can't SUID a shell script.
Diffstat (limited to 'parabolaweb-changepassword.c')
-rw-r--r--parabolaweb-changepassword.c103
1 files changed, 103 insertions, 0 deletions
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);
+}