properly compute width of containing block of inline elements
[kdelibs.git] / kdesu / kdesu_stub.c
blob34a4f639c877c77af62d1b2d559b67cd2f45f29f
1 /* vi: ts=8 sts=4 sw=4
3 * kdesu_stub.c: KDE su executes this stub through su or ssh. This stub in turn
4 * executes the target program. Before that, startup parameters
5 * are sent through stdin.
7 * This file is part of the KDE project, module kdesu.
8 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * Available parameters:
27 * Parameter Description Format (csl = comma separated list)
29 * - kdesu_stub Header "ok" | "stop"
30 * - display X11 display string
31 * - display_auth X11 authentication "type cookie" pair
32 * - command Command to run string
33 * - path PATH env. var string
34 * - build_sycoca Rebuild sycoca? "yes" | "no"
35 * - user Target user string
36 * - priority Process priority 0 <= int <= 100
37 * - scheduler Process scheduler "fifo" | "normal"
38 * - app_startup_id DESKTOP_STARTUP_ID string
39 * - environment Additional envvars strings, last one is empty
42 #include <config.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <pwd.h>
50 #include <termios.h>
51 #include <signal.h>
53 #ifdef HAVE_INITGROUPS
54 #include <grp.h>
55 #endif
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/wait.h>
60 #include <sys/time.h>
61 #include <sys/resource.h>
63 #ifdef POSIX1B_SCHEDULING
64 #include <sched.h>
65 #endif
67 /**
68 * Params sent by the peer.
71 struct param_struct
73 const char *name;
74 char *value;
77 struct param_struct params[] =
79 { "kdesu_stub", 0L },
80 { "display", 0L },
81 { "display_auth", 0L },
82 { "command", 0L },
83 { "path", 0L },
84 { "xwindows_only", 0L },
85 { "user", 0L },
86 { "priority", 0L },
87 { "scheduler", 0L },
88 /* obsoleted by app_startup_id { "app_start_pid", 0L } */
89 { "app_startup_id", 0L }
92 #define P_HEADER 0
93 #define P_DISPLAY 1
94 #define P_DISPLAY_AUTH 2
95 #define P_COMMAND 3
96 #define P_PATH 4
97 #define P_XWIN_ONLY 5
98 #define P_USER 6
99 #define P_PRIORITY 7
100 #define P_SCHEDULER 8
101 #define P_APP_STARTUP_ID 9
102 #define P_LAST 10
105 * Safe malloc functions.
107 char *xmalloc(size_t size)
109 char *ptr = malloc(size);
110 if (ptr) return ptr;
111 perror("malloc()");
112 exit(1);
116 char **xrealloc(char **ptr, int size)
118 ptr = realloc(ptr, size);
119 if (ptr) return ptr;
120 perror("realloc()");
121 exit(1);
126 * Solaris does not have a setenv()...
128 int xsetenv(const char *name, const char *value)
130 char *s = malloc(strlen(name)+strlen(value)+2);
131 if (!s) return -1;
132 strcpy(s, name);
133 strcat(s, "=");
134 strcat(s, value);
135 return putenv(s); /* yes: no free()! */
139 * Safe strdup and strip newline
141 char *xstrdup(char *src)
143 int len = strlen(src);
144 char *dst = xmalloc(len+1);
145 strcpy(dst, src);
146 if (dst[len-1] == '\n')
147 dst[len-1] = '\000';
148 return dst;
152 * Split comma separated list.
154 char **xstrsep(char *str)
156 int i = 0, size = 10;
157 char **list = (char **) xmalloc(size * sizeof(char *));
158 char *ptr = str, *nptr;
159 while ((nptr = strchr(ptr, ',')) != 0L)
161 if (i > size-2)
162 list = xrealloc(list, (size *= 2) * sizeof(char *));
163 *nptr = '\000';
164 list[i++] = ptr;
165 ptr = nptr+1;
167 if (*ptr != '\000')
168 list[i++] = ptr;
169 list[i] = 0L;
170 return list;
173 #define BUFSIZE 8192
176 * The main program
179 int main()
181 char buf[BUFSIZE+1];
182 #ifndef QWS
183 char xauthority[200];
184 #endif
185 char iceauthority[200];
186 int i/*, res, sycoca*/, prio;
187 pid_t pid;
188 FILE *fout;
189 struct passwd *pw;
190 const char* kdesu_lc_all;
192 /* Get startup parameters. */
194 for (i=0; i<P_LAST; i++)
196 printf("%s\n", params[i].name);
197 fflush(stdout);
198 if (fgets(buf, BUFSIZE, stdin) == 0L)
200 printf("end\n"); fflush(stdout);
201 perror("kdesu_stub: fgets()");
202 exit(1);
204 params[i].value = xstrdup(buf);
205 /* Installation check? */
206 if ((i == 0) && !strcmp(params[i].value, "stop"))
208 printf("end\n");
209 exit(0);
212 printf("environment\n");
213 fflush(stdout);
214 for(;;)
216 char* tmp;
217 if (fgets(buf, BUFSIZE, stdin) == 0L)
219 printf("end\n"); fflush(stdout);
220 perror("kdesu_stub: fgets()");
221 exit(1);
223 tmp = xstrdup( buf );
224 if( tmp[ 0 ] == '\0' ) /* terminator */
225 break;
226 putenv( xstrdup( buf ));
229 printf("end\n");
230 fflush(stdout);
232 xsetenv("PATH", params[P_PATH].value);
233 xsetenv("DESKTOP_STARTUP_ID", params[P_APP_STARTUP_ID].value);
235 kdesu_lc_all = getenv( "KDESU_LC_ALL" );
236 if( kdesu_lc_all != NULL )
237 xsetenv("LC_ALL",kdesu_lc_all);
238 else
239 unsetenv("LC_ALL");
241 /* Do we need to change uid? */
243 pw = getpwnam(params[P_USER].value);
244 if (pw == 0L)
246 printf("kdesu_stub: user %s does not exist!\n", params[P_USER].value);
247 exit(1);
249 xsetenv("HOME", pw->pw_dir);
251 /* Set scheduling/priority */
253 prio = atoi(params[P_PRIORITY].value);
254 if (!strcmp(params[P_SCHEDULER].value, "realtime"))
256 #ifdef POSIX1B_SCHEDULING
257 struct sched_param sched;
258 int min = sched_get_priority_min(SCHED_FIFO);
259 int max = sched_get_priority_max(SCHED_FIFO);
260 sched.sched_priority = min + (int) (((double) prio) * (max - min) / 100 + 0.5);
261 sched_setscheduler(0, SCHED_FIFO, &sched);
262 #else
263 printf("kdesu_stub: realtime scheduling not supported\n");
264 #endif
265 } else
267 #ifdef HAVE_SETPRIORITY
268 int val = 20 - (int) (((double) prio) * 40 / 100 + 0.5);
269 setpriority(PRIO_PROCESS, getpid(), val);
270 #endif
273 /* Drop privileges (this is permanent) */
275 if (getuid() != pw->pw_uid)
277 if (setgid(pw->pw_gid) == -1)
279 perror("kdesu_stub: setgid()");
280 exit(1);
282 #ifdef HAVE_INITGROUPS
283 if (initgroups(pw->pw_name, pw->pw_gid) == -1)
285 perror("kdesu_stub: initgroups()");
286 exit(1);
288 #endif
289 if (setuid(pw->pw_uid) == -1)
291 perror("kdesu_stub: setuid()");
292 exit(1);
294 xsetenv("HOME", pw->pw_dir);
297 /* Handle display */
299 if (strcmp(params[P_DISPLAY].value, "no"))
301 #ifndef QWS
302 xsetenv("DISPLAY", params[P_DISPLAY].value);
303 if (params[P_DISPLAY_AUTH].value[0])
305 int fd2;
307 ** save umask and set to 077, so we create those files only
308 ** readable for root. (if someone else could read them, we
309 ** are in deep shit).
311 int oldumask = umask(077);
312 const char *disp = params[P_DISPLAY].value;
313 if (strncmp(disp, "localhost:", 10) == 0)
314 disp += 9;
316 strcpy(xauthority, "/tmp/xauth.XXXXXXXXXX");
317 fd2 = mkstemp(xauthority);
318 umask(oldumask);
320 if (fd2 == -1) {
321 perror("kdesu_stub: mkstemp()");
322 exit(1);
323 } else
324 close(fd2);
325 xsetenv("XAUTHORITY", xauthority);
327 fout = popen("xauth >/dev/null 2>&1","w");
328 if (fout == NULL)
330 perror("kdesu_stub: popen(xauth)");
331 exit(1);
333 fprintf(fout, "add %s %s\n", disp,
334 params[P_DISPLAY_AUTH].value);
335 pclose(fout);
337 #else
338 xsetenv("DISPLAY", params[P_DISPLAY].value);
339 #endif
342 /* Rebuild the sycoca and start kdeinit? */
344 if (strcmp(params[P_XWIN_ONLY].value, "no"))
346 system("kdeinit4 --suicide");
349 /* Execute the command */
351 pid = fork();
352 if (pid == -1)
354 perror("kdesu_stub: fork()");
355 exit(1);
357 if (pid)
359 /* Parent: wait for child, delete tempfiles and return. */
360 int ret, state, xit = 1;
361 while (1)
363 ret = waitpid(pid, &state, 0);
364 if (ret == -1)
366 if (errno == EINTR)
367 continue;
368 if (errno != ECHILD)
369 perror("kdesu_stub: waitpid()");
370 break;
372 if (WIFEXITED(state))
373 xit = WEXITSTATUS(state);
376 #ifndef QWS
377 unlink(xauthority);
378 #endif
379 unlink(iceauthority);
380 exit(xit);
381 } else
383 setsid();
384 /* Child: exec command. */
385 sprintf(buf, "%s", params[P_COMMAND].value);
386 execl("/bin/sh", "sh", "-c", buf, (void *)0);
387 perror("kdesu_stub: exec()");
388 _exit(1);