Mon, 28 Jan 2013 17:37:18 +0100
Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.
michael@428 | 1 | /* |
michael@428 | 2 | ** openpkg.c -- OpenPKG Frontend |
michael@428 | 3 | ** Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/> |
michael@428 | 4 | ** |
michael@428 | 5 | ** This software is property of the OpenPKG GmbH, DE MUC HRB 160208. |
michael@428 | 6 | ** All rights reserved. Licenses which grant limited permission to use, |
michael@428 | 7 | ** copy, modify and distribute this software are available from the |
michael@428 | 8 | ** OpenPKG GmbH. |
michael@428 | 9 | ** |
michael@428 | 10 | ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
michael@428 | 11 | ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
michael@428 | 12 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
michael@428 | 13 | ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR |
michael@428 | 14 | ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@428 | 15 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@428 | 16 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
michael@428 | 17 | ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
michael@428 | 18 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
michael@428 | 19 | ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
michael@428 | 20 | ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
michael@428 | 21 | ** SUCH DAMAGE. |
michael@428 | 22 | */ |
michael@428 | 23 | |
michael@428 | 24 | /* program information */ |
michael@428 | 25 | #define LICENSE \ |
michael@428 | 26 | "Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>\n" \ |
michael@428 | 27 | "\n" \ |
michael@428 | 28 | "This software is property of the OpenPKG GmbH, DE MUC HRB 160208.\n" \ |
michael@428 | 29 | "All rights reserved. Licenses which grant limited permission to use,\n" \ |
michael@428 | 30 | "copy, modify and distribute this software are available from the\n" \ |
michael@428 | 31 | "OpenPKG GmbH.\n" \ |
michael@428 | 32 | "\n" \ |
michael@428 | 33 | "THIS SOFTWARE IS PROVIDED \"AS IS\" AND ANY EXPRESSED OR IMPLIED\n" \ |
michael@428 | 34 | "WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" \ |
michael@428 | 35 | "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" \ |
michael@428 | 36 | "IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR\n" \ |
michael@428 | 37 | "CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" \ |
michael@428 | 38 | "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" \ |
michael@428 | 39 | "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n" \ |
michael@428 | 40 | "USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" \ |
michael@428 | 41 | "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" \ |
michael@428 | 42 | "OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n" \ |
michael@428 | 43 | "OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" \ |
michael@428 | 44 | "SUCH DAMAGE.\n" |
michael@428 | 45 | |
michael@428 | 46 | /* system includes */ |
michael@428 | 47 | #include <stdio.h> |
michael@428 | 48 | #include <stdlib.h> |
michael@428 | 49 | #include <stdarg.h> |
michael@428 | 50 | #include <string.h> |
michael@428 | 51 | #include <sys/types.h> |
michael@428 | 52 | #include <sys/param.h> |
michael@428 | 53 | #include <sys/stat.h> |
michael@428 | 54 | #include <pwd.h> |
michael@428 | 55 | #include <grp.h> |
michael@428 | 56 | #include <unistd.h> |
michael@428 | 57 | #include <errno.h> |
michael@428 | 58 | |
michael@428 | 59 | /* sanity check compilation */ |
michael@428 | 60 | #ifndef OPENPKG_PREFIX |
michael@428 | 61 | #error OpenPKG instance prefix not defined |
michael@428 | 62 | #endif |
michael@428 | 63 | #ifndef OPENPKG_SUSR |
michael@428 | 64 | #error OpenPKG super user not defined |
michael@428 | 65 | #endif |
michael@428 | 66 | #ifndef OPENPKG_MUSR |
michael@428 | 67 | #error OpenPKG management user not defined |
michael@428 | 68 | #endif |
michael@428 | 69 | |
michael@428 | 70 | /* platform specifics */ |
michael@428 | 71 | #if defined(OPENPKG_PLATFORM_FREEBSD) || \ |
michael@428 | 72 | defined(OPENPKG_PLATFORM_NETBSD) || \ |
michael@428 | 73 | defined(OPENPKG_PLATFORM_OPENBSD) || \ |
michael@428 | 74 | defined(OPENPKG_PLATFORM_SUNOS) || \ |
michael@428 | 75 | defined(OPENPKG_PLATFORM_LINUX) || \ |
michael@428 | 76 | defined(OPENPKG_PLATFORM_DARWIN) || \ |
michael@428 | 77 | defined(OPENPKG_PLATFORM_AIX) || \ |
michael@428 | 78 | defined(OPENPKG_PLATFORM_IRIX) || \ |
michael@428 | 79 | defined(OPENPKG_PLATFORM_HPUX) |
michael@428 | 80 | #define HAVE_INITGROUPS |
michael@428 | 81 | #endif |
michael@428 | 82 | |
michael@428 | 83 | /* global debug enable flag */ |
michael@428 | 84 | static int debug_enable = 0; |
michael@428 | 85 | |
michael@428 | 86 | /* helper function: emulate (still less portable) setenv(3) via (more portable) putenv(3) */ |
michael@428 | 87 | static int my_setenv(const char *name, const char *value, int overwrite) |
michael@428 | 88 | { |
michael@428 | 89 | char *pair; |
michael@428 | 90 | |
michael@428 | 91 | if (overwrite == 0 && getenv(name) != NULL) |
michael@428 | 92 | return 0; |
michael@428 | 93 | if ((pair = malloc(strlen(name) + 1 + strlen(value) + 1)) == NULL) |
michael@428 | 94 | return -1; |
michael@428 | 95 | strcpy(pair, name); |
michael@428 | 96 | strcat(pair, "="); |
michael@428 | 97 | strcat(pair, value); |
michael@428 | 98 | putenv(pair); |
michael@428 | 99 | return 0; |
michael@428 | 100 | } |
michael@428 | 101 | |
michael@428 | 102 | /* helper function for printing a warning message */ |
michael@428 | 103 | static void warn(const char *fmt, ...) |
michael@428 | 104 | { |
michael@428 | 105 | va_list ap; |
michael@428 | 106 | |
michael@428 | 107 | va_start(ap, fmt); |
michael@428 | 108 | fprintf(stderr, "openpkg:WARNING: "); |
michael@428 | 109 | vfprintf(stderr, fmt, ap); |
michael@428 | 110 | fprintf(stderr, "\n"); |
michael@428 | 111 | va_end(ap); |
michael@428 | 112 | return; |
michael@428 | 113 | } |
michael@428 | 114 | |
michael@428 | 115 | /* helper function for printing a debug message */ |
michael@428 | 116 | static void debug(const char *fmt, ...) |
michael@428 | 117 | { |
michael@428 | 118 | va_list ap; |
michael@428 | 119 | |
michael@428 | 120 | va_start(ap, fmt); |
michael@428 | 121 | if (debug_enable) { |
michael@428 | 122 | fprintf(stderr, "openpkg:DEBUG: "); |
michael@428 | 123 | vfprintf(stderr, fmt, ap); |
michael@428 | 124 | fprintf(stderr, "\n"); |
michael@428 | 125 | } |
michael@428 | 126 | va_end(ap); |
michael@428 | 127 | return; |
michael@428 | 128 | } |
michael@428 | 129 | |
michael@428 | 130 | /* helper function for printing a fatal message and exit */ |
michael@428 | 131 | static void fatal(const char *fmt, ...) |
michael@428 | 132 | { |
michael@428 | 133 | va_list ap; |
michael@428 | 134 | |
michael@428 | 135 | va_start(ap, fmt); |
michael@428 | 136 | fprintf(stderr, "openpkg:ERROR: "); |
michael@428 | 137 | vfprintf(stderr, fmt, ap); |
michael@428 | 138 | fprintf(stderr, "\n"); |
michael@428 | 139 | va_end(ap); |
michael@428 | 140 | exit(1); |
michael@428 | 141 | return; |
michael@428 | 142 | } |
michael@428 | 143 | |
michael@428 | 144 | /* adjust process privileges */ |
michael@428 | 145 | static void adjust_privileges(uid_t uid, gid_t gid, int login) |
michael@428 | 146 | { |
michael@428 | 147 | struct passwd *pw; |
michael@428 | 148 | char cwd[MAXPATHLEN]; |
michael@428 | 149 | |
michael@428 | 150 | /* optionally emulate a more complete login */ |
michael@428 | 151 | if (login) { |
michael@428 | 152 | /* determine information about user id */ |
michael@428 | 153 | if ((pw = getpwuid(uid)) == NULL) |
michael@428 | 154 | fatal("unable to resolve user id \"%d\": %s", uid, strerror(errno)); |
michael@428 | 155 | |
michael@428 | 156 | /* reset some essential environment variables */ |
michael@428 | 157 | my_setenv("LOGNAME", pw->pw_name, 1); |
michael@428 | 158 | my_setenv("USER", pw->pw_name, 1); |
michael@428 | 159 | my_setenv("SHELL", pw->pw_shell, 1); |
michael@428 | 160 | my_setenv("HOME", pw->pw_dir, 1); |
michael@428 | 161 | |
michael@428 | 162 | #ifdef HAVE_INITGROUPS |
michael@428 | 163 | /* initialize complete group access list */ |
michael@428 | 164 | if (initgroups(pw->pw_name, pw->pw_gid) == -1) |
michael@428 | 165 | fatal("failed to initialize access group list via initgroups(3): %s", strerror(errno)); |
michael@428 | 166 | #endif |
michael@428 | 167 | } |
michael@428 | 168 | |
michael@428 | 169 | /* switch to group id (first) */ |
michael@428 | 170 | if (setgid(gid) == -1) |
michael@428 | 171 | fatal("failed to set group id via setgid(2): %s", strerror(errno)); |
michael@428 | 172 | |
michael@428 | 173 | /* switch to user id (second) */ |
michael@428 | 174 | if (setuid(uid) == -1) |
michael@428 | 175 | fatal("failed to set user id via setuid(2): %s", strerror(errno)); |
michael@428 | 176 | |
michael@428 | 177 | /* in case the current working directory is NO LONGER accessible, |
michael@428 | 178 | try to switch to the home directory of the target identity to |
michael@428 | 179 | prevent failures in subsequently called programs (e.g. GNU bash) */ |
michael@428 | 180 | if (login) { |
michael@428 | 181 | if (getcwd(cwd, sizeof(cwd)) == NULL) { |
michael@428 | 182 | warn("current working directory is no longer accessible -- switching to \"%s\"", pw->pw_dir); |
michael@428 | 183 | if (chdir(pw->pw_dir) == -1) |
michael@428 | 184 | fatal("unable to chdir(2) to \"%s\": %s", pw->pw_dir, strerror(errno)); |
michael@428 | 185 | } |
michael@428 | 186 | } |
michael@428 | 187 | |
michael@428 | 188 | return; |
michael@428 | 189 | } |
michael@428 | 190 | |
michael@428 | 191 | /* check whether caller is an explictly configured management user */ |
michael@428 | 192 | static int check_whether_is_manager(uid_t my_uid, gid_t my_gid, uid_t m_uid, gid_t m_gid) |
michael@428 | 193 | { |
michael@428 | 194 | char buf[1024]; |
michael@428 | 195 | char *username; |
michael@428 | 196 | char *groupname; |
michael@428 | 197 | char *filename; |
michael@428 | 198 | struct stat sb; |
michael@428 | 199 | char *cp; |
michael@428 | 200 | FILE *fp; |
michael@428 | 201 | struct passwd *pw; |
michael@428 | 202 | struct group *gr; |
michael@428 | 203 | int i; |
michael@428 | 204 | int ok_uid; |
michael@428 | 205 | int ok_gid; |
michael@428 | 206 | int is_manager; |
michael@428 | 207 | |
michael@428 | 208 | is_manager = 0; |
michael@428 | 209 | |
michael@428 | 210 | /* path to the managers configuration file */ |
michael@428 | 211 | filename = OPENPKG_PREFIX "/etc/openpkg/managers"; |
michael@428 | 212 | |
michael@428 | 213 | /* check permissions of file */ |
michael@428 | 214 | if (stat(filename, &sb) == -1) { |
michael@428 | 215 | warn("unable to determine information about configuration" |
michael@428 | 216 | " file \"%s\": %s -- ignoring file", filename, strerror(errno)); |
michael@428 | 217 | return 0; |
michael@428 | 218 | } |
michael@428 | 219 | if (sb.st_uid != m_uid) { |
michael@428 | 220 | warn("invalid owner user id %d (expected %d) on configuration" |
michael@428 | 221 | " file \"%s\" -- ignoring file", sb.st_uid, m_uid, filename); |
michael@428 | 222 | return 0; |
michael@428 | 223 | } |
michael@428 | 224 | if (sb.st_gid != m_gid) { |
michael@428 | 225 | warn("invalid owner group id %d (expected %d) on configuration" |
michael@428 | 226 | " file \"%s\" -- ignoring file", sb.st_gid, m_gid, filename); |
michael@428 | 227 | return 0; |
michael@428 | 228 | } |
michael@428 | 229 | if (sb.st_mode != (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)) { |
michael@428 | 230 | warn("invalid permissions on configuration" |
michael@428 | 231 | " file \"%s\" -- ignoring file", filename); |
michael@428 | 232 | return 0; |
michael@428 | 233 | } |
michael@428 | 234 | |
michael@428 | 235 | /* parse configuration file */ |
michael@428 | 236 | if ((fp = fopen(filename, "r")) == NULL) { |
michael@428 | 237 | warn("unable to open configuration file \"%s\": %s -- ignoring file", filename, strerror(errno)); |
michael@428 | 238 | return 0; |
michael@428 | 239 | } |
michael@428 | 240 | while ((cp = fgets(buf, sizeof(buf), fp)) != NULL) { |
michael@428 | 241 | /* parse entry as "<username>[:<groupname>]" where both |
michael@428 | 242 | <username> and <groupname> can be set and default to "*" |
michael@428 | 243 | to indicate an arbitrary user or group */ |
michael@428 | 244 | if ((i = strlen(buf)) == 0) { |
michael@428 | 245 | warn("unexpected empty buffer during parsing of configuration file \"%\"", filename); |
michael@428 | 246 | break; |
michael@428 | 247 | } |
michael@428 | 248 | if (i >= sizeof(buf)) { |
michael@428 | 249 | warn("unexpected buffer overflow during parsing of configuration file \"%\"", filename); |
michael@428 | 250 | break; |
michael@428 | 251 | } |
michael@428 | 252 | if (buf[i-1] != '\r' && buf[i-1] != '\n') { |
michael@428 | 253 | warn("unexpected non-newline-terminated line found during parsing of configuration file \"%\"", filename); |
michael@428 | 254 | break; |
michael@428 | 255 | } |
michael@428 | 256 | username = buf + strspn(buf, " \t"); |
michael@428 | 257 | cp = username + strcspn(username, " \t#\r\n"); |
michael@428 | 258 | *cp = '\0'; |
michael@428 | 259 | if (username[0] == '#' || username[0] == '\r' || username[0] == '\n' || username[0] == '\0') |
michael@428 | 260 | continue; |
michael@428 | 261 | groupname = "*"; |
michael@428 | 262 | if ((cp = strchr(username, ':')) != NULL) { |
michael@428 | 263 | *cp++ = '\0'; |
michael@428 | 264 | groupname = cp; |
michael@428 | 265 | } |
michael@428 | 266 | debug("parsing result: username=\"%s\" groupname=\"%s\"", username, groupname); |
michael@428 | 267 | |
michael@428 | 268 | /* check whether UID is ok */ |
michael@428 | 269 | ok_uid = 0; |
michael@428 | 270 | if (strcmp(username, "*") == 0) |
michael@428 | 271 | ok_uid = 1; |
michael@428 | 272 | else { |
michael@428 | 273 | if ((pw = getpwnam(username)) == NULL) { |
michael@428 | 274 | warn("invalid username \"%s\" in \"%s\"", username, filename); |
michael@428 | 275 | continue; |
michael@428 | 276 | } |
michael@428 | 277 | if (pw->pw_uid == my_uid) |
michael@428 | 278 | ok_uid = 1; |
michael@428 | 279 | } |
michael@428 | 280 | |
michael@428 | 281 | /* check whether GID is ok */ |
michael@428 | 282 | ok_gid = 0; |
michael@428 | 283 | if (strcmp(groupname, "*") == 0) |
michael@428 | 284 | ok_gid = 1; |
michael@428 | 285 | else { |
michael@428 | 286 | if ((gr = getgrnam(groupname)) == NULL) { |
michael@428 | 287 | warn("invalid groupname \"%s\" in \"%s\"", groupname, filename); |
michael@428 | 288 | continue; |
michael@428 | 289 | } |
michael@428 | 290 | if (gr->gr_gid == my_gid) |
michael@428 | 291 | ok_gid = 1; |
michael@428 | 292 | } |
michael@428 | 293 | |
michael@428 | 294 | /* if both UID and GID are ok, user is manager */ |
michael@428 | 295 | debug("matching: username ok = %s, groupname ok = %s", ok_uid ? "yes" : "no", ok_gid ? "yes" : "no"); |
michael@428 | 296 | if (ok_uid && ok_gid) { |
michael@428 | 297 | is_manager = 1; |
michael@428 | 298 | break; |
michael@428 | 299 | } |
michael@428 | 300 | } |
michael@428 | 301 | fclose(fp); |
michael@428 | 302 | return is_manager; |
michael@428 | 303 | } |
michael@428 | 304 | |
michael@428 | 305 | /* check whether command requires super-user privileges */ |
michael@428 | 306 | static int check_whether_require_superuser(int argc, char *argv[]) |
michael@428 | 307 | { |
michael@428 | 308 | int require_superuser; |
michael@428 | 309 | int i, j; |
michael@428 | 310 | |
michael@428 | 311 | require_superuser = 0; |
michael@428 | 312 | if (argc > 1 && strcmp(argv[1], "rpm") == 0) { |
michael@428 | 313 | for (i = 2; i < argc; i++) { |
michael@428 | 314 | if (strcmp(argv[i], "--") == 0) |
michael@428 | 315 | break; |
michael@428 | 316 | else if ( strcmp(argv[i], "--erase") == 0 |
michael@428 | 317 | || strcmp(argv[i], "--freshen") == 0 |
michael@428 | 318 | || strcmp(argv[i], "--install") == 0 |
michael@428 | 319 | || strcmp(argv[i], "--upgrade") == 0 |
michael@428 | 320 | || strcmp(argv[i], "--import") == 0 |
michael@428 | 321 | || strcmp(argv[i], "--initdb") == 0 |
michael@428 | 322 | || strcmp(argv[i], "--rebuilddb") == 0 |
michael@428 | 323 | || strcmp(argv[i], "--db-build") == 0 |
michael@428 | 324 | || strcmp(argv[i], "--db-rebuild") == 0 |
michael@428 | 325 | || strcmp(argv[i], "--db-cleanup") == 0 |
michael@428 | 326 | || strcmp(argv[i], "--db-fixate") == 0 |
michael@428 | 327 | || strcmp(argv[i], "--setperms") == 0 |
michael@428 | 328 | || strcmp(argv[i], "--setugids") == 0) { |
michael@428 | 329 | require_superuser = 1; |
michael@428 | 330 | break; |
michael@428 | 331 | } |
michael@428 | 332 | else if ( argv[i][0] == '-' |
michael@428 | 333 | && argv[i][1] != '-' |
michael@428 | 334 | && argv[i][1] != 'b' |
michael@428 | 335 | && argv[i][1] != 't' |
michael@428 | 336 | ) { |
michael@428 | 337 | for (j = 1; argv[i][j] != '\0'; j++) { |
michael@428 | 338 | if ( ( argv[i][j] == 'q' |
michael@428 | 339 | || argv[i][j] == 'K') |
michael@428 | 340 | && argv[i][j+1] != '\0') { |
michael@428 | 341 | j++; |
michael@428 | 342 | continue; |
michael@428 | 343 | } |
michael@428 | 344 | else if ( argv[i][j] == 'i' |
michael@428 | 345 | || argv[i][j] == 'U' |
michael@428 | 346 | || argv[i][j] == 'F' |
michael@428 | 347 | || argv[i][j] == 'V' |
michael@428 | 348 | || argv[i][j] == 'e') { |
michael@428 | 349 | require_superuser = 1; |
michael@428 | 350 | break; |
michael@428 | 351 | } |
michael@428 | 352 | } |
michael@428 | 353 | if (require_superuser) |
michael@428 | 354 | break; |
michael@428 | 355 | } |
michael@428 | 356 | } |
michael@428 | 357 | } |
michael@428 | 358 | else if (argc > 1 && strcmp(argv[1], "rc") == 0) { |
michael@428 | 359 | require_superuser = 1; |
michael@428 | 360 | for (i = 2; i < argc; i++) { |
michael@428 | 361 | if (strcmp(argv[i], "--") == 0) |
michael@428 | 362 | break; |
michael@428 | 363 | else if ( strcmp(argv[i], "-p") == 0 |
michael@428 | 364 | || strcmp(argv[i], "--print") == 0 |
michael@428 | 365 | || strcmp(argv[i], "-e") == 0 |
michael@428 | 366 | || strcmp(argv[i], "--eval") == 0 |
michael@428 | 367 | || strcmp(argv[i], "-q") == 0 |
michael@428 | 368 | || strcmp(argv[i], "--query") == 0 |
michael@428 | 369 | || strcmp(argv[i], "-c") == 0 |
michael@428 | 370 | || strcmp(argv[i], "--config") == 0) { |
michael@428 | 371 | require_superuser = 0; |
michael@428 | 372 | break; |
michael@428 | 373 | } |
michael@428 | 374 | } |
michael@428 | 375 | } |
michael@428 | 376 | return require_superuser; |
michael@428 | 377 | } |
michael@428 | 378 | |
michael@428 | 379 | /* main program */ |
michael@428 | 380 | int main(int argc, char **argv, char **envp) |
michael@428 | 381 | { |
michael@428 | 382 | int keep_original_privileges; |
michael@428 | 383 | int is_manager; |
michael@428 | 384 | int require_superuser; |
michael@428 | 385 | uid_t my_uid, my_euid; |
michael@428 | 386 | gid_t my_gid, my_egid; |
michael@428 | 387 | uid_t m_uid; |
michael@428 | 388 | gid_t m_gid; |
michael@428 | 389 | uid_t s_uid; |
michael@428 | 390 | gid_t s_gid; |
michael@428 | 391 | struct passwd *pw; |
michael@428 | 392 | struct group *gr; |
michael@428 | 393 | int dry_run; |
michael@428 | 394 | int license; |
michael@428 | 395 | |
michael@428 | 396 | /* parse command line options */ |
michael@428 | 397 | license = 0; |
michael@428 | 398 | dry_run = 0; |
michael@428 | 399 | keep_original_privileges = 0; |
michael@428 | 400 | if (argc <= 0) |
michael@428 | 401 | abort(); |
michael@428 | 402 | argv++; argc--; |
michael@428 | 403 | while (argc > 0) { |
michael@428 | 404 | if (argv[0][0] != '-') |
michael@428 | 405 | break; |
michael@428 | 406 | else if (strcmp(argv[0], "--") == 0) { |
michael@428 | 407 | argv++; argc--; |
michael@428 | 408 | break; |
michael@428 | 409 | } |
michael@428 | 410 | else if (strcmp(argv[0], "--license") == 0) { |
michael@428 | 411 | license = 1; |
michael@428 | 412 | argv++; argc--; |
michael@428 | 413 | continue; |
michael@428 | 414 | } |
michael@428 | 415 | else if (strcmp(argv[0], "--debug") == 0) { |
michael@428 | 416 | debug_enable = 1; |
michael@428 | 417 | argv++; argc--; |
michael@428 | 418 | continue; |
michael@428 | 419 | } |
michael@428 | 420 | else if (strcmp(argv[0], "--dry-run") == 0) { |
michael@428 | 421 | dry_run = 1; |
michael@428 | 422 | argv++; argc--; |
michael@428 | 423 | continue; |
michael@428 | 424 | } |
michael@428 | 425 | else if (strcmp(argv[0], "--keep-privileges") == 0) { |
michael@428 | 426 | keep_original_privileges = 1; |
michael@428 | 427 | argv++; argc--; |
michael@428 | 428 | continue; |
michael@428 | 429 | } |
michael@428 | 430 | break; |
michael@428 | 431 | } |
michael@428 | 432 | argv--; argc++; |
michael@428 | 433 | |
michael@428 | 434 | /* display stand-alone license information */ |
michael@428 | 435 | if (license) { |
michael@428 | 436 | fprintf(stdout, "%s", LICENSE); |
michael@428 | 437 | exit(0); |
michael@428 | 438 | } |
michael@428 | 439 | |
michael@428 | 440 | /* determine our current real and effective user/group ids */ |
michael@428 | 441 | my_uid = getuid(); |
michael@428 | 442 | my_gid = getgid(); |
michael@428 | 443 | my_euid = geteuid(); |
michael@428 | 444 | my_egid = getegid(); |
michael@428 | 445 | if ((pw = getpwuid(my_uid)) == NULL) |
michael@428 | 446 | fatal("unable to resolve current user id %d: %s", my_uid, strerror(errno)); |
michael@428 | 447 | if ((gr = getgrgid(my_gid)) == NULL) |
michael@428 | 448 | fatal("unable to resolve current group id %d: %s", my_gid, strerror(errno)); |
michael@428 | 449 | debug("current-user: usr=%s uid=%d euid=%d grp=%s gid=%d egid=%d", |
michael@428 | 450 | pw->pw_name, my_uid, my_euid, gr->gr_name, my_gid, my_egid); |
michael@428 | 451 | |
michael@428 | 452 | /* determine super user/group id */ |
michael@428 | 453 | if ((pw = getpwnam(OPENPKG_SUSR)) == NULL) |
michael@428 | 454 | fatal("unable to resolve OpenPKG superuser username \"%s\": %s", OPENPKG_SUSR, strerror(errno)); |
michael@428 | 455 | s_uid = pw->pw_uid; |
michael@428 | 456 | s_gid = pw->pw_gid; |
michael@428 | 457 | debug("super-user: s_usr=%s s_uid=%d s_gid=%d", OPENPKG_SUSR, s_uid, s_gid); |
michael@428 | 458 | |
michael@428 | 459 | /* determine management user/group id */ |
michael@428 | 460 | if ((pw = getpwnam(OPENPKG_MUSR)) == NULL) |
michael@428 | 461 | fatal("unable to resolve OpenPKG management username \"%s\": %s", OPENPKG_MUSR, strerror(errno)); |
michael@428 | 462 | m_uid = pw->pw_uid; |
michael@428 | 463 | m_gid = pw->pw_gid; |
michael@428 | 464 | debug("management-user: m_grp=%s m_uid=%d m_gid=%d", OPENPKG_MUSR, m_uid, m_gid); |
michael@428 | 465 | |
michael@428 | 466 | /* determine whether caller is explicitly configured as a management user */ |
michael@428 | 467 | is_manager = 0; |
michael@428 | 468 | if (!keep_original_privileges) |
michael@428 | 469 | is_manager = check_whether_is_manager(my_uid, my_gid, m_uid, m_gid); |
michael@428 | 470 | debug("current user is manager: %s", is_manager ? "yes" : "no"); |
michael@428 | 471 | |
michael@428 | 472 | /* determine whether command requires super-user privileges */ |
michael@428 | 473 | require_superuser = check_whether_require_superuser(argc, argv); |
michael@428 | 474 | debug("current command requires super user privileges: %s", require_superuser ? "yes" : "no"); |
michael@428 | 475 | |
michael@428 | 476 | /* adjust privileges according to determined information */ |
michael@428 | 477 | if (!keep_original_privileges && require_superuser && is_manager && my_euid == 0) { |
michael@428 | 478 | /* increase privileges to super user */ |
michael@428 | 479 | debug("increase privileges to super user"); |
michael@428 | 480 | adjust_privileges(s_uid, s_gid, 1); |
michael@428 | 481 | } |
michael@428 | 482 | else if (!keep_original_privileges && !require_superuser && is_manager && my_euid == 0) { |
michael@428 | 483 | /* decrease privileges to management user */ |
michael@428 | 484 | debug("decrease privileges to management user"); |
michael@428 | 485 | adjust_privileges(m_uid, m_gid, 1); |
michael@428 | 486 | } |
michael@428 | 487 | else /* keep_original_privileges || !is_manager */ { |
michael@428 | 488 | /* drop effective privileges for current user*/ |
michael@428 | 489 | debug("drop effective privileges for current user"); |
michael@428 | 490 | adjust_privileges(my_uid, my_gid, 0); |
michael@428 | 491 | } |
michael@428 | 492 | |
michael@428 | 493 | /* pass-through control to real Execution Frontend (shell script) */ |
michael@428 | 494 | argv[0] = OPENPKG_PREFIX "/lib/openpkg/openpkg"; |
michael@428 | 495 | debug("execute \"%s\"", argv[0]); |
michael@428 | 496 | if (!dry_run) { |
michael@428 | 497 | if (execve(argv[0], argv, envp) == -1) |
michael@428 | 498 | fatal("failed to execute \"%s\": %s", argv[0], strerror(errno)); |
michael@428 | 499 | /* NOT REACHED */ |
michael@428 | 500 | fatal("INTERNAL ERROR"); |
michael@428 | 501 | } |
michael@428 | 502 | return 0; |
michael@428 | 503 | } |
michael@428 | 504 |