rpm-fake-resolver.c (7066B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 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; version 2 of the License. 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 19 // Protocol: 20 // 1. startup 21 // 2. initialize (setuid, ctx-migrate, chroot, ...) 22 // 3. send "." token to fd 3 23 // 4. wait one character on fd 1 24 // 5. process this character and consume further characters from fd 1 as far 25 // as needed 26 // 6. go to 3) (or exit) 27 28 #ifdef HAVE_CONFIG_H 29 # include <config.h> 30 #endif 31 32 #include "internal.h" 33 #include "vserver.h" 34 #include "util.h" 35 36 #include <getopt.h> 37 #include <stdlib.h> 38 #include <stdbool.h> 39 #include <grp.h> 40 #include <pwd.h> 41 #include <fcntl.h> 42 #include <errno.h> 43 44 #define ENSC_WRAPPERS_PREFIX "rpm-fake-resolver: " 45 #define ENSC_WRAPPERS_VSERVER 1 46 #define ENSC_WRAPPERS_UNISTD 1 47 #define ENSC_WRAPPERS_IO 1 48 #define ENSC_WRAPPERS_FCNTL 1 49 #include <wrappers.h> 50 51 #define MAX_RQSIZE 0x1000 52 53 int wrapper_exit_code = 1; 54 55 struct ArgInfo { 56 xid_t ctx; 57 uid_t uid; 58 gid_t gid; 59 bool do_fork; 60 bool in_ctx; 61 char const * pid_file; 62 char const * chroot; 63 uint32_t caps; 64 int flags; 65 }; 66 67 static struct option const 68 CMDLINE_OPTIONS[] = { 69 { "help", no_argument, 0, 'h' }, 70 { "version", no_argument, 0, 'v' }, 71 { 0,0,0,0 } 72 }; 73 74 static void 75 showHelp(int fd, char const *cmd, int res) 76 { 77 WRITE_MSG(fd, "Usage: "); 78 WRITE_STR(fd, cmd); 79 WRITE_MSG(fd, 80 " [-c <ctx>] [-u <uid>] [-g <gid>] [-r <chroot>] [-s] [-n]\n" 81 "Please report bugs to " PACKAGE_BUGREPORT "\n"); 82 exit(res); 83 } 84 85 static void 86 showVersion() 87 { 88 WRITE_MSG(1, 89 "rpm-fake-resolver " VERSION " -- NSS resovler for rpm-fake\n" 90 "This program is part of " PACKAGE_STRING "\n\n" 91 "Copyright (C) 2003 Enrico Scholz\n" 92 VERSION_COPYRIGHT_DISCLAIMER); 93 exit(0); 94 } 95 96 97 inline static void 98 parseArgs(struct ArgInfo *args, int argc, char *argv[]) 99 { 100 while (1) { 101 int c = getopt_long(argc, argv, "F:C:c:u:g:r:ns", CMDLINE_OPTIONS, 0); 102 if (c==-1) break; 103 104 switch (c) { 105 case 'h' : showHelp(1, argv[0], 0); 106 case 'v' : showVersion(); 107 108 case 'c' : args->ctx = atoi(optarg); break; 109 case 'u' : args->uid = atoi(optarg); break; 110 case 'g' : args->gid = atoi(optarg); break; 111 case 'F' : args->flags = atoi(optarg); break; 112 case 'C' : args->caps = atoi(optarg); break; 113 case 'r' : args->chroot = optarg; break; 114 case 'n' : args->do_fork = false; break; 115 case 's' : args->in_ctx = true; break; 116 default : 117 WRITE_MSG(2, "Try '"); 118 WRITE_STR(2, argv[0]); 119 WRITE_MSG(2, " --help' for more information.\n"); 120 exit(1); 121 break; 122 } 123 } 124 125 if (optind!=argc) { 126 WRITE_MSG(2, "No further options allowed; aborting ...\n"); 127 exit(1); 128 } 129 130 if (args->chroot==0) { 131 WRITE_MSG(2, "No chroot specified; aborting...\n"); 132 exit(1); 133 } 134 } 135 136 static void 137 sendResult(bool state, uint32_t res) 138 { 139 if (state) { 140 static uint8_t ONE = 1; 141 Ewrite(1, &ONE, sizeof ONE); 142 } 143 else { 144 static uint8_t ZERO = 0; 145 Ewrite(1, &ZERO, sizeof ZERO); 146 } 147 148 Ewrite(1, &res, sizeof res); 149 } 150 151 static void 152 do_getpwnam() 153 { 154 uint32_t len; 155 156 if (EreadAll(0, &len, sizeof len) && 157 len<MAX_RQSIZE) { 158 char buf[len+1]; 159 struct passwd * res = 0; 160 161 if (EreadAll(0, buf, len)) { 162 buf[len] = '\0'; 163 res = getpwnam(buf); 164 } 165 166 if (res!=0) sendResult(true, res->pw_uid); 167 else sendResult(false, -1); 168 } 169 // TODO: logging 170 } 171 172 static void 173 do_getgrnam() 174 { 175 uint32_t len; 176 177 if (EreadAll(0, &len, sizeof len) && 178 len<MAX_RQSIZE) { 179 char buf[len+1]; 180 struct group * res = 0; 181 182 if (EreadAll(0, buf, len)) { 183 buf[len] = '\0'; 184 res = getgrnam(buf); 185 } 186 187 if (res!=0) sendResult(true, res->gr_gid); 188 else sendResult(false, -1); 189 } 190 // TODO: logging 191 } 192 193 static void 194 do_closenss() 195 { 196 uint8_t what; 197 198 if (EreadAll(0, &what, sizeof what)) { 199 switch (what) { 200 case 'p' : endpwent(); break; 201 case 'g' : endgrent(); break; 202 default : break; 203 } 204 } 205 } 206 207 static void 208 run() 209 { 210 uint8_t c; 211 212 while (EwriteAll(3, ".", 1), 213 EreadAll (0, &c, sizeof c)) { 214 switch (c) { 215 case 'P' : do_getpwnam(); break; 216 case 'G' : do_getgrnam(); break; 217 case 'Q' : exit(0); 218 case 'C' : do_closenss(); break; 219 case '.' : Ewrite(1, ".", 1); break; 220 default : Ewrite(1, "?", 1); break; 221 } 222 } 223 } 224 225 static void 226 daemonize(struct ArgInfo const UNUSED * args, int pid_fd) 227 { 228 int p[2]; 229 pid_t pid; 230 char c; 231 232 Epipe(p); 233 pid = Efork(); 234 235 if (pid!=0) { 236 if (pid_fd!=-1) { 237 char buf[sizeof(id_t)*3 + 2]; 238 size_t l; 239 240 l = utilvserver_fmt_uint(buf, pid); 241 Ewrite(pid_fd, buf, l); 242 Ewrite(pid_fd, "\n", 1); 243 } 244 _exit(0); 245 } 246 Eclose(p[1]); 247 TEMP_FAILURE_RETRY(read(p[0], &c, 1)); 248 Eclose(p[0]); 249 } 250 251 static void 252 activateContext(xid_t xid, bool in_ctx, 253 uint32_t UNUSED xid_caps, int UNUSED xid_flags) 254 { 255 if (in_ctx) { 256 struct vc_ctx_flags flags = { 257 .flagword = 0, 258 .mask = VC_VXF_STATE_SETUP, 259 }; 260 261 Evc_set_cflags(xid, &flags); 262 } 263 else if (vc_isSupported(vcFEATURE_MIGRATE)) 264 Evc_ctx_migrate(xid, 0); 265 else { 266 #ifdef VC_ENABLE_API_COMPAT 267 Evc_new_s_context(xid, xid_caps, xid_flags); 268 #else 269 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not change context: migrate kernel feature missing and 'compat' API disabled\n"); 270 exit(wrapper_exit_code); 271 #endif 272 } 273 } 274 275 int main(int argc, char * argv[]) 276 { 277 struct ArgInfo args = { 278 .ctx = VC_DYNAMIC_XID, 279 .uid = 99, 280 .gid = 99, 281 .do_fork = true, 282 .pid_file = 0, 283 .chroot = 0, 284 .in_ctx = false, 285 .flags = S_CTX_INFO_LOCK, 286 }; 287 int pid_fd = -1; 288 289 #ifdef __GLIBC__ 290 # warning *** rpm-fake-resolver is built against glibc; please do not report errors before trying a dietlibc version *** 291 WRITE_MSG(2, 292 "*** rpm-fake-resolver was built with glibc; please do ***\n" 293 "*** not report errors before trying a dietlibc version. ***\n"); 294 #endif 295 296 parseArgs(&args, argc, argv); 297 if (args.pid_file && args.do_fork) 298 pid_fd = EopenD(args.pid_file, O_CREAT|O_WRONLY, 0644); 299 300 if (args.chroot) Echroot(args.chroot); 301 Echdir("/"); 302 303 activateContext(args.ctx, args.in_ctx, args.caps, args.flags); 304 Esetgroups(0, &args.gid); 305 Esetgid(args.gid); 306 Esetuid(args.uid); 307 308 if (args.do_fork) daemonize(&args, pid_fd); 309 if (pid_fd!=-1) close(pid_fd); 310 run(); 311 }