static int client_ping(void) { pseudo_msg_t ping; pseudo_msg_t *ack; char tagbuf[pseudo_path_max()]; char *tag = pseudo_get_value("PSEUDO_TAG"); memset(&ping, 0, sizeof(ping)); ping.type = PSEUDO_MSG_PING; ping.op = OP_NONE; ping.pathlen = snprintf(tagbuf, sizeof(tagbuf), "%s%c%s", program_invocation_name ? program_invocation_name : "<unknown>", 0, tag ? tag : ""); free(tag); ping.client = getpid(); ping.result = 0; errno = 0; pseudo_debug(4, "sending ping\n"); if (pseudo_msg_send(connect_fd, &ping, ping.pathlen, tagbuf)) { pseudo_debug(3, "error pinging server: %s\n", strerror(errno)); return 1; } ack = pseudo_msg_receive(connect_fd); if (!ack) { pseudo_debug(2, "no ping response from server: %s\n", strerror(errno)); /* and that's not good, so... */ server_pid = 0; return 1; } if (ack->type != PSEUDO_MSG_ACK) { pseudo_debug(1, "invalid ping response from server: expected ack, got %d\n", ack->type); /* and that's not good, so... */ server_pid = 0; return 1; } pseudo_debug(5, "ping ok\n"); return 0; }
int wrap_clone_child(void *args) { struct clone_args *clargs = args; int (*fn)(void *) = clargs->fn; int flags = clargs->flags; void *arg = clargs->arg; /* We always free in the client */ free(clargs); if (!(flags & CLONE_VM)) { pseudo_setupenv(); if (!pseudo_get_value("PSEUDO_UNLOAD")) { pseudo_reinit_libpseudo(); } else { pseudo_dropenv(); } } return fn(arg); }
/* 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(); }