ircu2.10.12 pk910 fork
[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: wrapper.c,v 1.3 2004/05/15 14:50:09 entrope Exp $
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 /*fix for change uid/gid with chroot #ubra 08/02/03*/
51 int uid, gid;
52
53 /*
54  * Set the hard and soft limits for maximum file descriptors.
55  */
56 int
57 set_fdlimit(unsigned int max_descriptors)
58 {
59   struct rlimit limit;
60
61   limit.rlim_max = limit.rlim_cur = max_descriptors;
62
63   return setrlimit(RLIMIT_FD_MAX, &limit);
64 }
65
66 /*
67  * Change directories to the indicated root directory, then make it the
68  * root directory.
69  */
70 int
71 change_root(char *root)
72 {
73   if (chdir(root))
74     return -1;
75   if (chroot(root))
76     return -1;
77
78   return 0;
79 }
80
81 /*
82  * Change the user and group ids--including supplementary groups!--as
83  * appropriate.
84  *
85  * fix for change uid/gid with chroot #ubra 08/02/03
86  * old change_user() got splited into get_user() and set_user()
87  */
88 int
89 get_user(char *user, char *group)
90 {
91   struct passwd *pwd;
92   struct group *grp;
93   char *tmp;
94
95   /* Track down a struct passwd describing the desired user */
96   uid = strtol(user, &tmp, 10); /* was the user given as a number? */
97   if (*tmp) { /* strtol() failed to parse; look up as a user name */
98     if (!(pwd = getpwnam(user)))
99       return -1;
100   } else if (!(pwd = getpwuid(uid))) /* look up uid */
101       return -1;
102
103   uid = pwd->pw_uid; /* uid to change to */
104   gid = pwd->pw_gid; /* default gid for user */
105
106   if (group) { /* a group was specified; track down struct group */
107     gid = strtol(group, &tmp, 10); /* was the group given as a number? */
108     if (*tmp) { /* strtol() failed to parse; look up as a group name */
109       if (!(grp = getgrnam(group)))
110         return -1;
111     } else if (!(grp = getgrgid(gid))) /* look up gid */
112       return -1;
113
114     gid = grp->gr_gid; /* set the gid */
115   }
116
117   if (initgroups(pwd->pw_name, gid)) /* initialize supplementary groups */
118     return -1;
119   return 0; /* success! */
120 }
121
122 int
123 set_user(void) {
124   if (setgid(gid)) /* change our current group */
125     return -1;
126   if (setuid(uid)) /* change our current user */
127     return -1;
128
129   return 0; /* success! */
130 }
131
132 /*
133  * Explain how to use this program.
134  */
135 void
136 usage(char *prog, int retval)
137 {
138   fprintf(stderr, "Usage: %s [-u <user>] [-g <group>] [-l <limit>] [-c <root>]"
139           " -- \\\n\t\t<cmd> [<cmdargs>]\n", prog);
140   fprintf(stderr, "       %s -h\n", prog);
141
142   exit(retval);
143 }
144
145 int
146 main(int argc, char **argv)
147 {
148   int c, limit = -1;
149   char *prog, *user = 0, *group = 0, *root = 0;
150
151   /* determine program name for error reporting */
152   if ((prog = strrchr(argv[0], '/')))
153     prog++;
154   else
155     prog = argv[0];
156
157   /* process command line arguments */
158   while ((c = getopt(argc, argv, "hu:g:l:c:")) > 0)
159     switch (c) {
160     case 'h': /* requested help */
161       usage(prog, 0);
162       break;
163
164     case 'u': /* suggested a user */
165       user = optarg;
166       break;
167
168     case 'g': /* suggested a group */
169       group = optarg;
170       break;
171
172     case 'l': /* file descriptor limit */
173       limit = strtol(optarg, 0, 10);
174       break;
175
176     case 'c': /* select a root directory */
177       root = optarg;
178       break;
179
180     default: /* unknown command line argument */
181       usage(prog, 1);
182       break;
183     }
184
185   /* Not enough arguments; we must have a command to execute! */
186   if (optind >= argc)
187     usage(prog, 1);
188
189   if (limit > 0) /* set the requested fd limit */
190     if (set_fdlimit(limit) < 0) {
191       perror(prog);
192       return 1;
193     }
194
195   if(user) /* get the selected user account uid/gid*/
196    if (get_user(user, group)) {
197      perror(prog);
198      return 1;
199    }
200
201
202   if (root) /* change root directories */
203     if (change_root(root)) {
204       perror(prog);
205       return 1;
206     }
207
208   if (user) /* change to selected user account */
209     if (set_user()) {
210       perror(prog);
211       return 1;
212     }
213
214   /* execute the requested command */
215   execvp(argv[optind], argv + optind);
216
217   /* If we got here, execvp() failed; report the error */
218   perror(prog);
219   return 1;
220 }