Home | History | Annotate | Download | only in ltrace
      1 /*
      2  * This file is part of ltrace.
      3  * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
      4  * Copyright (C) 2010 Joe Damato
      5  * Copyright (C) 1998,1999,2003,2008,2009 Juan Cespedes
      6  * Copyright (C) 2006 Ian Wienand
      7  *
      8  * This program is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU General Public License as
     10  * published by the Free Software Foundation; either version 2 of the
     11  * License, or (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful, but
     14  * WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     21  * 02110-1301 USA
     22  */
     23 #include "config.h"
     24 
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <sys/types.h>
     28 #include <sys/stat.h>
     29 #include <unistd.h>
     30 #include <errno.h>
     31 #include <string.h>
     32 #include <pwd.h>
     33 #include <grp.h>
     34 
     35 #include "backend.h"
     36 #include "options.h"
     37 #include "debug.h"
     38 
     39 static void
     40 change_uid(const char * command)
     41 {
     42 	uid_t run_uid, run_euid;
     43 	gid_t run_gid, run_egid;
     44 
     45 	if (options.user) {
     46 		struct passwd *pent;
     47 
     48 		if (getuid() != 0 || geteuid() != 0) {
     49 			fprintf(stderr,
     50 				"you must be root to use the -u option\n");
     51 			exit(1);
     52 		}
     53 		if ((pent = getpwnam(options.user)) == NULL) {
     54 			fprintf(stderr, "cannot find user `%s'\n", options.user);
     55 			exit(1);
     56 		}
     57 		run_uid = pent->pw_uid;
     58 		run_gid = pent->pw_gid;
     59 
     60 		if (initgroups(options.user, run_gid) < 0) {
     61 			perror("ltrace: initgroups");
     62 			exit(1);
     63 		}
     64 	} else {
     65 		run_uid = getuid();
     66 		run_gid = getgid();
     67 	}
     68 	if (options.user || !geteuid()) {
     69 		struct stat statbuf;
     70 		run_euid = run_uid;
     71 		run_egid = run_gid;
     72 
     73 		if (!stat(command, &statbuf)) {
     74 			if (statbuf.st_mode & S_ISUID) {
     75 				run_euid = statbuf.st_uid;
     76 			}
     77 			if (statbuf.st_mode & S_ISGID) {
     78 				run_egid = statbuf.st_gid;
     79 			}
     80 		}
     81 		if (setregid(run_gid, run_egid) < 0) {
     82 			perror("ltrace: setregid");
     83 			exit(1);
     84 		}
     85 		if (setreuid(run_uid, run_euid) < 0) {
     86 			perror("ltrace: setreuid");
     87 			exit(1);
     88 		}
     89 	}
     90 }
     91 
     92 pid_t
     93 execute_program(const char * command, char **argv)
     94 {
     95 	pid_t pid;
     96 
     97 	debug(1, "Executing `%s'...", command);
     98 
     99 	pid = fork();
    100 	if (pid < 0) {
    101 	fail:
    102 		perror("ltrace: fork");
    103 		exit(1);
    104 	} else if (!pid) {	/* child */
    105 		change_uid(command);
    106 		trace_me();
    107 		execvp(command, argv);
    108 		fprintf(stderr, "Can't execute `%s': %s\n", command,
    109 			strerror(errno));
    110 		_exit(1);
    111 	}
    112 
    113 	if (wait_for_proc(pid) < 0)
    114 		goto fail;
    115 
    116 	debug(1, "PID=%d", pid);
    117 	return pid;
    118 }
    119