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