Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / tools / wrapper.c
1 /*
2 ** Copyright (C) 2000 by Kevin L. Mitchell <klmitch@mit.edu>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License as published by
6 ** the Free Software Foundation; either version 2 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU General Public License for more details.
13 **
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 **
18 ** @(#)$Id$
19 */
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/resource.h>
28 #include <unistd.h>
29
30 /*
31  * Try and find the correct name to use with getrlimit() for setting the max.
32  * number of files allowed to be open by this process.
33  *
34  * Shamelessly stolen from ircu...
35  */
36 #ifdef RLIMIT_FDMAX
37 #define RLIMIT_FD_MAX RLIMIT_FDMAX
38 #else
39 #ifdef RLIMIT_NOFILE
40 #define RLIMIT_FD_MAX RLIMIT_NOFILE
41 #else
42 #ifdef RLIMIT_OPEN_MAX
43 #define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
44 #else
45 #error Unable to find a valid RLIMIT_FD_MAX
46 #endif
47 #endif
48 #endif
49
50 /*
51  * Set the hard and soft limits for maximum file descriptors.
52  */
53 int
54 set_fdlimit(unsigned int max_descriptors)
55 {
56   struct rlimit limit;
57
58   limit.rlim_max = limit.rlim_cur = max_descriptors;
59
60   return setrlimit(RLIMIT_FD_MAX, &limit);
61 }
62
63 /*
64  * Change directories to the indicated root directory, then make it the
65  * root directory.
66  */
67 int
68 change_root(char *root)
69 {
70   if (chdir(root))
71     return -1;
72   if (chroot(root))
73     return -1;
74
75   return 0;
76 }
77
78 /*
79  * Change the user and group ids--including supplementary groups!--as
80  * appropriate.
81  */
82 int
83 change_user(char *user, char *group)
84 {
85   struct passwd *pwd;
86   struct group *grp;
87   char *tmp;
88   int uid, gid;
89
90   /* Track down a struct passwd describing the desired user */
91   uid = strtol(user, &tmp, 10); /* was the user given as a number? */
92   if (*tmp) { /* strtol() failed to parse; look up as a user name */
93     if (!(pwd = getpwnam(user)))
94       return -1;
95   } else if (!(pwd = getpwuid(uid))) /* look up uid */
96       return -1;
97
98   uid = pwd->pw_uid; /* uid to change to */
99   gid = pwd->pw_gid; /* default gid for user */
100
101   if (group) { /* a group was specified; track down struct group */
102     gid = strtol(group, &tmp, 10); /* was the group given as a number? */
103     if (*tmp) { /* strtol() failed to parse; look up as a group name */
104       if (!(grp = getgrnam(group)))
105         return -1;
106     } else if (!(grp = getgrgid(gid))) /* look up gid */
107       return -1;
108
109     gid = grp->gr_gid; /* set the gid */
110   }
111
112   if (initgroups(pwd->pw_name, gid)) /* initialize supplementary groups */
113     return -1;
114   if (setgid(gid)) /* change our current group */
115     return -1;
116   if (setuid(uid)) /* change our current user */
117     return -1;
118
119   return 0; /* success! */
120 }
121
122 /*
123  * Explain how to use this program.
124  */
125 void
126 usage(char *prog, int retval)
127 {
128   fprintf(stderr, "Usage: %s [-u <user>] [-g <group>] [-l <limit>] [-c <root>]"
129           " -- \\\n\t\t<cmd> [<cmdargs>]\n", prog);
130   fprintf(stderr, "       %s -h\n", prog);
131
132   exit(retval);
133 }
134
135 int
136 main(int argc, char **argv)
137 {
138   int c, limit = -1;
139   char *prog, *user = 0, *group = 0, *root = 0;
140
141   /* determine program name for error reporting */
142   if ((prog = strrchr(argv[0], '/')))
143     prog++;
144   else
145     prog = argv[0];
146
147   /* process command line arguments */
148   while ((c = getopt(argc, argv, "hu:g:l:c:")) > 0)
149     switch (c) {
150     case 'h': /* requested help */
151       usage(prog, 0);
152       break;
153
154     case 'u': /* suggested a user */
155       user = optarg;
156       break;
157
158     case 'g': /* suggested a group */
159       group = optarg;
160       break;
161
162     case 'l': /* file descriptor limit */
163       limit = strtol(optarg, 0, 10);
164       break;
165
166     case 'c': /* select a root directory */
167       root = optarg;
168       break;
169
170     default: /* unknown command line argument */
171       usage(prog, 1);
172       break;
173     }
174
175   /* Not enough arguments; we must have a command to execute! */
176   if (optind >= argc)
177     usage(prog, 1);
178
179   if (limit > 0) /* set the requested fd limit */
180     if (set_fdlimit(limit) < 0) {
181       perror(prog);
182       return 1;
183     }
184
185   if (root) /* change root directories */
186     if (change_root(root)) {
187       perror(prog);
188       return 1;
189     }
190
191   if (user) /* change to selected user account */
192     if (change_user(user, group)) {
193       perror(prog);
194       return 1;
195     }
196
197   /* execute the requested command */
198   execvp(argv[optind], argv + optind);
199
200   /* If we got here, execvp() failed; report the error */
201   perror(prog);
202   return 1;
203 }