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
53 #ifdef HAVE_INITGROUPS
57 #include <sys/types.h>
61 #include <sys/resource.h>
63 #ifdef POSIX1B_SCHEDULING
68 * Params sent by the peer.
77 struct param_struct params
[] =
81 { "display_auth", 0L },
84 { "xwindows_only", 0L },
88 /* obsoleted by app_startup_id { "app_start_pid", 0L } */
89 { "app_startup_id", 0L }
94 #define P_DISPLAY_AUTH 2
100 #define P_SCHEDULER 8
101 #define P_APP_STARTUP_ID 9
105 * Safe malloc functions.
107 char *xmalloc(size_t size
)
109 char *ptr
= malloc(size
);
116 char **xrealloc(char **ptr
, int size
)
118 ptr
= realloc(ptr
, size
);
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);
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);
146 if (dst
[len
-1] == '\n')
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)
162 list
= xrealloc(list
, (size
*= 2) * sizeof(char *));
183 char xauthority
[200];
185 char iceauthority
[200];
186 int i
/*, res, sycoca*/, prio
;
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
);
198 if (fgets(buf
, BUFSIZE
, stdin
) == 0L)
200 printf("end\n"); fflush(stdout
);
201 perror("kdesu_stub: fgets()");
204 params
[i
].value
= xstrdup(buf
);
205 /* Installation check? */
206 if ((i
== 0) && !strcmp(params
[i
].value
, "stop"))
212 printf("environment\n");
217 if (fgets(buf
, BUFSIZE
, stdin
) == 0L)
219 printf("end\n"); fflush(stdout
);
220 perror("kdesu_stub: fgets()");
223 tmp
= xstrdup( buf
);
224 if( tmp
[ 0 ] == '\0' ) /* terminator */
226 putenv( xstrdup( buf
));
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
);
241 /* Do we need to change uid? */
243 pw
= getpwnam(params
[P_USER
].value
);
246 printf("kdesu_stub: user %s does not exist!\n", params
[P_USER
].value
);
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
);
263 printf("kdesu_stub: realtime scheduling not supported\n");
267 #ifdef HAVE_SETPRIORITY
268 int val
= 20 - (int) (((double) prio
) * 40 / 100 + 0.5);
269 setpriority(PRIO_PROCESS
, getpid(), val
);
273 /* Drop privileges (this is permanent) */
275 if (getuid() != pw
->pw_uid
)
277 if (setgid(pw
->pw_gid
) == -1)
279 perror("kdesu_stub: setgid()");
282 #ifdef HAVE_INITGROUPS
283 if (initgroups(pw
->pw_name
, pw
->pw_gid
) == -1)
285 perror("kdesu_stub: initgroups()");
289 if (setuid(pw
->pw_uid
) == -1)
291 perror("kdesu_stub: setuid()");
294 xsetenv("HOME", pw
->pw_dir
);
299 if (strcmp(params
[P_DISPLAY
].value
, "no"))
302 xsetenv("DISPLAY", params
[P_DISPLAY
].value
);
303 if (params
[P_DISPLAY_AUTH
].value
[0])
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)
316 strcpy(xauthority
, "/tmp/xauth.XXXXXXXXXX");
317 fd2
= mkstemp(xauthority
);
321 perror("kdesu_stub: mkstemp()");
325 xsetenv("XAUTHORITY", xauthority
);
327 fout
= popen("xauth >/dev/null 2>&1","w");
330 perror("kdesu_stub: popen(xauth)");
333 fprintf(fout
, "add %s %s\n", disp
,
334 params
[P_DISPLAY_AUTH
].value
);
338 xsetenv("DISPLAY", params
[P_DISPLAY
].value
);
342 /* Rebuild the sycoca and start kdeinit? */
344 if (strcmp(params
[P_XWIN_ONLY
].value
, "no"))
346 system("kdeinit4 --suicide");
349 /* Execute the command */
354 perror("kdesu_stub: fork()");
359 /* Parent: wait for child, delete tempfiles and return. */
360 int ret
, state
, xit
= 1;
363 ret
= waitpid(pid
, &state
, 0);
369 perror("kdesu_stub: waitpid()");
372 if (WIFEXITED(state
))
373 xit
= WEXITSTATUS(state
);
379 unlink(iceauthority
);
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()");