diff options
Diffstat (limited to 'tdesu/tdesu_stub.c')
-rw-r--r-- | tdesu/tdesu_stub.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/tdesu/tdesu_stub.c b/tdesu/tdesu_stub.c new file mode 100644 index 000000000..5e1f09c24 --- /dev/null +++ b/tdesu/tdesu_stub.c @@ -0,0 +1,432 @@ +/* vi: ts=8 sts=4 sw=4 + * + * $Id$ + * + * This file is part of the KDE project, module tdesu. + * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org> + * + * tdesu_stub.c: KDE su executes this stub through su or ssh. This stub in turn + * executes the target program. Before that, startup parameters + * are sent through stdin. + * + * + * Available parameters: + * + * Parameter Description Format (csl = comma separated list) + * + * - tdesu_stub Header "ok" | "stop" + * - display X11 display string + * - display_auth X11 authentication "type cookie" pair + * - dcopserver KDE dcopserver csl of netids + * - dcop_auth DCOP authentication csl of "type cookie" pairs for DCOP + * - ice_auth ICE authentication csl of "type cookie" pairs for ICE + * - command Command to run string + * - path PATH env. var string + * - build_sycoca Rebuild sycoca? "yes" | "no" + * - user Target user string + * - priority Process priority 0 <= int <= 100 + * - scheduler Process scheduler "fifo" | "normal" + * - app_startup_id DESKTOP_STARTUP_ID string + * - environment Additional envvars strings, last one is empty + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <termios.h> +#include <signal.h> + +#ifdef HAVE_INITGROUPS +#include <grp.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> + +#ifdef POSIX1B_SCHEDULING +#include <sched.h> +#endif + +/** + * Params sent by the peer. + */ + +struct param_struct +{ + const char *name; + char *value; +}; + +struct param_struct params[] = +{ + { "tdesu_stub", 0L }, + { "display", 0L }, + { "display_auth", 0L }, + { "dcopserver", 0L }, + { "dcop_auth", 0L }, + { "ice_auth", 0L }, + { "command", 0L }, + { "path", 0L }, + { "xwindows_only", 0L }, + { "user", 0L }, + { "priority", 0L }, + { "scheduler", 0L }, +/* obsoleted by app_startup_id { "app_start_pid", 0L } */ + { "app_startup_id", 0L } +}; + +#define P_HEADER 0 +#define P_DISPLAY 1 +#define P_DISPLAY_AUTH 2 +#define P_DCOPSERVER 3 +#define P_DCOP_AUTH 4 +#define P_ICE_AUTH 5 +#define P_COMMAND 6 +#define P_PATH 7 +#define P_XWIN_ONLY 8 +#define P_USER 9 +#define P_PRIORITY 10 +#define P_SCHEDULER 11 +#define P_APP_STARTUP_ID 12 +#define P_LAST 13 + +/* Prototypes */ +char *xmalloc(size_t); +char *xrealloc(char *ptr, int size); +int xsetenv(const char *name, const char *value); +char *xstrdup(char *src); +char **xstrsep(char *str); + +/** + * Safe malloc functions. + */ +char *xmalloc(size_t size) +{ + char *ptr = malloc(size); + if (ptr) return ptr; + perror("malloc()"); + exit(1); +} + + +char *xrealloc(char *ptr, int size) +{ + ptr = realloc(ptr, size); + if (ptr) return ptr; + perror("realloc()"); + exit(1); +} + + +/** + * Solaris does not have a setenv()... + */ +int xsetenv(const char *name, const char *value) +{ + char *s = malloc(strlen(name)+strlen(value)+2); + if (!s) return -1; + strcpy(s, name); + strcat(s, "="); + strcat(s, value); + return putenv(s); /* yes: no free()! */ +} + +/** + * Safe strdup and strip newline + */ +char *xstrdup(char *src) +{ + int len = strlen(src); + char *dst = xmalloc(len+1); + strcpy(dst, src); + if (dst[len-1] == '\n') + dst[len-1] = '\000'; + return dst; +} + +/** + * Split comma separated list. + */ +char **xstrsep(char *str) +{ + int i = 0, size = 10; + char **list = (char **) xmalloc(size * sizeof(char *)); + char *ptr = str, *nptr; + while ((nptr = strchr(ptr, ',')) != 0L) + { + if (i > size-2) + list = realloc(list, (size *= 2) * sizeof(char *)); + *nptr = '\000'; + list[i++] = ptr; + ptr = nptr+1; + } + if (*ptr != '\000') + list[i++] = ptr; + list[i] = 0L; + return list; +} + +#define BUFSIZE 8192 + +/** + * The main program + */ + +int main() +{ + char buf[BUFSIZE+1]; +#ifndef QWS + char xauthority[200]; +#endif + char iceauthority[200]; + char **host, **auth; + int i/*, res, sycoca*/, prio; + pid_t pid; + FILE *fout; + struct passwd *pw; + const char* tdesu_lc_all; + + /* Get startup parameters. */ + + for (i=0; i<P_LAST; i++) + { + printf("%s\n", params[i].name); + fflush(stdout); + if (fgets(buf, BUFSIZE, stdin) == 0L) + { + printf("end\n"); fflush(stdout); + perror("tdesu_stub: fgets()"); + exit(1); + } + params[i].value = xstrdup(buf); + /* Installation check? */ + if ((i == 0) && !strcmp(params[i].value, "stop")) + { + printf("end\n"); + exit(0); + } + } + printf("environment\n"); + fflush(stdout); + for(;;) + { + char* tmp; + if (fgets(buf, BUFSIZE, stdin) == 0L) + { + printf("end\n"); fflush(stdout); + perror("tdesu_stub: fgets()"); + exit(1); + } + tmp = xstrdup( buf ); + if( tmp[ 0 ] == '\0' ) /* terminator */ + break; + putenv( xstrdup( buf )); + } + + printf("end\n"); + fflush(stdout); + + xsetenv("PATH", params[P_PATH].value); + xsetenv("DESKTOP_STARTUP_ID", params[P_APP_STARTUP_ID].value); + + tdesu_lc_all = getenv( "KDESU_LC_ALL" ); + if( tdesu_lc_all != NULL ) + xsetenv("LC_ALL",tdesu_lc_all); + else + unsetenv("LC_ALL"); + + /* Do we need to change uid? */ + + pw = getpwnam(params[P_USER].value); + if (pw == 0L) + { + printf("tdesu_stub: user %s does not exist!\n", params[P_USER].value); + exit(1); + } + xsetenv("HOME", pw->pw_dir); + + /* Set scheduling/priority */ + + prio = atoi(params[P_PRIORITY].value); + if (!strcmp(params[P_SCHEDULER].value, "realtime")) + { +#ifdef POSIX1B_SCHEDULING + struct sched_param sched; + int min = sched_get_priority_min(SCHED_FIFO); + int max = sched_get_priority_max(SCHED_FIFO); + sched.sched_priority = min + (int) (((double) prio) * (max - min) / 100 + 0.5); + sched_setscheduler(0, SCHED_FIFO, &sched); +#else + printf("tdesu_stub: realtime scheduling not supported\n"); +#endif + } else + { +#ifdef HAVE_SETPRIORITY + int val = 20 - (int) (((double) prio) * 40 / 100 + 0.5); + setpriority(PRIO_PROCESS, getpid(), val); +#endif + } + + /* Drop privileges (this is permanent) */ + + if (getuid() != pw->pw_uid) + { + if (setgid(pw->pw_gid) == -1) + { + perror("tdesu_stub: setgid()"); + exit(1); + } +#ifdef HAVE_INITGROUPS + if (initgroups(pw->pw_name, pw->pw_gid) == -1) + { + perror("tdesu_stub: initgroups()"); + exit(1); + } +#endif + if (setuid(pw->pw_uid) == -1) + { + perror("tdesu_stub: setuid()"); + exit(1); + } + xsetenv("HOME", pw->pw_dir); + } + + /* Handle display */ + + if (strcmp(params[P_DISPLAY].value, "no")) + { +#ifndef QWS + xsetenv("DISPLAY", params[P_DISPLAY].value); + if (params[P_DISPLAY_AUTH].value[0]) + { + int fd2; + /* + ** save umask and set to 077, so we create those files only + ** readable for root. (if someone else could read them, we + ** are in deep shit). + */ + int oldumask = umask(077); + const char *disp = params[P_DISPLAY].value; + if (strncmp(disp, "localhost:", 10) == 0) + disp += 9; + + strcpy(xauthority, "/tmp/xauth.XXXXXXXXXX"); + fd2 = mkstemp(xauthority); + umask(oldumask); + + if (fd2 == -1) { + perror("tdesu_stub: mkstemp()"); + exit(1); + } else + close(fd2); + xsetenv("XAUTHORITY", xauthority); + + fout = popen("xauth >/dev/null 2>&1","w"); + if (fout == NULL) + { + perror("tdesu_stub: popen(xauth)"); + exit(1); + } + fprintf(fout, "add %s %s\n", disp, + params[P_DISPLAY_AUTH].value); + pclose(fout); + } +#else + xsetenv("DISPLAY", params[P_DISPLAY].value); +#endif + } + + + /* Handle DCOP */ + + if (strcmp(params[P_DCOPSERVER].value, "no")) + { + xsetenv("DCOPSERVER", params[P_DCOPSERVER].value); + host = xstrsep(params[P_DCOPSERVER].value); + auth = xstrsep(params[P_ICE_AUTH].value); + if (host[0]) + { + int fd; + int oldumask = umask(077); + + strcpy(iceauthority, "/tmp/iceauth.XXXXXXXXXX"); + fd = mkstemp(iceauthority); + umask(oldumask); + if (fd == -1) { + perror("tdesu_stub: mkstemp()"); + exit(1); + } else + close(fd); + xsetenv("ICEAUTHORITY", iceauthority); + + fout = popen("iceauth >/dev/null 2>&1", "w"); + if (!fout) { + perror("tdesu_stub: popen iceauth"); + exit(1); + } + for (i=0; host[i]; i++) + fprintf(fout, "add ICE \"\" %s %s\n", host[i], auth[i]); + auth = xstrsep(params[P_DCOP_AUTH].value); + for (i=0; host[i]; i++) + fprintf(fout, "add DCOP \"\" %s %s\n", host[i], auth[i]); + pclose(fout); + } + } + + /* Rebuild the sycoca and start tdeinit? */ + + if (strcmp(params[P_XWIN_ONLY].value, "no")) + { + system("tdeinit --suicide"); + } + + /* Execute the command */ + + pid = fork(); + if (pid == -1) + { + perror("tdesu_stub: fork()"); + exit(1); + } + if (pid) + { + /* Parent: wait for child, delete tempfiles and return. */ + int ret, state, xit = 1; + while (1) + { + ret = waitpid(pid, &state, 0); + if (ret == -1) + { + if (errno == EINTR) + continue; + if (errno != ECHILD) + perror("tdesu_stub: waitpid()"); + break; + } + if (WIFEXITED(state)) + xit = WEXITSTATUS(state); + } + +#ifndef QWS + unlink(xauthority); +#endif + unlink(iceauthority); + exit(xit); + } else + { + setsid(); + /* Child: exec command. */ + sprintf(buf, "%s", params[P_COMMAND].value); + execl("/bin/sh", "sh", "-c", buf, (void *)0); + perror("tdesu_stub: exec()"); + _exit(1); + } +} |