int pseudo_client_chroot(const char *path) { /* free old value */ free(pseudo_chroot); pseudo_debug(2, "client chroot: %s\n", path); if (!strcmp(path, "/")) { pseudo_chroot_len = 0; pseudo_chroot = 0; pseudo_set_value("PSEUDO_CHROOT", NULL); return 0; } /* allocate new value */ pseudo_chroot_len = strlen(path); pseudo_chroot = malloc(pseudo_chroot_len + 1); if (!pseudo_chroot) { pseudo_diag("Couldn't allocate chroot directory buffer.\n"); pseudo_chroot_len = 0; errno = ENOMEM; return -1; } memcpy(pseudo_chroot, path, pseudo_chroot_len + 1); pseudo_set_value("PSEUDO_CHROOT", pseudo_chroot); return 0; }
void pseudo_client_touchgid(void) { static char gidbuf[256]; snprintf(gidbuf, 256, "%d,%d,%d,%d", pseudo_rgid, pseudo_egid, pseudo_sgid, pseudo_fgid); pseudo_set_value("PSEUDO_GIDS", gidbuf); }
void pseudo_client_touchuid(void) { static char uidbuf[256]; snprintf(uidbuf, 256, "%d,%d,%d,%d", pseudo_ruid, pseudo_euid, pseudo_suid, pseudo_fuid); pseudo_set_value("PSEUDO_UIDS", uidbuf); }
/* spawn server */ static int client_spawn_server(void) { int status; FILE *fp; char * pseudo_pidfile; if ((server_pid = fork()) != 0) { if (server_pid == -1) { pseudo_diag("couldn't fork server: %s\n", strerror(errno)); return 1; } pseudo_debug(4, "spawned server, pid %d\n", server_pid); /* wait for the child process to terminate, indicating server * is ready */ waitpid(server_pid, &status, 0); server_pid = -2; pseudo_pidfile = pseudo_localstatedir_path(PSEUDO_PIDFILE); fp = fopen(pseudo_pidfile, "r"); if (fp) { if (fscanf(fp, "%d", &server_pid) != 1) { pseudo_debug(1, "Opened server PID file, but didn't get a pid.\n"); } fclose(fp); } else { pseudo_debug(1, "no pid file (%s): %s\n", pseudo_pidfile, strerror(errno)); } pseudo_debug(2, "read new pid file: %d\n", server_pid); free(pseudo_pidfile); /* at this point, we should have a new server_pid */ return 0; } else { char *base_args[] = { NULL, NULL, NULL }; char **argv; char *option_string = pseudo_get_value("PSEUDO_OPTS"); int args; int fd; pseudo_new_pid(); base_args[0] = pseudo_bindir_path("pseudo"); base_args[1] = "-d"; if (option_string) { char *s; int arg; /* count arguments in PSEUDO_OPTS, starting at 2 * for pseudo/-d/NULL, plus one for the option string. * The number of additional arguments may be less * than the number of spaces, but can't be more. */ args = 4; for (s = option_string; *s; ++s) if (*s == ' ') ++args; argv = malloc(args * sizeof(char *)); argv[0] = base_args[0]; argv[1] = base_args[1]; arg = 2; while ((s = strsep(&option_string, " ")) != NULL) { if (*s) { argv[arg++] = strdup(s); } } argv[arg] = 0; } else { argv = base_args; } /* close any higher-numbered fds which might be open, * such as sockets. We don't have to worry about 0 and 1; * the server closes them already, and more importantly, * they can't have been opened or closed without us already * having spawned a server... The issue is just socket() * calls which could result in fds being left open, and those * can't overwrite fds 0-2 unless we closed them... * * No, really. It works. */ for (fd = 3; fd < 1024; ++fd) { if (fd != pseudo_util_debug_fd) close(fd); } /* and now, execute the server */ pseudo_set_value("PSEUDO_RELOADED", "YES"); pseudo_setupenv(); pseudo_dropenv(); /* drop PRELINK_LIBRARIES */ pseudo_debug(4, "calling execv on %s\n", argv[0]); execv(argv[0], argv); pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno)); exit(1); } }
void pseudo_init_client(void) { char *env; pseudo_antimagic(); pseudo_new_pid(); if (connect_fd != -1) { close(connect_fd); connect_fd = -1; } /* in child processes, PSEUDO_DISABLED may have become set to * some truthy value, in which case we'd disable pseudo, * or it may have gone away, in which case we'd enable * pseudo (and cause it to reinit the defaults). */ env = getenv("PSEUDO_DISABLED"); if (!env) { env = pseudo_get_value("PSEUDO_DISABLED"); } if (env) { int actually_disabled = 1; switch (*env) { case '0': case 'f': case 'F': case 'n': case 'N': actually_disabled = 0; break; case 's': case 'S': actually_disabled = 0; pseudo_local_only = 1; break; } if (actually_disabled) { if (!pseudo_disabled) { pseudo_antimagic(); pseudo_disabled = 1; } pseudo_set_value("PSEUDO_DISABLED", "1"); } else { if (pseudo_disabled) { pseudo_magic(); pseudo_disabled = 0; pseudo_inited = 0; /* Re-read the initial values! */ } pseudo_set_value("PSEUDO_DISABLED", "0"); } } else { pseudo_set_value("PSEUDO_DISABLED", "0"); } /* Setup global items needed for pseudo to function... */ if (!pseudo_inited) { /* Ensure that all of the values are reset */ server_pid = 0; pseudo_prefix_dir_fd = -1; pseudo_localstate_dir_fd = -1; pseudo_pwd_fd = -1; pseudo_pwd_lck_fd = -1; pseudo_pwd_lck_name = NULL; pseudo_pwd = NULL; pseudo_grp_fd = -1; pseudo_grp = NULL; pseudo_cwd = NULL; pseudo_cwd_len = 0; pseudo_chroot = NULL; pseudo_passwd = NULL; pseudo_chroot_len = 0; pseudo_cwd_rel = NULL; pseudo_nosymlinkexp = 0; } if (!pseudo_disabled && !pseudo_inited) { char *pseudo_path = 0; pseudo_path = pseudo_prefix_path(NULL); if (pseudo_prefix_dir_fd == -1) { if (pseudo_path) { pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY); /* directory is missing? */ if (pseudo_prefix_dir_fd == -1 && errno == ENOENT) { pseudo_debug(1, "prefix directory doesn't exist, trying to create\n"); mkdir_p(pseudo_path); pseudo_prefix_dir_fd = open(pseudo_path, O_RDONLY); } pseudo_prefix_dir_fd = pseudo_fd(pseudo_prefix_dir_fd, MOVE_FD); } else { pseudo_diag("No prefix available to to find server.\n"); exit(1); } if (pseudo_prefix_dir_fd == -1) { pseudo_diag("Can't open prefix path (%s) for server: %s\n", pseudo_path, strerror(errno)); exit(1); } } free(pseudo_path); pseudo_path = pseudo_localstatedir_path(NULL); if (pseudo_localstate_dir_fd == -1) { if (pseudo_path) { pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY); /* directory is missing? */ if (pseudo_localstate_dir_fd == -1 && errno == ENOENT) { pseudo_debug(1, "local state directory doesn't exist, trying to create\n"); mkdir_p(pseudo_path); pseudo_localstate_dir_fd = open(pseudo_path, O_RDONLY); } pseudo_localstate_dir_fd = pseudo_fd(pseudo_localstate_dir_fd, MOVE_FD); } else { pseudo_diag("No prefix available to to find server.\n"); exit(1); } if (pseudo_localstate_dir_fd == -1) { pseudo_diag("Can't open local state path (%s) for server: %s\n", pseudo_path, strerror(errno)); exit(1); } } free(pseudo_path); env = pseudo_get_value("PSEUDO_NOSYMLINKEXP"); if (env) { char *endptr; /* if the environment variable is not an empty string, * parse it; "0" means turn NOSYMLINKEXP off, "1" means * turn it on (disabling the feature). An empty string * or something we can't parse means to set the flag; this * is a safe default because if you didn't want the flag * set, you normally wouldn't set the environment variable * at all. */ if (*env) { pseudo_nosymlinkexp = strtol(env, &endptr, 10); if (*endptr) pseudo_nosymlinkexp = 1; } else { pseudo_nosymlinkexp = 1; } } else { pseudo_nosymlinkexp = 0; } free(env); env = pseudo_get_value("PSEUDO_UIDS"); if (env) sscanf(env, "%d,%d,%d,%d", &pseudo_ruid, &pseudo_euid, &pseudo_suid, &pseudo_fuid); free(env); env = pseudo_get_value("PSEUDO_GIDS"); if (env) sscanf(env, "%d,%d,%d,%d", &pseudo_rgid, &pseudo_egid, &pseudo_sgid, &pseudo_fuid); free(env); env = pseudo_get_value("PSEUDO_CHROOT"); if (env) { pseudo_chroot = strdup(env); if (pseudo_chroot) { pseudo_chroot_len = strlen(pseudo_chroot); } else { pseudo_diag("can't store chroot path (%s)\n", env); } } free(env); env = pseudo_get_value("PSEUDO_PASSWD"); if (env) { pseudo_passwd = strdup(env); } free(env); pseudo_inited = 1; } if (!pseudo_disabled) pseudo_client_getcwd(); pseudo_magic(); }
/* You can either create a query or create a log entry. They use very * similar syntax, but: * - if you're making a query, you can use >, <, etc. * - if you're logging, you can't. * This is tracked by recording whether any non-exact relations * have been requested ("query_only"), and refusing to set the -l * flag if they have, and refusing to accept any such relation * if the -l flag is already set. */ int main(int argc, char **argv) { pseudo_query_t *traits = 0, *current = 0, *new_trait = 0; char *s; log_history history; int query_only = 0; int o; int bad_args = 0; char *format = "%s %-12.12R %-4y %7o: [mode %04m, %2a] %p %T"; while ((o = getopt(argc, argv, "vla:c:d:DE:f:F:g:G:hi:I:m:M:o:O:p:P:r:R:s:S:t:T:u:Ux:y:")) != -1) { switch (o) { case 'P': s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW); if (!s) pseudo_diag("Can't resolve prefix path '%s'\n", optarg); pseudo_set_value("PSEUDO_PREFIX", s); break; case 'v': pseudo_debug_verbose(); break; case 'x': pseudo_debug_set(optarg); break; case 'l': opt_l = 1; break; case 'D': opt_D = 1; query_only = 1; break; case 'E': timeformat = strdup(optarg); break; case 'F': /* disallow specifying -F with -l */ format = strdup(optarg); query_only = 1; break; case 'U': opt_U = 1; query_only = 1; break; case 'I': /* PSQF_ID */ query_only = 1; /* FALLTHROUGH */ case 'a': /* PSQF_ACCESS */ case 'c': /* PSQF_CLIENT */ case 'd': /* PSQF_DEV */ case 'f': /* PSQF_FD */ case 'g': /* PSQF_GID */ case 'G': /* PSQF_TAG */ case 'i': /* PSQF_INODE */ case 'm': /* PSQF_PERM */ case 'M': /* PSQF_MODE */ case 'o': /* PSQF_OP */ case 'O': /* PSQF_ORDER */ case 'p': /* PSQF_PATH */ case 'r': /* PSQF_RESULT */ case 'R': /* PSQF_PROGRAM */ case 's': /* PSQF_STAMP */ case 'S': /* PSQF_SEVERITY */ case 't': /* PSQF_FTYPE */ case 'T': /* PSQF_TEXT */ case 'u': /* PSQF_UID */ case 'y': /* PSQF_TYPE */ new_trait = plog_trait(o, optarg); if (!new_trait) { bad_args = 1; } break; case 'h': usage(EXIT_SUCCESS); break; case '?': /* FALLTHROUGH */ default: fprintf(stderr, "unknown option '%c'\n", optopt); usage(EXIT_FAILURE); break; } if (new_trait) { if (current) { current->next = new_trait; current = current->next; } else { traits = new_trait; current = new_trait; } new_trait = 0; } } pseudo_debug_flags_finalize(); if (optind < argc) { pseudo_diag("Error: Extra arguments not associated with any option.\n"); usage(EXIT_FAILURE); } if (query_only && opt_l) { pseudo_diag("Error: -l cannot be used with query-only options or flags.\n"); bad_args = 1; } /* should be set only if we have already diagnosed the bad arguments. */ if (bad_args) exit(EXIT_FAILURE); if (!pseudo_get_prefix(argv[0])) { pseudo_diag("Can't figure out prefix. Set PSEUDO_PREFIX or invoke with full path.\n"); exit(EXIT_FAILURE); } if (!pseudo_get_bindir()) { pseudo_diag("Can't figure out bindir. Set PSEUDO_BINDIR.\n"); exit(EXIT_FAILURE); } if (!pseudo_get_libdir()) { pseudo_diag("Can't figure out libdir. Set PSEUDO_LIBDIR.\n"); exit(EXIT_FAILURE); } if (!pseudo_get_localstatedir()) { pseudo_diag("Can't figure out localstatedir. Set PSEUDO_LOCALSTATEDIR.\n"); exit(EXIT_FAILURE); } if (opt_l) { pdb_log_traits(traits); } else { int fields; fields = format_scan(format); if (fields == -1) { pseudo_diag("couldn't parse format string (%s).\n", format); return EXIT_FAILURE; } if (opt_D) { if (pdb_delete(traits, fields)) { pseudo_diag("errors occurred trying to delete entries.\n"); } } else { history = pdb_history(traits, fields, opt_U); if (history) { log_entry *e; while ((e = pdb_history_entry(history)) != NULL) { display(e, format); log_entry_free(e); } pdb_history_free(history); } else { pseudo_diag("could not retrieve history.\n"); return EXIT_FAILURE; } } } return 0; }