// whitelist for /home/user directory void fs_whitelist(void) { char *homedir = cfg.homedir; assert(homedir); ProfileEntry *entry = cfg.profile; if (!entry) return; char *new_name = NULL; int home_dir = 0; // /home/user directory flag int tmp_dir = 0; // /tmp directory flag int media_dir = 0; // /media directory flag int mnt_dir = 0; // /mnt directory flag int var_dir = 0; // /var directory flag int dev_dir = 0; // /dev directory flag int opt_dir = 0; // /opt directory flag int srv_dir = 0; // /srv directory flag // verify whitelist files, extract symbolic links, etc. while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } // resolve ${DOWNLOADS} if (strcmp(entry->data + 10, "${DOWNLOADS}") == 0) { char *tmp = resolve_downloads(); if (tmp) entry->data = tmp; else { *entry->data = '\0'; fprintf(stderr, "***\n"); fprintf(stderr, "*** Warning: cannot whitelist Downloads directory\n"); fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); fprintf(stderr, "*** \tPlease create a proper Downloads directory for your application.\n"); fprintf(stderr, "***\n"); continue; } } // replace ~/ or ${HOME} into /home/username // if (new_name) // free(new_name); new_name = expand_home(entry->data + 10, cfg.homedir); assert(new_name); if (arg_debug) fprintf(stderr, "Debug %d: new_name #%s#\n", __LINE__, new_name); // valid path referenced to filesystem root if (*new_name != '/') { if (arg_debug) fprintf(stderr, "Debug %d: \n", __LINE__); goto errexit; } // extract the absolute path of the file // realpath function will fail with ENOENT if the file is not found char *fname = realpath(new_name, NULL); if (!fname) { // file not found, blank the entry in the list and continue if (arg_debug || arg_debug_whitelists) { printf("Removed whitelist path: %s\n", entry->data); printf("\texpanded: %s\n", new_name); printf("\treal path: (null)\n"); printf("\t"); fflush(0); perror("realpath"); } *entry->data = '\0'; // if 1 the file was not found; mount an empty directory if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { if(!arg_private) home_dir = 1; } else if (strncmp(new_name, "/tmp/", 5) == 0) tmp_dir = 1; else if (strncmp(new_name, "/media/", 7) == 0) media_dir = 1; else if (strncmp(new_name, "/mnt/", 5) == 0) mnt_dir = 1; else if (strncmp(new_name, "/var/", 5) == 0) var_dir = 1; else if (strncmp(new_name, "/dev/", 5) == 0) dev_dir = 1; else if (strncmp(new_name, "/opt/", 5) == 0) opt_dir = 1; else if (strncmp(new_name, "/srv/", 5) == 0) opt_dir = 1; continue; } // check for supported directories if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { // whitelisting home directory is disabled if --private option is present if (arg_private) { if (arg_debug || arg_debug_whitelists) printf("Removed whitelist path %s, --private option is present\n", entry->data); *entry->data = '\0'; continue; } entry->home_dir = 1; home_dir = 1; if (arg_debug || arg_debug_whitelists) fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n", __LINE__, fname, cfg.homedir); // both path and absolute path are under /home if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0) { // check if the file is owned by the user struct stat s; if (stat(fname, &s) == 0 && s.st_uid != getuid()) goto errexit; } } else if (strncmp(new_name, "/tmp/", 5) == 0) { entry->tmp_dir = 1; tmp_dir = 1; // both path and absolute path are under /tmp if (strncmp(fname, "/tmp/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/media/", 7) == 0) { entry->media_dir = 1; media_dir = 1; // both path and absolute path are under /media if (strncmp(fname, "/media/", 7) != 0) { goto errexit; } } else if (strncmp(new_name, "/mnt/", 5) == 0) { entry->mnt_dir = 1; mnt_dir = 1; // both path and absolute path are under /mnt if (strncmp(fname, "/mnt/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/var/", 5) == 0) { entry->var_dir = 1; var_dir = 1; // both path and absolute path are under /var // exceptions: /var/run and /var/lock if (strcmp(new_name, "/var/run")== 0) ; else if (strcmp(new_name, "/var/lock")== 0) ; else if (strncmp(fname, "/var/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/dev/", 5) == 0) { entry->dev_dir = 1; dev_dir = 1; // both path and absolute path are under /dev if (strncmp(fname, "/dev/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/opt/", 5) == 0) { entry->opt_dir = 1; opt_dir = 1; // both path and absolute path are under /dev if (strncmp(fname, "/opt/", 5) != 0) { goto errexit; } } else if (strncmp(new_name, "/srv/", 5) == 0) { entry->srv_dir = 1; srv_dir = 1; // both path and absolute path are under /srv if (strncmp(fname, "/srv/", 5) != 0) { goto errexit; } } else { goto errexit; } // mark symbolic links if (is_link(new_name)) entry->link = new_name; else { free(new_name); new_name = NULL; } // change file name in entry->data if (strcmp(fname, entry->data + 10) != 0) { char *newdata; if (asprintf(&newdata, "whitelist %s", fname) == -1) errExit("asprintf"); entry->data = newdata; if (arg_debug || arg_debug_whitelists) printf("Replaced whitelist path: %s\n", entry->data); } free(fname); entry = entry->next; } // /home/user if (home_dir) { // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR mkdir_attr(RUN_WHITELIST_HOME_USER_DIR, 0755, getuid(), getgid()); if (mount(cfg.homedir, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount a tmpfs and initialize /home/user fs_private(); } // /tmp mountpoint if (tmp_dir) { // keep a copy of real /tmp directory in mkdir_attr(RUN_WHITELIST_TMP_DIR, 1777, 0, 0); if (mount("/tmp", RUN_WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /tmp if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /tmp directory\n"); if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); fs_logger("tmpfs /tmp"); } // /media mountpoint if (media_dir) { // some distros don't have a /media directory struct stat s; if (stat("/media", &s) == 0) { // keep a copy of real /media directory in RUN_WHITELIST_MEDIA_DIR mkdir_attr(RUN_WHITELIST_MEDIA_DIR, 0755, 0, 0); if (mount("/media", RUN_WHITELIST_MEDIA_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /media if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /media directory\n"); if (mount("tmpfs", "/media", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /media"); fs_logger("tmpfs /media"); } else media_dir = 0; } // /mnt mountpoint if (mnt_dir) { // check if /mnt directory exists struct stat s; if (stat("/mnt", &s) == 0) { // keep a copy of real /mnt directory in RUN_WHITELIST_MNT_DIR mkdir_attr(RUN_WHITELIST_MNT_DIR, 0755, 0, 0); if (mount("/mnt", RUN_WHITELIST_MNT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /mnt if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /mnt directory\n"); if (mount("tmpfs", "/mnt", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /mnt"); fs_logger("tmpfs /mnt"); } else mnt_dir = 0; } // /var mountpoint if (var_dir) { // keep a copy of real /var directory in RUN_WHITELIST_VAR_DIR mkdir_attr(RUN_WHITELIST_VAR_DIR, 0755, 0, 0); if (mount("/var", RUN_WHITELIST_VAR_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /var if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /var directory\n"); if (mount("tmpfs", "/var", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /var"); fs_logger("tmpfs /var"); } // /dev mountpoint if (dev_dir) { // keep a copy of real /dev directory in RUN_WHITELIST_DEV_DIR mkdir_attr(RUN_WHITELIST_DEV_DIR, 0755, 0, 0); if (mount("/dev", RUN_WHITELIST_DEV_DIR, NULL, MS_BIND|MS_REC, "mode=755,gid=0") < 0) errExit("mount bind"); // mount tmpfs on /dev if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /dev directory\n"); if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /dev"); fs_logger("tmpfs /dev"); } // /opt mountpoint if (opt_dir) { // keep a copy of real /opt directory in RUN_WHITELIST_OPT_DIR mkdir_attr(RUN_WHITELIST_OPT_DIR, 0755, 0, 0); if (mount("/opt", RUN_WHITELIST_OPT_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /opt if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /opt directory\n"); if (mount("tmpfs", "/opt", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /opt"); fs_logger("tmpfs /opt"); } // /srv mountpoint if (srv_dir) { // check if /srv directory exists struct stat s; if (stat("/srv", &s) == 0) { // keep a copy of real /srv directory in RUN_WHITELIST_SRV_DIR mkdir_attr(RUN_WHITELIST_SRV_DIR, 0755, 0, 0); if (mount("/srv", RUN_WHITELIST_SRV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // mount tmpfs on /srv if (arg_debug || arg_debug_whitelists) printf("Mounting tmpfs on /srv directory\n"); if (mount("tmpfs", "/srv", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mounting tmpfs on /srv"); fs_logger("tmpfs /srv"); } else srv_dir = 0; } // go through profile rules again, and interpret whitelist commands entry = cfg.profile; while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } //printf("here %d#%s#\n", __LINE__, entry->data); // whitelist the real file if (strcmp(entry->data, "whitelist /run") == 0 && (strcmp(entry->link, "/var/run") == 0 || strcmp(entry->link, "/var/lock") == 0)) { int rv = symlink(entry->data + 10, entry->link); if (rv) fprintf(stderr, "Warning cannot create symbolic link %s\n", entry->link); else if (arg_debug || arg_debug_whitelists) printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); } else { whitelist_path(entry); // create the link if any if (entry->link) { // if the link is already there, do not bother struct stat s; if (stat(entry->link, &s) != 0) { // create the path if necessary mkpath(entry->link, s.st_mode); int rv = symlink(entry->data + 10, entry->link); if (rv) fprintf(stderr, "Warning cannot create symbolic link %s\n", entry->link); else if (arg_debug || arg_debug_whitelists) printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); } } } entry = entry->next; } // mask the real home directory, currently mounted on RUN_WHITELIST_HOME_DIR if (home_dir) { if (mount("tmpfs", RUN_WHITELIST_HOME_USER_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_HOME_USER_DIR); } // mask the real /tmp directory, currently mounted on RUN_WHITELIST_TMP_DIR if (tmp_dir) { if (mount("tmpfs", RUN_WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_TMP_DIR); } // mask the real /var directory, currently mounted on RUN_WHITELIST_VAR_DIR if (var_dir) { if (mount("tmpfs", RUN_WHITELIST_VAR_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_VAR_DIR); } // mask the real /opt directory, currently mounted on RUN_WHITELIST_OPT_DIR if (opt_dir) { if (mount("tmpfs", RUN_WHITELIST_OPT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_OPT_DIR); } // mask the real /dev directory, currently mounted on RUN_WHITELIST_DEV_DIR if (dev_dir) { if (mount("tmpfs", RUN_WHITELIST_DEV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_DEV_DIR); } // mask the real /media directory, currently mounted on RUN_WHITELIST_MEDIA_DIR if (media_dir) { if (mount("tmpfs", RUN_WHITELIST_MEDIA_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_MEDIA_DIR); } // mask the real /mnt directory, currently mounted on RUN_WHITELIST_MNT_DIR if (mnt_dir) { if (mount("tmpfs", RUN_WHITELIST_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_MNT_DIR); } // mask the real /srv directory, currently mounted on RUN_WHITELIST_SRV_DIR if (srv_dir) { if (mount("tmpfs", RUN_WHITELIST_SRV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); } if (new_name) free(new_name); return; errexit: fprintf(stderr, "Error: invalid whitelist path %s\n", new_name); exit(1); }
extern int task_cgroup_cpuset_create(slurmd_job_t *job) { int rc; int fstatus = SLURM_ERROR; xcgroup_t cpuset_cg; uint32_t jobid = job->jobid; uint32_t stepid = job->stepid; uid_t uid = job->uid; uid_t gid = job->gid; char* user_alloc_cores = NULL; char* job_alloc_cores = NULL; char* step_alloc_cores = NULL; char* cpus = NULL; size_t cpus_size; /* build user cgroup relative path if not set (should not be) */ if (*user_cgroup_path == '\0') { if (snprintf(user_cgroup_path,PATH_MAX, "/uid_%u",uid) >= PATH_MAX) { error("task/cgroup: unable to build uid %u cpuset " "cg relative path : %m",uid); return SLURM_ERROR; } } /* build job cgroup relative path if no set (should not be) */ if (*job_cgroup_path == '\0') { if (snprintf(job_cgroup_path,PATH_MAX,"%s/job_%u", user_cgroup_path,jobid) >= PATH_MAX) { error("task/cgroup: unable to build job %u cpuset " "cg relative path : %m",jobid); return SLURM_ERROR; } } /* build job step cgroup relative path (should not be) */ if (*jobstep_cgroup_path == '\0') { if (stepid == NO_VAL) { if (snprintf(jobstep_cgroup_path, PATH_MAX, "%s/step_batch", job_cgroup_path) >= PATH_MAX) { error("task/cgroup: unable to build job step" " %u.batch cpuset cg relative path: %m", jobid); return SLURM_ERROR; } } else { if (snprintf(jobstep_cgroup_path, PATH_MAX, "%s/step_%u", job_cgroup_path, stepid) >= PATH_MAX) { error("task/cgroup: unable to build job step" " %u.%u cpuset cg relative path: %m", jobid, stepid); return SLURM_ERROR; } } } /* * create cpuset root cg and lock it * * we will keep the lock until the end to avoid the effect of a release * agent that would remove an existing cgroup hierarchy while we are * setting it up. As soon as the step cgroup is created, we can release * the lock. * Indeed, consecutive slurm steps could result in cg being removed * between the next EEXIST instanciation and the first addition of * a task. The release_agent will have to lock the root cpuset cgroup * to avoid this scenario. */ if (xcgroup_create(&cpuset_ns,&cpuset_cg,"",0,0) != XCGROUP_SUCCESS) { error("task/cgroup: unable to create root cpuset xcgroup"); return SLURM_ERROR; } if (xcgroup_lock(&cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&cpuset_cg); error("task/cgroup: unable to lock root cpuset cg"); return SLURM_ERROR; } /* * build job and job steps allocated cores lists */ debug("task/cgroup: job abstract cores are '%s'", job->job_alloc_cores); debug("task/cgroup: step abstract cores are '%s'", job->step_alloc_cores); if (xcpuinfo_abs_to_mac(job->job_alloc_cores, &job_alloc_cores) != XCPUINFO_SUCCESS) { error("task/cgroup: unable to build job physical cores"); goto error; } if (xcpuinfo_abs_to_mac(job->step_alloc_cores, &step_alloc_cores) != XCPUINFO_SUCCESS) { error("task/cgroup: unable to build step physical cores"); goto error; } debug("task/cgroup: job physical cores are '%s'", job->job_alloc_cores); debug("task/cgroup: step physical cores are '%s'", job->step_alloc_cores); /* * create user cgroup in the cpuset ns (it could already exist) */ if (xcgroup_create(&cpuset_ns,&user_cpuset_cg, user_cgroup_path, getuid(),getgid()) != XCGROUP_SUCCESS) { goto error; } if (xcgroup_instanciate(&user_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); goto error; } /* * check that user's cpuset cgroup is consistant and add the job cores */ rc = xcgroup_get_param(&user_cpuset_cg,"cpuset.cpus",&cpus,&cpus_size); if (rc != XCGROUP_SUCCESS || cpus_size == 1) { /* initialize the cpusets as it was inexistant */ if (_xcgroup_cpuset_init(&user_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_delete(&user_cpuset_cg); xcgroup_destroy(&user_cpuset_cg); goto error; } } user_alloc_cores = xstrdup(job_alloc_cores); if (cpus != NULL && cpus_size > 1) { cpus[cpus_size-1]='\0'; xstrcat(user_alloc_cores,","); xstrcat(user_alloc_cores,cpus); } xcgroup_set_param(&user_cpuset_cg,"cpuset.cpus",user_alloc_cores); xfree(cpus); /* * create job cgroup in the cpuset ns (it could already exist) */ if (xcgroup_create(&cpuset_ns,&job_cpuset_cg, job_cgroup_path, getuid(),getgid()) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); goto error; } if (xcgroup_instanciate(&job_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); xcgroup_destroy(&job_cpuset_cg); goto error; } if (_xcgroup_cpuset_init(&job_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); xcgroup_destroy(&job_cpuset_cg); goto error; } xcgroup_set_param(&job_cpuset_cg,"cpuset.cpus",job_alloc_cores); /* * create step cgroup in the cpuset ns (it should not exists) * use job's user uid/gid to enable tasks cgroups creation by * the user inside the step cgroup owned by root */ if (xcgroup_create(&cpuset_ns,&step_cpuset_cg, jobstep_cgroup_path, uid,gid) != XCGROUP_SUCCESS) { /* do not delete user/job cgroup as */ /* they can exist for other steps */ xcgroup_destroy(&user_cpuset_cg); xcgroup_destroy(&job_cpuset_cg); goto error; } if (xcgroup_instanciate(&step_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); xcgroup_destroy(&job_cpuset_cg); xcgroup_destroy(&step_cpuset_cg); goto error; } if (_xcgroup_cpuset_init(&step_cpuset_cg) != XCGROUP_SUCCESS) { xcgroup_destroy(&user_cpuset_cg); xcgroup_destroy(&job_cpuset_cg); xcgroup_delete(&step_cpuset_cg); xcgroup_destroy(&step_cpuset_cg); goto error; } xcgroup_set_param(&step_cpuset_cg,"cpuset.cpus",step_alloc_cores); /* attach the slurmstepd to the step cpuset cgroup */ pid_t pid = getpid(); rc = xcgroup_add_pids(&step_cpuset_cg,&pid,1); if (rc != XCGROUP_SUCCESS) { error("task/cgroup: unable to add slurmstepd to cpuset cg '%s'", step_cpuset_cg.path); fstatus = SLURM_ERROR; } else fstatus = SLURM_SUCCESS; error: xcgroup_unlock(&cpuset_cg); xcgroup_destroy(&cpuset_cg); xfree(user_alloc_cores); xfree(job_alloc_cores); xfree(step_alloc_cores); return fstatus; }
void uwsgi_detach_daemons() { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL // stop any legion daemon, doesn't matter if dumb or smart if (ud->pid > 0 && (ud->legion || !ud->pidfile)) { #else // stop only dumb daemons if (ud->pid > 0 && !ud->pidfile) { #endif uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command); // try to stop daemon gracefully, kill it if it won't die // if mercy is not set then wait up to 3 seconds time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3); int waitpid_status; while (!kill(ud->pid, 0)) { kill(-(ud->pid), ud->stop_signal); sleep(1); waitpid(ud->pid, &waitpid_status, WNOHANG); if (uwsgi_now() >= timeout) { uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command); kill(-(ud->pid), SIGKILL); break; } } // unregister daemon to prevent it from being respawned ud->registered = 0; } ud = ud->next; } } static int daemon_spawn(void *); void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) { // skip unregistered daemons if (!ud->registered) return; ud->throttle = 0; if (uwsgi.current_time - ud->last_spawn <= 3) { ud->throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn); // if ud->respawns == 0 then we can end up with throttle < 0 if (ud->throttle <= 0) ud->throttle = 1; } pid_t pid = uwsgi_fork("uWSGI external daemon"); if (pid < 0) { uwsgi_error("fork()"); return; } if (pid > 0) { ud->has_daemonized = 0; ud->pid = pid; ud->status = 1; ud->pidfile_checks = 0; if (ud->respawns == 0) { ud->born = uwsgi_now(); } ud->respawns++; ud->last_spawn = uwsgi_now(); } else { // close uwsgi sockets uwsgi_close_all_sockets(); uwsgi_close_all_fds(); #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && defined(CLONE_NEWPID) if (ud->ns_pid) { // we need to create a new session if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } // avoid the need to set stop_signal in attach-daemon2 signal(SIGTERM, end_me); char stack[PTHREAD_STACK_MIN]; pid_t pid = clone((int (*)(void *))daemon_spawn, stack + PTHREAD_STACK_MIN, SIGCHLD | CLONE_NEWPID, (void *) ud); if (pid > 0) { #ifdef PR_SET_PDEATHSIG if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("uwsgi_spawn_daemon()/prctl()"); } #endif // block all signals except SIGTERM sigset_t smask; sigfillset(&smask); sigdelset(&smask, SIGTERM); sigprocmask(SIG_BLOCK, &smask, NULL); int status; if (waitpid(pid, &status, 0) < 0) { uwsgi_error("uwsgi_spawn_daemon()/waitpid()"); } _exit(0); } uwsgi_error("uwsgi_spawn_daemon()/clone()"); exit(1); } #endif daemon_spawn((void *) ud); } } static int daemon_spawn(void *arg) { struct uwsgi_daemon *ud = (struct uwsgi_daemon *) arg; if (ud->gid) { if (setgid(ud->gid)) { uwsgi_error("uwsgi_spawn_daemon()/setgid()"); exit(1); } } if (ud->uid) { if (setuid(ud->uid)) { uwsgi_error("uwsgi_spawn_daemon()/setuid()"); exit(1); } } if (ud->daemonize) { /* refork... */ pid_t pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } uwsgi_write_pidfile(ud->pidfile); } if (!uwsgi.daemons_honour_stdin && !ud->honour_stdin) { // /dev/null will became stdin uwsgi_remap_fd(0, "/dev/null"); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } if (!ud->pidfile) { #ifdef PR_SET_PDEATHSIG if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif } if (ud->throttle) { uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, ud->throttle); sleep((unsigned int) ud->throttle); } uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid()); uwsgi_exec_command_with_args(ud->command); uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command); // never here; exit(1); } void uwsgi_opt_add_daemon(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *pidfile = NULL; int daemonize = 0; int freq = 10; char *space = NULL; int stop_signal = SIGTERM; int reload_signal = 0; char *command = uwsgi_str(value); #ifdef UWSGI_SSL char *legion = NULL; if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid legion daemon syntax: %s\n", command); exit(1); } *space = 0; legion = command; command = space+1; } #endif if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command); exit(1); } *space = 0; pidfile = command; // check for freq char *comma = strchr(pidfile, ','); if (comma) { *comma = 0; freq = atoi(comma + 1); } command = space + 1; if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) { daemonize = 1; } } if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = command; uwsgi_ud->pid = 0; uwsgi_ud->status = 0; uwsgi_ud->freq = freq; uwsgi_ud->registered = 0; uwsgi_ud->next = NULL; uwsgi_ud->respawns = 0; uwsgi_ud->last_spawn = 0; uwsgi_ud->daemonize = daemonize; uwsgi_ud->pidfile = pidfile; uwsgi_ud->control = 0; uwsgi_ud->stop_signal = stop_signal; uwsgi_ud->reload_signal = reload_signal; if (!strcmp(opt, "attach-control-daemon")) { uwsgi_ud->control = 1; } #ifdef UWSGI_SSL uwsgi_ud->legion = legion; #endif uwsgi.daemons_cnt++; } void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *d_command = NULL; char *d_freq = NULL; char *d_pidfile = NULL; char *d_control = NULL; char *d_legion = NULL; char *d_daemonize = NULL; char *d_touch = NULL; char *d_stopsignal = NULL; char *d_reloadsignal = NULL; char *d_stdin = NULL; char *d_uid = NULL; char *d_gid = NULL; char *d_ns_pid = NULL; char *arg = uwsgi_str(value); if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "command", &d_command, "cmd", &d_command, "exec", &d_command, "freq", &d_freq, "pidfile", &d_pidfile, "control", &d_control, "daemonize", &d_daemonize, "daemon", &d_daemonize, "touch", &d_touch, "stopsignal", &d_stopsignal, "stop_signal", &d_stopsignal, "reloadsignal", &d_reloadsignal, "reload_signal", &d_reloadsignal, "stdin", &d_stdin, "uid", &d_uid, "gid", &d_gid, "ns_pid", &d_ns_pid, NULL)) { uwsgi_log("invalid --%s keyval syntax\n", opt); exit(1); } if (!d_command) { uwsgi_log("--%s: you need to specify a 'command' key\n", opt); exit(1); } #ifndef UWSGI_SSL if (d_legion) { uwsgi_log("legion subsystem is not supported on this uWSGI version, rebuild with ssl support\n"); exit(1); } #endif if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = d_command; uwsgi_ud->freq = d_freq ? atoi(d_freq) : 10; uwsgi_ud->daemonize = d_daemonize ? 1 : 0; uwsgi_ud->pidfile = d_pidfile; uwsgi_ud->stop_signal = d_stopsignal ? atoi(d_stopsignal) : SIGTERM; uwsgi_ud->reload_signal = d_reloadsignal ? atoi(d_reloadsignal) : 0; uwsgi_ud->control = d_control ? 1 : 0; uwsgi_ud->uid = d_uid ? atoi(d_uid) : 0; uwsgi_ud->gid = d_gid ? atoi(d_gid) : 0; uwsgi_ud->honour_stdin = d_stdin ? 1 : 0; #ifdef UWSGI_SSL uwsgi_ud->legion = d_legion; #endif uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0; if (d_touch) { size_t i,rlen = 0; char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen); for(i=0;i<rlen;i++) { uwsgi_string_new_list(&uwsgi_ud->touch, argv[i]); } if (argv) free(argv); } uwsgi.daemons_cnt++; free(arg); }
int main(int argc, char **argv) { int i; sigset_t set; #if ENABLE_MPEGTS uint32_t adapter_mask = 0; #endif int log_level = LOG_INFO; int log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG; const char *log_debug = NULL, *log_trace = NULL; char buf[512]; main_tid = pthread_self(); /* Setup global mutexes */ pthread_mutex_init(&ffmpeg_lock, NULL); pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_init(&atomic_lock, NULL); pthread_cond_init(>imer_cond, NULL); /* Defaults */ tvheadend_webui_port = 9981; tvheadend_webroot = NULL; tvheadend_htsp_port = 9982; tvheadend_htsp_port_extra = 0; /* Command line options */ int opt_help = 0, opt_version = 0, opt_fork = 0, opt_firstrun = 0, opt_stderr = 0, opt_syslog = 0, opt_uidebug = 0, opt_abort = 0, opt_noacl = 0, opt_fileline = 0, opt_threadid = 0, opt_ipv6 = 0, opt_tsfile_tuner = 0, opt_dump = 0, opt_xspf = 0; const char *opt_config = NULL, *opt_user = NULL, *opt_group = NULL, *opt_logpath = NULL, *opt_log_debug = NULL, *opt_log_trace = NULL, *opt_pidpath = "/var/run/tvheadend.pid", #if ENABLE_LINUXDVB *opt_dvb_adapters = NULL, #endif *opt_bindaddr = NULL, *opt_subscribe = NULL, *opt_user_agent = NULL; str_list_t opt_satip_xml = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) }; str_list_t opt_tsfile = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) }; cmdline_opt_t cmdline_opts[] = { { 0, NULL, "Generic Options", OPT_BOOL, NULL }, { 'h', "help", "Show this page", OPT_BOOL, &opt_help }, { 'v', "version", "Show version infomation", OPT_BOOL, &opt_version }, { 0, NULL, "Service Configuration", OPT_BOOL, NULL }, { 'c', "config", "Alternate config path", OPT_STR, &opt_config }, { 'f', "fork", "Fork and run as daemon", OPT_BOOL, &opt_fork }, { 'u', "user", "Run as user", OPT_STR, &opt_user }, { 'g', "group", "Run as group", OPT_STR, &opt_group }, { 'p', "pid", "Alternate pid path", OPT_STR, &opt_pidpath }, { 'C', "firstrun", "If no user account exists then create one with\n" "no username and no password. Use with care as\n" "it will allow world-wide administrative access\n" "to your Tvheadend installation until you edit\n" "the access-control from within the Tvheadend UI", OPT_BOOL, &opt_firstrun }, #if ENABLE_LINUXDVB { 'a', "adapters", "Only use specified DVB adapters (comma separated)", OPT_STR, &opt_dvb_adapters }, #endif #if ENABLE_SATIP_CLIENT { 0, "satip_xml", "URL with the SAT>IP server XML location", OPT_STR_LIST, &opt_satip_xml }, #endif { 0, NULL, "Server Connectivity", OPT_BOOL, NULL }, { '6', "ipv6", "Listen on IPv6", OPT_BOOL, &opt_ipv6 }, { 'b', "bindaddr", "Specify bind address", OPT_STR, &opt_bindaddr}, { 0, "http_port", "Specify alternative http port", OPT_INT, &tvheadend_webui_port }, { 0, "http_root", "Specify alternative http webroot", OPT_STR, &tvheadend_webroot }, { 0, "htsp_port", "Specify alternative htsp port", OPT_INT, &tvheadend_htsp_port }, { 0, "htsp_port2", "Specify extra htsp port", OPT_INT, &tvheadend_htsp_port_extra }, { 0, "useragent", "Specify User-Agent header for the http client", OPT_STR, &opt_user_agent }, { 0, "xspf", "Use xspf playlist instead M3U", OPT_BOOL, &opt_xspf }, { 0, NULL, "Debug Options", OPT_BOOL, NULL }, { 'd', "stderr", "Enable debug on stderr", OPT_BOOL, &opt_stderr }, { 's', "syslog", "Enable debug to syslog", OPT_BOOL, &opt_syslog }, { 'l', "logfile", "Enable debug to file", OPT_STR, &opt_logpath }, { 0, "debug", "Enable debug subsystems", OPT_STR, &opt_log_debug }, #if ENABLE_TRACE { 0, "trace", "Enable trace subsystems", OPT_STR, &opt_log_trace }, #endif { 0, "fileline", "Add file and line numbers to debug", OPT_BOOL, &opt_fileline }, { 0, "threadid", "Add the thread ID to debug", OPT_BOOL, &opt_threadid }, { 0, "uidebug", "Enable webUI debug (non-minified JS)", OPT_BOOL, &opt_uidebug }, { 'A', "abort", "Immediately abort", OPT_BOOL, &opt_abort }, { 'D', "dump", "Enable coredumps for daemon", OPT_BOOL, &opt_dump }, { 0, "noacl", "Disable all access control checks", OPT_BOOL, &opt_noacl }, { 'j', "join", "Subscribe to a service permanently", OPT_STR, &opt_subscribe }, { 0, NULL, "TODO: testing", OPT_BOOL, NULL }, { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner }, { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile }, }; /* Get current directory */ tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0]))); /* Set locale */ setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); /* make sure the timezone is set */ tzset(); /* Process command line */ for (i = 1; i < argc; i++) { /* Find option */ cmdline_opt_t *opt = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]); if (!opt) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "invalid option specified [%s]", argv[i]); /* Process */ if (opt->type == OPT_BOOL) *((int*)opt->param) = 1; else if (++i == argc) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "option %s requires a value", opt->lopt); else if (opt->type == OPT_INT) *((int*)opt->param) = atoi(argv[i]); else if (opt->type == OPT_STR_LIST) { str_list_t *strl = opt->param; if (strl->num < strl->max) strl->str[strl->num++] = argv[i]; } else *((char**)opt->param) = argv[i]; /* Stop processing */ if (opt_help) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL); if (opt_version) show_version(argv[0]); } /* Additional cmdline processing */ #if ENABLE_LINUXDVB if (!opt_dvb_adapters) { adapter_mask = ~0; } else { char *p, *e; char *r = NULL; char *dvb_adapters = strdup(opt_dvb_adapters); adapter_mask = 0x0; p = strtok_r(dvb_adapters, ",", &r); while (p) { int a = strtol(p, &e, 10); if (*e != 0 || a < 0 || a > 31) { tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p); free(dvb_adapters); return 1; } adapter_mask |= (1 << a); p = strtok_r(NULL, ",", &r); } free(dvb_adapters); if (!adapter_mask) { tvhlog(LOG_ERR, "START", "No adapters specified!"); return 1; } } #endif if (tvheadend_webroot) { char *tmp; if (*tvheadend_webroot == '/') tmp = strdup(tvheadend_webroot); else { tmp = malloc(strlen(tvheadend_webroot)+2); *tmp = '/'; strcpy(tmp+1, tvheadend_webroot); } if (tmp[strlen(tmp)-1] == '/') tmp[strlen(tmp)-1] = '\0'; tvheadend_webroot = tmp; } tvheadend_webui_debug = opt_uidebug; /* Setup logging */ if (isatty(2)) log_options |= TVHLOG_OPT_DECORATE; if (opt_stderr || opt_syslog || opt_logpath) { if (!opt_log_trace && !opt_log_debug) log_debug = "all"; log_level = LOG_DEBUG; if (opt_stderr) log_options |= TVHLOG_OPT_DBG_STDERR; if (opt_syslog) log_options |= TVHLOG_OPT_DBG_SYSLOG; if (opt_logpath) log_options |= TVHLOG_OPT_DBG_FILE; } if (opt_fileline) log_options |= TVHLOG_OPT_FILELINE; if (opt_threadid) log_options |= TVHLOG_OPT_THREAD; if (opt_log_trace) { log_level = LOG_TRACE; log_trace = opt_log_trace; } if (opt_log_debug) log_debug = opt_log_debug; tvhlog_init(log_level, log_options, opt_logpath); tvhlog_set_debug(log_debug); tvhlog_set_trace(log_trace); signal(SIGPIPE, handle_sigpipe); // will be redundant later /* Daemonise */ if(opt_fork) { const char *homedir; gid_t gid; uid_t uid; struct group *grp = getgrnam(opt_group ?: "video"); struct passwd *pw = opt_user ? getpwnam(opt_user) : NULL; FILE *pidfile = fopen(opt_pidpath, "w+"); if(grp != NULL) { gid = grp->gr_gid; } else { gid = 1; } if (pw != NULL) { if (getuid() != pw->pw_uid) { gid_t glist[10]; int gnum; gnum = get_user_groups(pw, glist, 10); if (setgroups(gnum, glist)) { tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?"); return 1; } } uid = pw->pw_uid; homedir = pw->pw_dir; setenv("HOME", homedir, 1); } else { uid = 1; } if ((getgid() != gid) && setgid(gid)) { tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?"); return 1; } if ((getuid() != uid) && setuid(uid)) { tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?"); return 1; } if(daemon(0, 0)) { exit(2); } if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } /* Make dumpable */ if (opt_dump) { #ifdef PLATFORM_LINUX if (chdir("/tmp")) tvhwarn("START", "failed to change cwd to /tmp"); prctl(PR_SET_DUMPABLE, 1); #else tvhwarn("START", "Coredumps not implemented on your platform"); #endif } umask(0); } tvheadend_running = 1; /* Start log thread (must be done post fork) */ tvhlog_start(); /* Alter logging */ if (opt_fork) tvhlog_options &= ~TVHLOG_OPT_STDERR; if (!isatty(2)) tvhlog_options &= ~TVHLOG_OPT_DECORATE; /* Initialise clock */ pthread_mutex_lock(&global_lock); time(&dispatch_clock); /* Signal handling */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); trap_init(argv[0]); /* SSL library init */ OPENSSL_config(NULL); SSL_load_error_strings(); SSL_library_init(); /* Initialise configuration */ uuid_init(); idnode_init(); config_init(opt_config); /** * Initialize subsystems */ intlconv_init(); api_init(); fsmonitor_init(); #if ENABLE_LIBAV libav_init(); transcoding_init(); #endif imagecache_init(); http_client_init(opt_user_agent); esfilter_init(); service_init(); #if ENABLE_MPEGTS mpegts_init(adapter_mask, &opt_satip_xml, &opt_tsfile, opt_tsfile_tuner); #endif channel_init(); subscription_init(); access_init(opt_firstrun, opt_noacl); #if ENABLE_TIMESHIFT timeshift_init(); #endif tcp_server_init(opt_ipv6); http_server_init(opt_bindaddr); webui_init(opt_xspf); #if ENABLE_UPNP upnp_server_init(opt_bindaddr); #endif service_mapper_init(); descrambler_init(); epggrab_init(); epg_init(); dvr_init(); htsp_init(opt_bindaddr); if(opt_subscribe != NULL) subscription_dummy_join(opt_subscribe, 1); avahi_init(); bonjour_init(); epg_updated(); // cleanup now all prev ref's should have been created pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s", tvheadend_version, getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)), hts_settings_get_root()); if(opt_abort) abort(); mainloop(); #if ENABLE_UPNP tvhftrace("main", upnp_server_done); #endif tvhftrace("main", htsp_done); tvhftrace("main", http_server_done); tvhftrace("main", webui_done); tvhftrace("main", fsmonitor_done); #if ENABLE_MPEGTS tvhftrace("main", mpegts_done); #endif tvhftrace("main", http_client_done); // Note: the locking is obviously a bit redundant, but without // we need to disable the gtimer_arm call in epg_save() pthread_mutex_lock(&global_lock); tvhftrace("main", epg_save); #if ENABLE_TIMESHIFT tvhftrace("main", timeshift_term); #endif pthread_mutex_unlock(&global_lock); tvhftrace("main", epggrab_done); tvhftrace("main", tcp_server_done); tvhftrace("main", descrambler_done); tvhftrace("main", service_mapper_done); tvhftrace("main", service_done); tvhftrace("main", channel_done); tvhftrace("main", dvr_done); tvhftrace("main", subscription_done); tvhftrace("main", access_done); tvhftrace("main", epg_done); tvhftrace("main", avahi_done); tvhftrace("main", bonjour_done); tvhftrace("main", imagecache_done); tvhftrace("main", idnode_done); tvhftrace("main", lang_code_done); tvhftrace("main", api_done); tvhftrace("main", config_done); tvhftrace("main", hts_settings_done); tvhftrace("main", dvb_done); tvhftrace("main", lang_str_done); tvhftrace("main", esfilter_done); tvhftrace("main", intlconv_done); tvhftrace("main", urlparse_done); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); tvhlog_end(); if(opt_fork) unlink(opt_pidpath); free(opt_tsfile.str); free(opt_satip_xml.str); /* OpenSSL - welcome to the "cleanup" hell */ ENGINE_cleanup(); RAND_cleanup(); CRYPTO_cleanup_all_ex_data(); EVP_cleanup(); CONF_modules_free(); COMP_zlib_cleanup(); ERR_remove_state(0); ERR_free_strings(); { sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); } /* end of OpenSSL cleanup code */ return 0; } /** * */ void tvh_str_set(char **strp, const char *src) { free(*strp); *strp = src ? strdup(src) : NULL; } /** * */ int tvh_str_update(char **strp, const char *src) { if(src == NULL) return 0; free(*strp); *strp = strdup(src); return 1; } /** * */ void scopedunlock(pthread_mutex_t **mtxp) { pthread_mutex_unlock(*mtxp); }
int main(int argc, char *argv[]) { struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; int fib = -1; char *endptr; af = AF_UNSPEC; while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:np:Qq:rSTsuWw:xz")) != -1) switch(ch) { case '4': #ifdef INET af = AF_INET; #else errx(1, "IPv4 support is not compiled in"); #endif break; case '6': #ifdef INET6 af = AF_INET6; #else errx(1, "IPv6 support is not compiled in"); #endif break; case 'A': Aflag = 1; break; case 'a': aflag = 1; break; case 'B': Bflag = 1; break; case 'b': bflag = 1; break; case 'd': dflag = 1; break; case 'F': fib = strtol(optarg, &endptr, 0); if (*endptr != '\0' || (fib == 0 && (errno == EINVAL || errno == ERANGE))) errx(1, "%s: invalid fib", optarg); break; case 'f': if (strcmp(optarg, "ipx") == 0) af = AF_IPX; else if (strcmp(optarg, "inet") == 0) af = AF_INET; #ifdef INET6 else if (strcmp(optarg, "inet6") == 0) af = AF_INET6; #endif #ifdef IPSEC else if (strcmp(optarg, "pfkey") == 0) af = PF_KEY; #endif else if (strcmp(optarg, "unix") == 0) af = AF_UNIX; else if (strcmp(optarg, "atalk") == 0) af = AF_APPLETALK; #ifdef NETGRAPH else if (strcmp(optarg, "ng") == 0 || strcmp(optarg, "netgraph") == 0) af = AF_NETGRAPH; #endif else if (strcmp(optarg, "link") == 0) af = AF_LINK; else { errx(1, "%s: unknown address family", optarg); } break; case 'g': gflag = 1; break; case 'h': hflag = 1; break; case 'I': { char *cp; iflag = 1; for (cp = interface = optarg; isalpha(*cp); cp++) continue; unit = atoi(cp); break; } case 'i': iflag = 1; break; case 'L': Lflag = 1; break; case 'M': memf = optarg; break; case 'm': mflag = 1; break; case 'N': nlistf = optarg; break; case 'n': numeric_addr = numeric_port = 1; break; case 'p': if ((tp = name2protox(optarg)) == NULL) { errx(1, "%s: unknown or uninstrumented protocol", optarg); } pflag = 1; break; case 'Q': Qflag = 1; break; case 'q': noutputs = atoi(optarg); if (noutputs != 0) noutputs++; break; case 'r': rflag = 1; break; case 's': ++sflag; break; case 'S': numeric_addr = 1; break; case 'u': af = AF_UNIX; break; case 'W': case 'l': Wflag = 1; break; case 'w': interval = atoi(optarg); iflag = 1; break; case 'T': Tflag = 1; break; case 'x': xflag = 1; break; case 'z': zflag = 1; break; case '?': default: usage(); } argv += optind; argc -= optind; #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { if (isdigit(**argv)) { interval = atoi(*argv); if (interval <= 0) usage(); ++argv; iflag = 1; } if (*argv) { nlistf = *argv; if (*++argv) memf = *argv; } } #endif /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ live = (nlistf == NULL && memf == NULL); if (!live) setgid(getgid()); if (xflag && Tflag) errx(1, "-x and -T are incompatible, pick one."); if (Bflag) { if (!live) usage(); bpf_stats(interface); exit(0); } if (mflag) { if (!live) { if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_SFSTAT].n_value); } else mbpr(NULL, 0); exit(0); } if (Qflag) { if (!live) { if (kread(0, NULL, 0) == 0) netisr_stats(kvmd); } else netisr_stats(NULL); exit(0); } #if 0 /* * Keep file descriptors open to avoid overhead * of open/close on each call to get* routines. */ sethostent(1); setnetent(1); #else /* * This does not make sense any more with DNS being default over * the files. Doing a setXXXXent(1) causes a tcp connection to be * used for the queries, which is slower. */ #endif if (iflag && !sflag) { intpr(interval, NULL, af); exit(0); } if (rflag) { if (sflag) { rt_stats(); flowtable_stats(); } else routepr(fib, af); exit(0); } if (gflag) { if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mrt6_stats(); #endif } else { if (af == AF_INET || af == AF_UNSPEC) mroutepr(); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) mroute6pr(); #endif } exit(0); } /* Load all necessary kvm symbols */ kresolve_list(nl); if (tp) { printproto(tp, tp->pr_name); exit(0); } if (af == AF_INET || af == AF_UNSPEC) for (tp = protox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #ifdef INET6 if (af == AF_INET6 || af == AF_UNSPEC) for (tp = ip6protox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #endif /*INET6*/ #ifdef IPSEC if (af == PF_KEY || af == AF_UNSPEC) for (tp = pfkeyprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #endif /*IPSEC*/ #ifdef IPX if (af == AF_IPX || af == AF_UNSPEC) { for (tp = ipxprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); } #endif /* IPX */ if (af == AF_APPLETALK || af == AF_UNSPEC) for (tp = atalkprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #ifdef NETGRAPH if (af == AF_NETGRAPH || af == AF_UNSPEC) for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #endif /* NETGRAPH */ if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value, nl[N_UNP_SPHEAD].n_value); exit(0); }
int main(int argc, char *argv[]) { struct kinfo_proc *kp; struct kinfo_proc *dkp; struct stat *stp; time_t touched; int ch, i, nentries, nusers, wcmd, longidle, longattime, dropgid; const char *memf, *nlistf, *p; char *x_suffix; char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX]; char fn[MAXHOSTNAMELEN]; char *dot; (void)setlocale(LC_ALL, ""); use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0'); use_comma = (*nl_langinfo(RADIXCHAR) != ','); /* Are we w(1) or uptime(1)? */ if (this_is_uptime(argv[0]) == 0) { wcmd = 0; p = ""; } else { wcmd = 1; p = "dhiflM:N:nsuw"; } dropgid = 0; memf = _PATH_DEVNULL; nlistf = NULL; while ((ch = getopt(argc, argv, p)) != -1) switch (ch) { case 'd': dflag = 1; break; case 'h': header = 0; break; case 'i': sortidle = 1; break; case 'M': header = 0; memf = optarg; dropgid = 1; break; case 'N': nlistf = optarg; dropgid = 1; break; case 'n': nflag = 1; break; case 'f': case 'l': case 's': case 'u': case 'w': warnx("[-flsuw] no longer supported"); /* FALLTHROUGH */ case '?': default: usage(wcmd); } argc -= optind; argv += optind; if (!(_res.options & RES_INIT)) res_init(); _res.retrans = 2; /* resolver timeout to 2 seconds per try */ _res.retry = 1; /* only try once.. */ /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ if (dropgid) setgid(getgid()); if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL) errx(1, "%s", errbuf); (void)time(&now); if (*argv) sel_users = argv; setutxent(); for (nusers = 0; (utmp = getutxent()) != NULL;) { if (utmp->ut_type != USER_PROCESS) continue; if (!(stp = ttystat(utmp->ut_line))) continue; /* corrupted record */ ++nusers; if (wcmd == 0) continue; if (sel_users) { int usermatch; char **user; usermatch = 0; for (user = sel_users; !usermatch && *user; user++) if (!strcmp(utmp->ut_user, *user)) usermatch = 1; if (!usermatch) continue; } if ((ep = calloc(1, sizeof(struct entry))) == NULL) errx(1, "calloc"); *nextp = ep; nextp = &ep->next; memmove(&ep->utmp, utmp, sizeof *utmp); ep->tdev = stp->st_rdev; /* * If this is the console device, attempt to ascertain * the true console device dev_t. */ if (ep->tdev == 0) { size_t size; size = sizeof(dev_t); (void)sysctlbyname("machdep.consdev", &ep->tdev, &size, NULL, 0); } touched = stp->st_atime; if (touched < ep->utmp.ut_tv.tv_sec) { /* tty untouched since before login */ touched = ep->utmp.ut_tv.tv_sec; } if ((ep->idle = now - touched) < 0) ep->idle = 0; } endutxent(); if (header || wcmd == 0) { pr_header(&now, nusers); if (wcmd == 0) { (void)kvm_close(kd); exit(0); } #define HEADER_USER "USER" #define HEADER_TTY "TTY" #define HEADER_FROM "FROM" #define HEADER_LOGIN_IDLE "LOGIN@ IDLE " #define HEADER_WHAT "WHAT\n" #define WUSED (W_DISPUSERSIZE + W_DISPLINESIZE + W_DISPHOSTSIZE + \ sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */ (void)printf("%-*.*s %-*.*s %-*.*s %s", W_DISPUSERSIZE, W_DISPUSERSIZE, HEADER_USER, W_DISPLINESIZE, W_DISPLINESIZE, HEADER_TTY, W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM, HEADER_LOGIN_IDLE HEADER_WHAT); } if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL) err(1, "%s", kvm_geterr(kd)); for (i = 0; i < nentries; i++, kp++) { if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB || kp->ki_tdev == NODEV) continue; for (ep = ehead; ep != NULL; ep = ep->next) { if (ep->tdev == kp->ki_tdev) { /* * proc is associated with this terminal */ if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) { /* * Proc is 'most interesting' */ if (proc_compare(ep->kp, kp)) ep->kp = kp; } /* * Proc debug option info; add to debug * list using kinfo_proc ki_spare[0] * as next pointer; ptr to ptr avoids the * ptr = long assumption. */ dkp = ep->dkp; ep->dkp = kp; debugproc(kp) = dkp; } } } if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 && ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 && ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0) ttywidth = 79; else ttywidth = ws.ws_col - 1; argwidth = ttywidth - WUSED; if (argwidth < 4) argwidth = 8; for (ep = ehead; ep != NULL; ep = ep->next) { if (ep->kp == NULL) { ep->args = strdup("-"); continue; } ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth), ep->kp->ki_comm, MAXCOMLEN); if (ep->args == NULL) err(1, NULL); } /* sort by idle time */ if (sortidle && ehead != NULL) { struct entry *from, *save; from = ehead; ehead = NULL; while (from != NULL) { for (nextp = &ehead; (*nextp) && from->idle >= (*nextp)->idle; nextp = &(*nextp)->next) continue; save = from; from = from->next; save->next = *nextp; *nextp = save; } } for (ep = ehead; ep != NULL; ep = ep->next) { struct addrinfo hints, *res; struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr_in *lsin = (struct sockaddr_in *)&ss; struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss; time_t t; int isaddr; p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-"; if ((x_suffix = strrchr(p, ':')) != NULL) { if ((dot = strchr(x_suffix, '.')) != NULL && strchr(dot+1, '.') == NULL) *x_suffix++ = '\0'; else x_suffix = NULL; } isaddr = 0; memset(&ss, '\0', sizeof(ss)); if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) { lsin6->sin6_len = sizeof(*lsin6); lsin6->sin6_family = AF_INET6; isaddr = 1; } else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) { lsin->sin_len = sizeof(*lsin); lsin->sin_family = AF_INET; isaddr = 1; } if (!nflag) { /* Attempt to change an IP address into a name */ if (isaddr && realhostname_sa(fn, sizeof(fn), sa, sa->sa_len) == HOSTNAME_FOUND) p = fn; } else if (!isaddr) { /* * If a host has only one A/AAAA RR, change a * name into an IP address */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(p, NULL, &hints, &res) == 0) { if (res->ai_next == NULL && getnameinfo(res->ai_addr, res->ai_addrlen, fn, sizeof(fn), NULL, 0, NI_NUMERICHOST) == 0) p = fn; freeaddrinfo(res); } } if (x_suffix) { (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix); p = buf; } if (dflag) { for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) { const char *ptr; ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth), dkp->ki_comm, MAXCOMLEN); if (ptr == NULL) ptr = "-"; (void)printf("\t\t%-9d %s\n", dkp->ki_pid, ptr); } } (void)printf("%-*.*s %-*.*s %-*.*s ", W_DISPUSERSIZE, W_DISPUSERSIZE, ep->utmp.ut_user, W_DISPLINESIZE, W_DISPLINESIZE, *ep->utmp.ut_line ? (strncmp(ep->utmp.ut_line, "tty", 3) && strncmp(ep->utmp.ut_line, "cua", 3) ? ep->utmp.ut_line : ep->utmp.ut_line + 3) : "-", W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-"); t = ep->utmp.ut_tv.tv_sec; longattime = pr_attime(&t, &now); longidle = pr_idle(ep->idle); (void)printf("%.*s\n", argwidth - longidle - longattime, ep->args); } (void)kvm_close(kd); exit(0); }
/* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int grantpt (int fd) { int retval = -1; #ifdef PATH_MAX char _buf[PATH_MAX]; #else char _buf[512]; #endif char *buf = _buf; struct stat st; uid_t uid; gid_t gid; pid_t pid; if (pts_name (fd, &buf, sizeof (_buf))) return -1; if (stat(buf, &st) < 0) goto cleanup; /* Make sure that we own the device. */ uid = getuid (); if (st.st_uid != uid) { if (chown (buf, uid, st.st_gid) < 0) goto helper; } gid = getgid (); /* Make sure the group of the device is that special group. */ if (st.st_gid != gid) { if (chown (buf, uid, gid) < 0) goto helper; } /* Make sure the permission mode is set to readable and writable by the owner, and writable by the group. */ if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)) { if (chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0) goto helper; } retval = 0; goto cleanup; /* We have to use the helper program. */ helper: pid = vfork (); if (pid == -1) goto cleanup; else if (pid == 0) { /* Disable core dumps. */ struct rlimit rl = { 0, 0 }; setrlimit (RLIMIT_CORE, &rl); /* We pase the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO) if (dup2 (fd, PTY_FILENO) < 0) _exit (FAIL_EBADF); execle (_PATH_PT_CHOWN, _PATH_PT_CHOWN, NULL, NULL); _exit (FAIL_EXEC); } else { int w; if (waitpid (pid, &w, 0) == -1) goto cleanup; if (!WIFEXITED (w)) errno = ENOEXEC; else switch (WEXITSTATUS(w)) { case 0: retval = 0; break; case FAIL_EBADF: errno = EBADF; break; case FAIL_EINVAL: errno = EINVAL; break; case FAIL_EACCES: errno = EACCES; break; case FAIL_EXEC: errno = ENOEXEC; break; default: assert(! "getpt: internal error: invalid exit code from pt_chown"); } } cleanup: if (buf != _buf) free (buf); return retval; }
void edit_file(char *buf) /* copy file to a temp file, edit that file, and install it if necessary */ { char *cureditor = NULL; char editorcmd[PATH_LEN]; pid_t pid; int status; struct stat st; time_t mtime = 0; char *tmp_str; FILE *f, *fi; int file = 0; int c; char correction = 0; short return_val = EXIT_OK; explain("fcrontab : editing %s's fcrontab", user); if ((cureditor=getenv("VISUAL")) == NULL || strcmp(cureditor, "\0") == 0 ) if((cureditor=getenv("EDITOR"))==NULL || strcmp(cureditor, "\0") == 0 ) cureditor = editor; file = temp_file(&tmp_str); if ( (fi = fdopen(file, "w")) == NULL ) { error_e("could not fdopen"); goto exiterr; } #ifndef USE_SETE_ID if (fchown(file, asuid, asgid) != 0) { error_e("Could not fchown %s to asuid and asgid", tmp_str); goto exiterr; } #endif /* copy user's fcrontab (if any) to a temp file */ if ( (f = fopen(buf, "r")) == NULL ) { if ( errno != ENOENT ) { error_e("could not open file %s", buf); goto exiterr; } else fprintf(stderr, "no fcrontab for %s - using an empty one\n", user); } else { /* copy original file to temp file */ while ( (c=getc(f)) != EOF ) putc(c, fi); fclose(f); } fclose(fi); close(file); do { if ( stat(tmp_str, &st) == 0 ) mtime = st.st_mtime; else { error_e("could not stat \"%s\"", buf); goto exiterr; } switch ( pid = fork() ) { case 0: /* child */ if ( uid != ROOTUID ) { if (setgid(asgid) < 0) { error_e("setgid(asgid)"); goto exiterr; } if (setuid(asuid) < 0) { error_e("setuid(asuid)"); goto exiterr; } } else { /* Some programs, like perl, require gid=egid : */ if ( setgid(getgid()) < 0 ) { error_e("setgid(getgid())"); goto exiterr; } } snprintf(editorcmd, sizeof(editorcmd), "%s %s", cureditor, tmp_str); execlp(shell, shell, "-c", editorcmd, tmp_str, NULL); error_e("Error while running \"%s\"", cureditor); goto exiterr; case -1: error_e("fork"); goto exiterr; default: /* parent */ break ; } /* only reached by parent */ waitpid(pid, &status, 0); if ( ! WIFEXITED(status) ) { fprintf(stderr, "Editor exited abnormally:" " fcrontab is unchanged.\n"); goto exiterr; } #ifndef USE_SETE_ID /* we have chown the tmp file to user's name : user may have * linked the tmp file to a file owned by root. In that case, as * fcrontab is setuid root, user may read some informations he is not * allowed to read : * we *must* check that the tmp file is not a link. */ /* open the tmp file, chown it to root and chmod it to avoid race * conditions */ /* make sure that the tmp file is not a link */ { int fd = 0; if ( (fd = open(tmp_str, O_RDONLY)) <= 0 || fstat(fd, &st) != 0 || ! S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || st.st_uid != asuid || st.st_nlink > 1){ fprintf(stderr, "%s is not a valid regular file.\n", tmp_str); close(fd); goto exiterr; } if ( fchown(fd, ROOTUID, ROOTGID) != 0 || fchmod(fd, S_IRUSR|S_IWUSR) != 0 ){ fprintf(stderr, "Can't chown or chmod %s.\n", tmp_str); close(fd); goto exiterr; } close(fd); } #endif /* check if file has been modified */ if ( stat(tmp_str, &st) != 0 ) { error_e("could not stat %s", tmp_str); goto exiterr; } else if ( st.st_mtime > mtime || correction == 1) { correction = 0; switch ( read_file(tmp_str) ) { case ERR: goto exiterr; case 2: fprintf(stderr, "\nFile contains some errors. " "Ignore [i] or Correct [c] ? "); /* the 2nd getchar() is for the newline char (\n) */ while ( (c = getchar()) && c != 'i' && c != 'c' ) { fprintf(stderr, "Please press c to correct, " "or i to ignore: "); while (c != '\n') c = getchar(); } if ( c == 'c' ) { /* free memory used to store the list */ delete_file(user); correction = 1; } break; default: break; } } else { fprintf(stderr, "Fcrontab is unchanged :" " no need to install it.\n"); goto end; } } while ( correction == 1); if ( write_file(tmp_str) != OK ) return_val = EXIT_ERR; /* free memory used to store the list */ delete_file(user); /* tell daemon to update the conf */ need_sig = 1; end: if ( remove(tmp_str) != 0 ) error_e("could not remove %s", tmp_str); free(tmp_str); xexit (return_val); exiterr: if ( remove(tmp_str) != 0 ) error_e("could not remove %s", tmp_str); free(tmp_str); xexit (EXIT_ERR); }
int main(int argc, char *argv[]) { int argPos; int result; char *targetSuidPath="/bin/su"; char *helperSuidPath="/bin/mount"; for(argPos=1; argPos<argc; argPos++) { char *argName=argv[argPos]; if(!strcmp(argName, "--")) { argPos++; break; } if(strncmp(argName, "--", 2)) { break; } fprintf(stderr, "%s: unknown argument %s\n", argv[0], argName); exit(1); } mkdir("/tmp/x", 0700); mkdir("/tmp/x/bin", 0700); mkdir("/tmp/x/over", 0700); // Create child; child commences execution in childFunc() // CLONE_NEWNS: new mount namespace // CLONE_NEWPID // CLONE_NEWUTS pid_t pid=clone(childFunc, child_stack+STACK_SIZE, CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, argv+argPos); if(pid==-1) { fprintf(stderr, "Clone failed: %d (%s)\n", errno, strerror(errno)); return(1); } char idMapFileName[128]; char idMapData[128]; sprintf(idMapFileName, "/proc/%d/setgroups", pid); int setGroupsFd=open(idMapFileName, O_WRONLY); if(setGroupsFd<0) { fprintf(stderr, "Failed to open setgroups\n"); return(1); } result=write(setGroupsFd, "deny", 4); if(result<0) { fprintf(stderr, "Failed to disable setgroups\n"); return(1); } close(setGroupsFd); sprintf(idMapFileName, "/proc/%d/uid_map", pid); fprintf(stderr, "Setting uid map in %s\n", idMapFileName); int uidMapFd=open(idMapFileName, O_WRONLY); if(uidMapFd<0) { fprintf(stderr, "Failed to open uid map\n"); return(1); } sprintf(idMapData, "0 %d 1\n", getuid()); result=write(uidMapFd, idMapData, strlen(idMapData)); if(result<0) { fprintf(stderr, "UID map write failed: %d (%s)\n", errno, strerror(errno)); return(1); } close(uidMapFd); sprintf(idMapFileName, "/proc/%d/gid_map", pid); fprintf(stderr, "Setting gid map in %s\n", idMapFileName); int gidMapFd=open(idMapFileName, O_WRONLY); if(gidMapFd<0) { fprintf(stderr, "Failed to open gid map\n"); return(1); } sprintf(idMapData, "0 %d 1\n", getgid()); result=write(gidMapFd, idMapData, strlen(idMapData)); if(result<0) { fprintf(stderr, "GID map write failed: %d (%s)\n", errno, strerror(errno)); return(1); } close(gidMapFd); // Wait until /tmp/x/over/su exists struct stat statBuf; while(1) { usleep(100); result=stat("/tmp/x/over/su", &statBuf); if(!result) break; } // Overwrite the file sprintf(idMapFileName, "/proc/%d/cwd/su", pid); // No slashes allowed, everything else is OK. char suidExecMinimalElf[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00, 0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xa2, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa4, 0x90, 0x04, 0x08, 0xa4, 0x90, 0x04, 0x08, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xc0, 0x89, 0xc8, 0x89, 0xd0, 0x89, 0xd8, 0x04, 0xd2, 0xcd, 0x80, 0x31, 0xc0, 0x04, 0xd0, 0xcd, 0x80, 0x31, 0xc0, 0x89, 0xd0, 0xb0, 0x0b, 0x89, 0xe1, 0x83, 0xc1, 0x08, 0x8b, 0x19, 0xcd, 0x80 }; char *helperArgs[]={"/bin/mount", NULL}; int destFd=open(idMapFileName, O_RDWR|O_CREAT|O_TRUNC, 07777); if(destFd<0) { fprintf(stderr, "Failed to open %s, error %s\n", idMapFileName, strerror(errno)); return(1); } char *suidWriteNext=suidExecMinimalElf; char *suidWriteEnd=suidExecMinimalElf+sizeof(suidExecMinimalElf); while(suidWriteNext!=suidWriteEnd) { char *suidWriteTestPos=suidWriteNext; while((!*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd)) suidWriteTestPos++; // We cannot write any 0-bytes. So let seek fill up the file wihh // null-bytes for us. lseek(destFd, suidWriteTestPos-suidExecMinimalElf, SEEK_SET); suidWriteNext=suidWriteTestPos; while((*suidWriteTestPos)&&(suidWriteTestPos!=suidWriteEnd)) suidWriteTestPos++; pid_t helperPid=fork(); if(!helperPid) { struct rlimit limits; // We can't truncate, that would remove the setgid property of // the file. So make sure the SUID binary does not write too much. limits.rlim_cur=suidWriteTestPos-suidExecMinimalElf; limits.rlim_max=limits.rlim_cur; setrlimit(RLIMIT_FSIZE, &limits); // Do not rely on some SUID binary to print out the unmodified // program name, some OSes might have hardening against that. // Let the ld-loader will do that for us. limits.rlim_cur=1<<22; limits.rlim_max=limits.rlim_cur; result=setrlimit(RLIMIT_AS, &limits); dup2(destFd, 1); dup2(destFd, 2); helperArgs[0]=suidWriteNext; execve(helperSuidPath, helperArgs, NULL); fprintf(stderr, "Exec failed\n"); return(1); } waitpid(helperPid, NULL, 0); suidWriteNext=suidWriteTestPos; } close(destFd); execve(idMapFileName, argv+argPos-1, NULL); fprintf(stderr, "Failed to execute %s: %d (%s)\n", idMapFileName, errno, strerror(errno)); return(1); }
static int callback_login(struct userid_callback *a, void *vp) { struct userid_info *uinfo=(struct userid_info *)vp; struct stat stat_buf; time_t t; char curdir[1024]; char *token=NULL; if (stat(a->homedir, &stat_buf) < 0) return (-1); if (stat_buf.st_mode & S_ISVTX) { errno=EAGAIN; return (1); } time(&t); if (!uinfo->isproxy) { token=authtoken_create(uinfo->userid, t); if (!token) { syslog(LOG_NOTICE, "pcpd: authtoken_create() failed."); maildir_cache_cancel(); return (1); } } maildir_cache_start(); libmail_changeuidgid(a->uid, getgid()); if (chdir(a->homedir) < 0) { free(token); syslog(LOG_NOTICE, "pcpd: chdir(%s) failed.", a->homedir); maildir_cache_cancel(); exit(1); } if (chdir(a->maildir && *a->maildir ? a->maildir:"Maildir") < 0) { free(token); syslog(LOG_NOTICE, "pcpd: chdir(Maildir) failed."); maildir_cache_cancel(); exit(1); } mkdir("calendar", 0700); if (chdir("calendar") < 0) { free(token); syslog(LOG_NOTICE, "pcpd: chdir(Maildir) failed."); maildir_cache_cancel(); exit(1); } curdir[sizeof(curdir)-1]=0; if (getcwd(curdir, sizeof(curdir)-1) == 0) { syslog(LOG_NOTICE, "pcpd: getcwd() failed."); maildir_cache_cancel(); exit(1); } maildir_cache_save(uinfo->userid, t, curdir, a->uid, getgid()); alarm(0); if (!uinfo->isproxy) { printf("102 %s logged in.\n", token); free(token); } return (0); }
FILE *Popen(char * const parameters[], const char *type) { FILE *iop; struct pid *cur; int pdes[2], pid; if (parameters == NULL || type == NULL) { return NULL; } if ((*type != 'r' && *type != 'w') || type[1]) { return NULL; } if ((cur = (struct pid *) malloc(sizeof(struct pid))) == NULL) { return NULL; } if (pipe(pdes) < 0) { free(cur); return NULL; } // // Block all signals until command is exited. // We need to gather information about the // child in Pclose(). // DisableSignals(); switch (pid = Fork()) { case -1: { // // Error. // #ifdef PANIC *logofs << "Popen: PANIC! Function fork failed. " << "Error is " << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; #endif cerr << "Error" << ": Function fork failed. " << "Error is " << EGET() << " '" << ESTR() << "'.\n"; close(pdes[0]); close(pdes[1]); free(cur); return NULL; } case 0: { // // Child. // setgid(getgid()); setuid(getuid()); if (*type == 'r') { if (pdes[1] != 1) { // // Set up stdout. // dup2(pdes[1], 1); close(pdes[1]); } close(pdes[0]); } else { if (pdes[0] != 0) { // // Set up stdin. // dup2(pdes[0], 0); close(pdes[0]); } close(pdes[1]); } execvp(parameters[0], parameters + 1); exit(127); } } // // Parent. Save data about the child. // RegisterChild(pid); if (*type == 'r') { iop = fdopen(pdes[0], type); close(pdes[1]); } else { iop = fdopen(pdes[1], type); close(pdes[0]); } cur -> fp = iop; cur -> self = pid; cur -> next = pidlist; pidlist = cur; #ifdef TEST *logofs << "Popen: Executing "; for (int i = 0; i < 256 && parameters[i] != NULL; i++) { *logofs << "[" << parameters[i] << "]"; } *logofs << " with descriptor " << fileno(iop) << ".\n" << logofs_flush; #endif return iop; }
/* ============== VID_LoadRefresh ============== */ qboolean VID_LoadRefresh( char *name ) { refimport_t ri; GetRefAPI_t GetRefAPI; char fn[MAX_OSPATH]; struct stat st; extern uid_t saved_euid; FILE *fp; if ( reflib_active ) { if (KBD_Close_fp) KBD_Close_fp(); if (RW_IN_Shutdown_fp) RW_IN_Shutdown_fp(); KBD_Close_fp = NULL; RW_IN_Shutdown_fp = NULL; re.Shutdown(); VID_FreeReflib (); } Com_Printf( "------- Loading %s -------\n", name ); //regain root seteuid(saved_euid); if ((fp = fopen(so_file, "r")) == NULL) { Com_Printf( "LoadLibrary(\"%s\") failed: can't open %s (required for location of ref libraries)\n", name, so_file); return false; } fgets(fn, sizeof(fn), fp); fclose(fp); while (*fn && isspace(fn[strlen(fn) - 1])) fn[strlen(fn) - 1] = 0; strcat(fn, "/"); strcat(fn, name); // permission checking if (strstr(fn, "softx") == NULL) { // softx doesn't require root if (stat(fn, &st) == -1) { Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name, strerror(errno)); return false; } #if 0 if (st.st_uid != 0) { Com_Printf( "LoadLibrary(\"%s\") failed: ref is not owned by root\n", name); return false; } if ((st.st_mode & 0777) & ~0700) { Com_Printf( "LoadLibrary(\"%s\") failed: invalid permissions, must be 700 for security considerations\n", name); return false; } #endif } else { // softx requires we give up root now setreuid(getuid(), getuid()); setegid(getgid()); } if ( ( reflib_library = dlopen( fn, RTLD_LAZY | RTLD_GLOBAL ) ) == 0 ) { Com_Printf( "LoadLibrary(\"%s\") failed: %s\n", name , dlerror()); return false; } Com_Printf( "LoadLibrary(\"%s\")\n", fn ); ri.Cmd_AddCommand = Cmd_AddCommand; ri.Cmd_RemoveCommand = Cmd_RemoveCommand; ri.Cmd_Argc = Cmd_Argc; ri.Cmd_Argv = Cmd_Argv; ri.Cmd_ExecuteText = Cbuf_ExecuteText; ri.Con_Printf = VID_Printf; ri.Sys_Error = VID_Error; ri.FS_LoadFile = FS_LoadFile; ri.FS_FreeFile = FS_FreeFile; ri.FS_Gamedir = FS_Gamedir; ri.Cvar_Get = Cvar_Get; ri.Cvar_Set = Cvar_Set; ri.Cvar_SetValue = Cvar_SetValue; ri.Vid_GetModeInfo = VID_GetModeInfo; ri.Vid_MenuInit = VID_MenuInit; ri.Vid_NewWindow = VID_NewWindow; if ( ( GetRefAPI = (void *) dlsym( reflib_library, "GetRefAPI" ) ) == 0 ) Com_Error( ERR_FATAL, "dlsym failed on %s", name ); re = GetRefAPI( ri ); if (re.api_version != API_VERSION) { VID_FreeReflib (); Com_Error (ERR_FATAL, "%s has incompatible api_version", name); } /* Init IN (Mouse) */ in_state.IN_CenterView_fp = IN_CenterView; in_state.Key_Event_fp = Do_Key_Event; in_state.viewangles = cl.viewangles; in_state.in_strafe_state = &in_strafe.state; if ((RW_IN_Init_fp = dlsym(reflib_library, "RW_IN_Init")) == NULL || (RW_IN_Shutdown_fp = dlsym(reflib_library, "RW_IN_Shutdown")) == NULL || (RW_IN_Activate_fp = dlsym(reflib_library, "RW_IN_Activate")) == NULL || (RW_IN_Commands_fp = dlsym(reflib_library, "RW_IN_Commands")) == NULL || (RW_IN_Move_fp = dlsym(reflib_library, "RW_IN_Move")) == NULL || (RW_IN_Frame_fp = dlsym(reflib_library, "RW_IN_Frame")) == NULL) Sys_Error("No RW_IN functions in REF.\n"); Real_IN_Init(); if ( re.Init( 0, 0 ) == -1 ) { re.Shutdown(); VID_FreeReflib (); return false; } /* Init KBD */ #if 1 if ((KBD_Init_fp = dlsym(reflib_library, "KBD_Init")) == NULL || (KBD_Update_fp = dlsym(reflib_library, "KBD_Update")) == NULL || (KBD_Close_fp = dlsym(reflib_library, "KBD_Close")) == NULL) Sys_Error("No KBD functions in REF.\n"); #else { void KBD_Init(void); void KBD_Update(void); void KBD_Close(void); KBD_Init_fp = KBD_Init; KBD_Update_fp = KBD_Update; KBD_Close_fp = KBD_Close; } #endif KBD_Init_fp(Do_Key_Event); // give up root now setreuid(getuid(), getuid()); setegid(getgid()); Com_Printf( "------------------------------------\n"); reflib_active = true; return true; }
/** * main * * Entry point for shroudBNC. */ int main(int argc, char **argv) { #ifdef _WIN32 char TclLibrary[512]; #endif CConfig *Config; bool Daemonize, Usage; char *ConfigDir = NULL, *LogDir = NULL, *DataDir = NULL, *PidPath = NULL; g_ArgC = argc; g_ArgV = argv; sbncGetExePath(); // first call sets exe path in static var Daemonize = true; Usage = false; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--config") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing parameter for --config: You need to specify the config directory."); return EXIT_FAILURE; } ConfigDir = argv[i + 1]; i++; continue; } if (strcmp(argv[i], "--log") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing parameter for --log: You need to specify the log directory."); return EXIT_FAILURE; } LogDir = argv[i + 1]; i++; continue; } if (strcmp(argv[i], "--data") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing parameter for --log: You need to specify the log directory."); return EXIT_FAILURE; } DataDir = argv[i + 1]; i++; continue; } if (strcmp(argv[i], "--pid") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing parameter for --pid: You need to specify the PID path."); return EXIT_FAILURE; } PidPath = argv[i + 1]; i++; continue; } if (strcmp(argv[i], "--lpc") == 0) { fprintf(stderr, "Warning: Ignoring --lpc (which is now the default behaviour.)\n"); continue; } if (strcmp(argv[i], "--foreground") == 0) { Daemonize = false; continue; } if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "/?") == 0) { Usage = true; continue; } fprintf(stderr, "Unknown command-line option: '%s'\n", argv[i]); return EXIT_FAILURE; } bool WasNull = false; if (ConfigDir == NULL) { WasNull = true; ConfigDir = sbncFindConfigDir(); } if (mkdir(ConfigDir) < 0 && errno != EEXIST) { fprintf(stderr, "Config directory (%s) could not be created: %s\n", ConfigDir, strerror(errno)); free(ConfigDir); return EXIT_FAILURE; } sbncSetConfigPath(ConfigDir); if (LogDir) sbncSetLogPath(LogDir); else if (DataDir) sbncSetLogPath(DataDir); else sbncSetLogPath(ConfigDir); if (DataDir) sbncSetDataPath(DataDir); else sbncSetDataPath(ConfigDir); if (PidPath) sbncSetPidPath(PidPath); else sbncSetPidPath(sbncBuildPath("sbnc.pid", sbncGetDataPath())); if (WasNull) free(ConfigDir); if (chdir(sbncGetDataPath()) < 0) { fprintf(stderr, "Could not chdir() into data directory (%s): %s\n", sbncGetDataPath(), strerror(errno)); free(ConfigDir); return EXIT_FAILURE; } fprintf(stderr, "shroudBNC (version: " BNCVERSION ") - an object-oriented IRC bouncer\n"); fprintf(stderr, "Configuration directory: %s\n", sbncGetConfigPath()); fprintf(stderr, "Log directory: %s\n", sbncGetLogPath()); fprintf(stderr, "Data directory: %s\n", sbncGetDataPath()); fprintf(stderr, "PID path: %s\n", sbncGetPidPath()); if (Usage) { fprintf(stderr, "\n"); fprintf(stderr, "Syntax: %s [OPTION]", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, "\t--help\t\t\tdisplay this help and exit\n"); fprintf(stderr, "\t--foreground\t\trun in the foreground\n"); fprintf(stderr, "\t--config <config dir>\tspecifies the location of the configuration directory.\n"); fprintf(stderr, "\t--data <data dir>\tspecifies the location of the data directory (defaults to the config directory).\n"); fprintf(stderr, "\t--log <log dir>\tspecifies the location of the log directory (defaults to the data directory if given, else the config directory).\n"); fprintf(stderr, "\t--pid <pid path>\tspecifies the location of the PID file (defaults to <data dir>/sbnc.pid).\n"); return 3; } #ifdef _WIN32 if (!GetEnvironmentVariable("TCL_LIBRARY", TclLibrary, sizeof(TclLibrary)) || strlen(TclLibrary) == 0) { SetEnvironmentVariable("TCL_LIBRARY", "./tcl8.4"); } #endif srand((unsigned int)time(NULL)); #ifndef _WIN32 if (getuid() == 0 || geteuid() == 0 || getgid() == 0 || getegid() == 0) { printf("You cannot run shroudBNC as 'root' or using an account which has 'wheel' " "privileges. Use an ordinary user account and remove the suid bit if it is set.\n"); return EXIT_FAILURE; } rlimit core_limit = { INT_MAX, INT_MAX }; setrlimit(RLIMIT_CORE, &core_limit); #endif #if !defined(_WIN32 ) || defined(__MINGW32__) lt_dlinit(); #endif time(&g_CurrentTime); Config = new CConfig(sbncBuildPath("sbnc.conf", NULL), NULL); if (Config == NULL) { printf("Fatal: could not create config object."); #if !defined(_WIN32 ) || defined(__MINGW32__) lt_dlexit(); #endif return EXIT_FAILURE; } // constructor sets g_Bouncer new CCore(Config, argc, argv); #if !defined(_WIN32) signal(SIGPIPE, SIG_IGN); #endif g_Bouncer->StartMainLoop(Daemonize); delete g_Bouncer; delete Config; #if !defined(_WIN32 ) || defined(__MINGW32__) lt_dlexit(); #endif exit(EXIT_SUCCESS); }
int ds_daemon(http_conf * conf, int t) { int uid = getuid(); int gid = getgid(); int status = 0; if(conf->user && strlen(conf->user)) { struct passwd * pw = getpwnam(conf->user); if(!pw) { printf(" user[%s] no found\n", conf->user); exit(0); } uid = pw->pw_uid; gid = pw->pw_gid; printf("\n user:%s\n", conf->user); } if(t == 0 ) { ds_init_daemon(conf); } if( t == 0 || t == 1) { ds_init_children(conf); //ds_pid = getpid(); if(setsid() == -1) { //setsid创建一个新会话 printf("setsid() failed!" DS_LINEEND); exit(0); } umask(0); setuid(uid); setgid(gid); ds_init(conf); } /*if( t == 2) { conf->work_mode = FORK_PROCESS_WORK_HTTP_MODE; }*/ if(t == 2) { //使用两个pipe 完成accept 和cgi进程的通信,pipe 0read, 1write int pipHttp[2], pipCgi[2]; pipe(pipHttp); pipe(pipCgi); int forkCgiPid = fork(); if(forkCgiPid == 0) { conf->child_pip.in = pipCgi[0]; conf->child_pip.out = pipHttp[1]; close(pipHttp[0]); close(pipCgi[1]); conf->work_mode = FORK_PROCESS_WORK_CGI_MODE; } else { conf->child_pip.in = pipHttp[0]; conf->child_pip.out = pipCgi[1]; close(pipHttp[1]); close(pipCgi[0]); conf->work_mode = FORK_PROCESS_WORK_HTTP_MODE; } } return OK; }
// whitelist for /home/user directory void fs_whitelist(void) { char *homedir = cfg.homedir; assert(homedir); ProfileEntry *entry = cfg.profile; if (!entry) return; // realpath function will fail with ENOENT if the file is not found // we need to expand the path before installing a new, empty home directory while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } char *new_name = expand_home(entry->data + 10, cfg.homedir); assert(new_name); char *fname = realpath(new_name, NULL); free(new_name); if (fname) { // change file name in entry->data if (strcmp(fname, entry->data + 10) != 0) { char *newdata; if (asprintf(&newdata, "whitelist %s", fname) == -1) errExit("asprintf"); entry->data = newdata; if (arg_debug) printf("Replaced whitelist path: %s\n", entry->data); } free(fname); } else { // file not found, blank the entry in the list if (arg_debug) printf("Removed whitelist path: %s\n", entry->data); *entry->data = '\0'; } entry = entry->next; } // create /tmp/firejail/mnt/whome directory fs_build_mnt_dir(); int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO); if (rv == -1) errExit("mkdir"); if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0) errExit("chown"); if (chmod(WHITELIST_HOME_DIR, 0755) < 0) errExit("chmod"); // keep a copy of real home dir in /tmp/firejail/mnt/whome if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) errExit("mount bind"); // start building the new home directory by mounting a tmpfs fielsystem fs_private(); // go through profile rules again, and interpret whitelist commands entry = cfg.profile; while (entry) { // handle only whitelist commands if (strncmp(entry->data, "whitelist ", 10)) { entry = entry->next; continue; } whitelist_path(entry->data + 10); entry = entry->next; } // mask the real home directory, currently mounted on /tmp/firejail/mnt/whome if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) errExit("mount tmpfs"); }
int main(int argc, char **argv) { struct sigaction sa; char pwd[BUFSIZE + 1]; int c; guint i; char *path; #ifdef ENABLE_NLS if (!setlocale(LC_MESSAGES, "")) msg(_("Locale could not be set")); bindtextdomain(PACKAGE_NAME, LOCALEROOTDIR); (void)textdomain(PACKAGE_NAME); #endif /* ENABLE_NLS */ /* setup our signal handling */ sa.sa_flags = 0; sigfillset(&sa.sa_mask); sa.sa_handler = got_sig; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (((getuid() != geteuid()) || (getgid() != getegid()))) { msg(_("Will not run suid/sgid for safety reasons")); exit(EXIT_FAILURE); } if (!getcwd(pwd, BUFSIZE)) { msg(_("Could not get current working directory")); exit(EXIT_FAILURE); } for (c = 0; c < argc; c++) { if (strlen(argv[c]) > BUFSIZE) { msg(_("Argument length overrun")); exit(EXIT_FAILURE); } } while ((c = getopt(argc, argv, "thnVvus:r:Tq")) != -1) { switch (c) { case 'v': opt_verbose = 1; break; case 'h': usage_up(stdout); exit(EXIT_SUCCESS); case 'n': opt_dry = TRUE; break; case 'T': opt_table = TRUE; opt_dry = TRUE; opt_verbose = 0; break; case 'u': opt_chown = FALSE; break; case 's': opt_strip = abs(atoi(optarg)); break; case 'r': /* expand relative paths */ if (!g_path_is_absolute(optarg)) opt_path_strip = abspath(g_strdup_printf ("%s/%s", pwd, optarg)); else opt_path_strip = abspath(optarg); if (!opt_path_strip) { msg(_("Failed to expand path `%s\'"), optarg); exit(EXIT_FAILURE); } if (opt_path_strip[strlen(opt_path_strip) - 1] != '/') opt_path_strip = g_strdup_printf("%s/", opt_path_strip); /* count the number of labels */ for (i = 0; i < strlen(opt_path_strip); i++) { if (opt_path_strip[i] == '/') opt_path_strip_len++; } opt_path_strip_len--; /* we added the closing slash, so need -1 here */ break; case 'q': opt_quiet = TRUE; break; case 't': opt_top = TRUE; break; case 'V': #ifdef DEBUG fprintf(stdout, "%s %s (with --enable-debug)\n", PROGNAME, VERSION); #else fprintf(stdout, "%s %s\n", PROGNAME, VERSION); #endif /* DEBUG */ exit(EXIT_SUCCESS); default: msg(_("Unknown option seen `%c\'"), optopt); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; if (opt_table) { path = NULL; } else { if (argc != 1) { msg(_("Destination directory is required")); exit(EXIT_FAILURE); } if (!g_path_is_absolute(argv[0])) { gchar *full_path = g_strdup_printf("%s/%s", pwd, argv[0]); path = abspath(full_path); g_free(full_path); } else path = abspath(argv[0]); } if (!opt_dry) { if (opt_top) { /* this is not 100%, but better than nothing */ if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) { msg(_("Failed to create directory `%s\'"), path); exit(EXIT_FAILURE); } if (mkpath(path, 00777) == -1) { msg(_("Failed to create directory `%s\': %s"), path, strerror(errno)); exit(EXIT_FAILURE); } } else { if (!g_file_test(path, G_FILE_TEST_IS_DIR)) { msg(_("No such directory: `%s\'"), path); exit(EXIT_FAILURE); } } } if (update(path) == FALSE) exit(EXIT_FAILURE); g_free(path); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { char *gidmap = NULL, *inside = NULL, *outside = NULL, *uidmap = NULL; char *bind = NULL; int hostnet = 0, master, option, stdio = 0; pid_t child, parent; while ((option = getopt(argc, argv, "+:b:cg:i:no:u:")) > 0) switch (option) { case 'b': bind = optarg; break; case 'c': stdio++; break; case 'g': gidmap = optarg; break; case 'i': inside = optarg; break; case 'n': hostnet++; break; case 'o': outside = optarg; break; case 'u': uidmap = optarg; break; default: usage(argv[0]); } if (argc <= optind) usage(argv[0]); parent = getpid(); switch (child = fork()) { case -1: error(1, errno, "fork"); case 0: raise(SIGSTOP); // if (geteuid() != 0) // denysetgroups(parent); writemap(parent, GID, gidmap); writemap(parent, UID, uidmap); if (outside) { if (setgid(getgid()) < 0 || setuid(getuid()) < 0) error(1, 0, "Failed to drop privileges"); execlp(SHELL, SHELL, "-c", outside, NULL); error(1, errno, "exec %s", outside); } exit(EXIT_SUCCESS); } if (setgid(getgid()) < 0 || setuid(getuid()) < 0) error(1, 0, "Failed to drop privileges"); if (unshare(CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWUTS) < 0) error(1, 0, "Failed to unshare namespaces"); if (!hostnet && unshare(CLONE_NEWNET) < 0) error(1, 0, "Failed to unshare network namespace"); waitforstop(child); kill(child, SIGCONT); waitforexit(child); setgid(0); setgroups(0, NULL); setuid(0); master = stdio ? -1 : getconsole(); createroot(argv[optind], master, inside, bind); unshare(CLONE_NEWPID); switch (child = fork()) { case -1: error(1, errno, "fork"); case 0: mountproc(); if (!hostnet) mountsys(); enterroot(); if (master >= 0) { close(master); setconsole("/dev/console"); } clearenv(); putenv("container=contain"); if (argv[optind + 1]) execv(argv[optind + 1], argv + optind + 1); else execl(SHELL, SHELL, NULL); error(1, errno, "exec"); } return supervise(child, master); }
static void xlocaledir( char *buf, int buf_len) { char *p = buf; int len = 0; #ifndef NO_XLOCALEDIR char *dir; int priv = 1; dir = getenv("XLOCALEDIR"); if (dir) { #ifndef WIN32 /* * Only use the user-supplied path if the process isn't priviledged. */ if (getuid() == geteuid() && getgid() == getegid()) { #if defined(HASSETUGID) priv = issetugid(); #elif defined(HASGETRESUID) { uid_t ruid, euid, suid; gid_t rgid, egid, sgid; if ((getresuid(&ruid, &euid, &suid) == 0) && (getresgid(&rgid, &egid, &sgid) == 0)) priv = (euid != suid) || (egid != sgid); } #else /* * If there are saved ID's the process might still be priviledged * even though the above test succeeded. If issetugid() and * getresgid() aren't available, test this by trying to set * euid to 0. * * Note: this only protects setuid-root clients. It doesn't * protect other setuid or any setgid clients. If this tradeoff * isn't acceptable, set DisableXLocaleDirEnv to YES in host.def. */ unsigned int oldeuid; oldeuid = geteuid(); if (seteuid(0) != 0) { priv = 0; } else { seteuid(oldeuid); priv = 1; } #endif } #else priv = 0; #endif if (!priv) { len = strlen(dir); strncpy(p, dir, buf_len); if (len < buf_len) { p[len++] = LC_PATHDELIM; p += len; } } } #endif /* NO_XLOCALEDIR */ if (len < buf_len) #ifndef __UNIXOS2__ strncpy(p, XLOCALEDIR, buf_len - len); #else strncpy(p,__XOS2RedirRoot(XLOCALEDIR), buf_len - len); #endif buf[buf_len-1] = '\0'; }
int main(int argc, char **argv) { struct quotause *qup, *protoprivs, *curprivs; long id, protoid; long long lim; int i, quotatype, range, tmpfd; uid_t startuid, enduid; u_int32_t *limp; char *protoname, *cp, *oldoptarg, ch; int eflag = 0, tflag = 0, pflag = 0; char *fspath = NULL; char buf[MAXLOGNAME]; if (argc < 2) usage(); if (getuid()) errx(1, "permission denied"); quotatype = USRQUOTA; protoprivs = NULL; curprivs = NULL; protoname = NULL; while ((ch = getopt(argc, argv, "ugtf:p:e:")) != -1) { switch(ch) { case 'f': fspath = optarg; break; case 'p': protoname = optarg; pflag++; break; case 'g': quotatype = GRPQUOTA; break; case 'u': quotatype = USRQUOTA; break; case 't': tflag++; break; case 'e': if ((qup = malloc(sizeof(*qup))) == NULL) errx(2, "out of memory"); bzero(qup, sizeof(*qup)); i = 0; oldoptarg = optarg; for (cp = optarg; (cp = strsep(&optarg, ":")) != NULL; i++) { if (cp != oldoptarg) *(cp - 1) = ':'; limp = NULL; switch (i) { case 0: strlcpy(qup->fsname, cp, sizeof(qup->fsname)); break; case 1: limp = &qup->dqblk.dqb_bsoftlimit; break; case 2: limp = &qup->dqblk.dqb_bhardlimit; break; case 3: limp = &qup->dqblk.dqb_isoftlimit; break; case 4: limp = &qup->dqblk.dqb_ihardlimit; break; default: warnx("incorrect quota specification: " "%s", oldoptarg); usage(); break; /* XXX: report an error */ } if (limp != NULL) { lim = strtoll(cp, NULL, 10); if (lim < 0 || lim > UINT_MAX) errx(1, "invalid limit value: " "%lld", lim); *limp = (u_int32_t)lim; } } qup->dqblk.dqb_bsoftlimit = btodb((off_t)qup->dqblk.dqb_bsoftlimit * 1024); qup->dqblk.dqb_bhardlimit = btodb((off_t)qup->dqblk.dqb_bhardlimit * 1024); if (protoprivs == NULL) { protoprivs = curprivs = qup; } else { curprivs->next = qup; curprivs = qup; } eflag++; pflag++; break; default: usage(); } } argc -= optind; argv += optind; if (pflag) { if (protoprivs == NULL) { if ((protoid = getentry(protoname, quotatype)) == -1) exit(1); protoprivs = getprivs(protoid, quotatype, fspath); for (qup = protoprivs; qup; qup = qup->next) { qup->dqblk.dqb_btime = 0; qup->dqblk.dqb_itime = 0; } } for (; argc-- > 0; argv++) { if (strspn(*argv, "0123456789-") == strlen(*argv) && (cp = strchr(*argv, '-')) != NULL) { *cp++ = '\0'; startuid = atoi(*argv); enduid = atoi(cp); if (enduid < startuid) errx(1, "ending uid (%d) must be >= starting uid (%d) when using uid ranges", enduid, startuid); range = 1; } else { startuid = enduid = 0; range = 0; } for ( ; startuid <= enduid; startuid++) { if (range) snprintf(buf, sizeof(buf), "%d", startuid); else snprintf(buf, sizeof(buf), "%s", *argv); if ((id = getentry(buf, quotatype)) < 0) continue; if (eflag) { for (qup = protoprivs; qup; qup = qup->next) { curprivs = getprivs(id, quotatype, qup->fsname); if (curprivs == NULL) continue; strcpy(qup->qfname, curprivs->qfname); strcpy(qup->fsname, curprivs->fsname); } } putprivs(id, quotatype, protoprivs); } } exit(0); } tmpfd = mkstemp(tmpfil); fchown(tmpfd, getuid(), getgid()); if (tflag) { protoprivs = getprivs(0, quotatype, fspath); if (writetimes(protoprivs, tmpfd, quotatype) == 0) exit(1); if (editit(tmpfil) && readtimes(protoprivs, tmpfil)) putprivs(0, quotatype, protoprivs); freeprivs(protoprivs); close(tmpfd); unlink(tmpfil); exit(0); } for ( ; argc > 0; argc--, argv++) { if ((id = getentry(*argv, quotatype)) == -1) continue; curprivs = getprivs(id, quotatype, fspath); if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) continue; if (editit(tmpfil) && readprivs(curprivs, tmpfil)) putprivs(id, quotatype, curprivs); freeprivs(curprivs); } close(tmpfd); unlink(tmpfil); exit(0); }
int main(int argc, char *argv[]) { int opt, proto = -1, route = 0; kvm_t *kvmd = NULL; char *memf = NULL; while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) { switch (opt) { case 'n': numeric_bdaddr = 1; break; case 'M': memf = optarg; break; case 'p': if (strcasecmp(optarg, "hci_raw") == 0) proto = N_HCI_RAW; else if (strcasecmp(optarg, "l2cap_raw") == 0) proto = N_L2CAP_RAW; else if (strcasecmp(optarg, "l2cap") == 0) proto = N_L2CAP; else if (strcasecmp(optarg, "rfcomm") == 0) proto = N_RFCOMM; else if (strcasecmp(optarg, "rfcomm_s") == 0) proto = N_RFCOMM_S; else usage(); /* NOT REACHED */ break; case 'r': route = 1; break; case 'h': default: usage(); /* NOT REACHED */ } } if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route) usage(); /* NOT REACHED */ /* * Discard setgid privileges if not the running kernel so that * bad guys can't print interesting stuff from kernel memory. */ if (memf != NULL) if (setgid(getgid()) != 0) err(1, "setgid"); kvmd = kopen(memf); if (kvmd == NULL) return (1); switch (proto) { case N_HCI_RAW: hcirawpr(kvmd, nl[N_HCI_RAW].n_value); break; case N_L2CAP_RAW: if (route) l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value); else l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value); break; case N_L2CAP: if (route) l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value); else l2cappr(kvmd, nl[N_L2CAP].n_value); break; case N_RFCOMM: rfcommpr(kvmd, nl[N_RFCOMM].n_value); break; case N_RFCOMM_S: rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value); break; default: if (route) { l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value); l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value); } else { hcirawpr(kvmd, nl[N_HCI_RAW].n_value); l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value); l2cappr(kvmd, nl[N_L2CAP].n_value); rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value); rfcommpr(kvmd, nl[N_RFCOMM].n_value); } break; } return (kvm_close(kvmd)); } /* main */
int main(int argc, char **argv) { static char *full_name = 0; /* sendmail -F */ struct stat st; char *slash; char *sender = 0; /* sendmail -f */ int c; int fd; int mode; ARGV *ext_argv; int debug_me = 0; int err; int n; int flags = SM_FLAG_DEFAULT; char *site_to_flush = 0; char *id_to_flush = 0; char *encoding = 0; char *qtime = 0; const char *errstr; uid_t uid; const char *rewrite_context = MAIL_ATTR_RWR_LOCAL; int dsn_notify = 0; const char *dsn_envid = 0; int saved_optind; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; /* * Be consistent with file permissions. */ umask(022); /* * To minimize confusion, make sure that the standard file descriptors * are open before opening anything else. XXX Work around for 44BSD where * fstat can return EBADF on an open file descriptor. */ for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal_status(EX_OSERR, "open /dev/null: %m"); /* * The CDE desktop calendar manager leaks a parent file descriptor into * the child process. For the sake of sendmail compatibility we have to * close the file descriptor otherwise mail notification will hang. */ for ( /* void */ ; fd < 100; fd++) (void) close(fd); /* * Process environment options as early as we can. We might be called * from a set-uid (set-gid) program, so be careful with importing * environment variables. */ if (safe_getenv(CONF_ENV_VERB)) msg_verbose = 1; if (safe_getenv(CONF_ENV_DEBUG)) debug_me = 1; /* * Initialize. Set up logging, read the global configuration file and * extract configuration information. Set up signal handlers so that we * can clean up incomplete output. */ if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); msg_cleanup(tempfail); msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); /* * Some sites mistakenly install Postfix sendmail as set-uid root. Drop * set-uid privileges only when root, otherwise some systems will not * reset the saved set-userid, which would be a security vulnerability. */ if (geteuid() == 0 && getuid() != 0) { msg_warn("the Postfix sendmail command has set-uid root file permissions"); msg_warn("or the command is run from a set-uid root process"); msg_warn("the Postfix sendmail command must be installed without set-uid root file permissions"); set_ugid(getuid(), getgid()); } /* * Further initialization. Load main.cf first, so that command-line * options can override main.cf settings. Pre-scan the argument list so * that we load the right main.cf file. */ #define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx" saved_optind = optind; while (argv[OPTIND] != 0) { if (strcmp(argv[OPTIND], "-q") == 0) { /* not getopt compatible */ optind++; continue; } if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0) break; if (c == 'C') { VSTRING *buf = vstring_alloc(1); if (setenv(CONF_ENV_PATH, strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ? sane_dirname(buf, optarg) : optarg, 1) < 0) msg_fatal_status(EX_UNAVAILABLE, "out of memory"); vstring_free(buf); } } optind = saved_optind; mail_conf_read(); if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY); get_mail_conf_str_table(str_table); if (chdir(var_queue_dir)) msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir); signal(SIGPIPE, SIG_IGN); /* * Optionally start the debugger on ourself. This must be done after * reading the global configuration file, because that file specifies * what debugger command to execute. */ if (debug_me) debug_process(); /* * The default mode of operation is determined by the process name. It * can, however, be changed via command-line options (for example, * "newaliases -bp" will show the mail queue). */ if (strcmp(argv[0], "mailq") == 0) { mode = SM_MODE_MAILQ; } else if (strcmp(argv[0], "newaliases") == 0) { mode = SM_MODE_NEWALIAS; } else if (strcmp(argv[0], "smtpd") == 0) { mode = SM_MODE_DAEMON; } else { mode = SM_MODE_ENQUEUE; } /* * Parse JCL. Sendmail has been around for a long time, and has acquired * a large number of options in the course of time. Some options such as * -q are not parsable with GETOPT() and get special treatment. */ #define OPTIND (optind > 0 ? optind : 1) while (argv[OPTIND] != 0) { if (strcmp(argv[OPTIND], "-q") == 0) { if (mode == SM_MODE_DAEMON) msg_warn("ignoring -q option in daemon mode"); else mode = SM_MODE_FLUSHQ; optind++; continue; } if (strcmp(argv[OPTIND], "-V") == 0) { msg_warn("option -V is deprecated with Postfix 2.3; " "specify -XV instead"); argv[OPTIND] = "-XV"; } if (strncmp(argv[OPTIND], "-V", 2) == 0 && strlen(argv[OPTIND]) == 4) { msg_warn("option %s is deprecated with Postfix 2.3; " "specify -X%s instead", argv[OPTIND], argv[OPTIND] + 1); argv[OPTIND] = concatenate("-X", argv[OPTIND] + 1, (char *) 0); } if (strcmp(argv[OPTIND], "-XV") == 0) { verp_delims = var_verp_delims; optind++; continue; } if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0) break; switch (c) { default: if (msg_verbose) msg_info("-%c option ignored", c); break; case 'n': msg_fatal_status(EX_USAGE, "-%c option not supported", c); case 'B': if (strcmp(optarg, "8BITMIME") == 0)/* RFC 1652 */ encoding = MAIL_ATTR_ENC_8BIT; else if (strcmp(optarg, "7BIT") == 0) /* RFC 1652 */ encoding = MAIL_ATTR_ENC_7BIT; else msg_fatal_status(EX_USAGE, "-B option needs 8BITMIME or 7BIT"); break; case 'F': /* full name */ full_name = optarg; break; case 'G': /* gateway submission */ rewrite_context = MAIL_ATTR_RWR_REMOTE; break; case 'I': /* newaliases */ mode = SM_MODE_NEWALIAS; break; case 'N': if ((dsn_notify = dsn_notify_mask(optarg)) == 0) msg_warn("bad -N option value -- ignored"); break; case 'V': /* DSN, was: VERP */ if (strlen(optarg) > 100) msg_warn("too long -V option value -- ignored"); else if (!allprint(optarg)) msg_warn("bad syntax in -V option value -- ignored"); else dsn_envid = optarg; break; case 'X': switch (*optarg) { default: msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg); case 'V': /* VERP */ if (verp_delims_verify(optarg + 1) != 0) msg_fatal_status(EX_USAGE, "-V requires two characters from %s", var_verp_filter); verp_delims = optarg + 1; break; } break; case 'b': switch (*optarg) { default: msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg); case 'd': /* daemon mode */ if (mode == SM_MODE_FLUSHQ) msg_warn("ignoring -q option in daemon mode"); mode = SM_MODE_DAEMON; break; case 'h': /* print host status */ case 'H': /* flush host status */ mode = SM_MODE_IGNORE; break; case 'i': /* newaliases */ mode = SM_MODE_NEWALIAS; break; case 'm': /* deliver mail */ mode = SM_MODE_ENQUEUE; break; case 'p': /* mailq */ mode = SM_MODE_MAILQ; break; case 's': /* stand-alone mode */ mode = SM_MODE_USER; break; case 'v': /* expand recipients */ flags |= DEL_REQ_FLAG_USR_VRFY; break; } break; case 'f': sender = optarg; break; case 'i': flags &= ~SM_FLAG_AEOF; break; case 'o': switch (*optarg) { default: if (msg_verbose) msg_info("-%c%c option ignored", c, *optarg); break; case 'A': if (optarg[1] == 0) msg_fatal_status(EX_USAGE, "-oA requires pathname"); myfree(var_alias_db_map); var_alias_db_map = mystrdup(optarg + 1); set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map); break; case '7': case '8': break; case 'i': flags &= ~SM_FLAG_AEOF; break; case 'm': break; } break; case 'r': /* obsoleted by -f */ sender = optarg; break; case 'q': if (ISDIGIT(optarg[0])) { qtime = optarg; } else if (optarg[0] == 'R') { site_to_flush = optarg + 1; if (*site_to_flush == 0) msg_fatal_status(EX_USAGE, "specify: -qRsitename"); } else if (optarg[0] == 'I') { id_to_flush = optarg + 1; if (*id_to_flush == 0) msg_fatal_status(EX_USAGE, "specify: -qIqueueid"); } else { msg_fatal_status(EX_USAGE, "-q%c is not implemented", optarg[0]); } break; case 't': flags |= SM_FLAG_XRCPT; break; case 'v': msg_verbose++; break; case '?': msg_fatal_status(EX_USAGE, "usage: %s [options]", argv[0]); } } /* * Look for conflicting options and arguments. */ if ((flags & SM_FLAG_XRCPT) && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-t can be used only in delivery mode"); if (site_to_flush && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-qR can be used only in delivery mode"); if (id_to_flush && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-qI can be used only in delivery mode"); if (flags & DEL_REQ_FLAG_USR_VRFY) { if (flags & SM_FLAG_XRCPT) msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv"); if (dsn_notify) msg_fatal_status(EX_USAGE, "-N option cannot be used with -bv"); if (msg_verbose == 1) msg_fatal_status(EX_USAGE, "-v option cannot be used with -bv"); } /* * The -v option plays double duty. One requests verbose delivery, more * than one requests verbose logging. */ if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) { msg_verbose = 0; flags |= DEL_REQ_FLAG_RECORD; } /* * Start processing. Everything is delegated to external commands. */ if (qtime && mode != SM_MODE_DAEMON) exit(0); switch (mode) { default: msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case SM_MODE_ENQUEUE: if (site_to_flush) { if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush site requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ } else if (id_to_flush) { if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush queue_id requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-i", id_to_flush, (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ } else { enqueue(flags, encoding, dsn_envid, dsn_notify, rewrite_context, sender, full_name, argv + OPTIND); exit(0); /* NOTREACHED */ } break; case SM_MODE_MAILQ: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "display queue mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-p", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_FLUSHQ: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "flush queue mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postqueue", "-f", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_DAEMON: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "daemon mode requires no recipient"); ext_argv = argv_alloc(2); argv_add(ext_argv, "postfix", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_add(ext_argv, "start", (char *) 0); argv_terminate(ext_argv); err = (mail_run_background(var_command_dir, ext_argv->argv) < 0); argv_free(ext_argv); exit(err); break; case SM_MODE_NEWALIAS: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "alias initialization mode requires no recipient"); if (*var_alias_db_map == 0) return (0); ext_argv = argv_alloc(2); argv_add(ext_argv, "postalias", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_split_append(ext_argv, var_alias_db_map, ", \t\r\n"); argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_USER: if (argv[OPTIND]) msg_fatal_status(EX_USAGE, "stand-alone mode requires no recipient"); /* The actual enforcement happens in the postdrop command. */ if ((errstr = check_user_acl_byuid(var_submit_acl, uid = getuid())) != 0) msg_fatal_status(EX_NOPERM, "User %s(%ld) is not allowed to submit mail", errstr, (long) uid); ext_argv = argv_alloc(2); argv_add(ext_argv, "smtpd", "-S", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_terminate(ext_argv); mail_run_replace(var_daemon_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_IGNORE: exit(0); /* NOTREACHED */ } }
INTERNAL int SYS_GetGID(void) { return getgid(); }
/** Main execution routine @param argc Number of args (0) @param argv Args (always empty) */ int main (int argc, char *argv[]) { /* --------------------------------------------------------------------- * Alert! setuid program with root privileges * ---------------------------------------------------------------------*/ /* syslog */ openlog ("odcgi", LOG_PID, LOG_USER); script_env_t env; /* Agent address */ //! @todo: what if eth0 don't exists? snprintf (env.agent_address, MAX_ENV_SIZE, "%s", getip ("eth0")); //! @todo: lots of static variables. Maybe some can be reused to save memory char http_gui[8]; //char http_style[10]; char http_logout[8]; char http_user[256]; char http_pass[256]; char http_session[1024]; char http_noheader[8]; char http_newuser[256]; char http_newpass1[256]; char http_newpass2[256]; char http_deluser[256]; char http_moduser[256]; char http_modpass1[256]; char http_modpass2[256]; char http_modoldpass[256]; char http_getfile[256]; char http_resource[50]; char http_play_mjpg[100]; char http_temp[100]; /* Configuration vars */ FILE *fh; read_config_file (fh, OD_APP_I18N_CONF, lang, "en"); //read_config_file(fh,OD_APP_STYLE_CONF,style,"default"); //read_config_file(fh,OD_APP_SKIN_CONF,skin,"silver"); /* Get HTTP variables */ cgi_t *cgi = cgi_alloc (); cgi_get_param_by_name (cgi, "GUI", http_gui, sizeof (http_gui)); cgi_get_param_by_name (cgi, "LOGOUT", http_logout, sizeof (http_logout)); cgi_get_param_by_name (cgi, "USER", http_user, sizeof (http_user)); cgi_get_param_by_name (cgi, "PASS", http_pass, sizeof (http_pass)); cgi_get_param_by_name (cgi, "HTSESSID", http_session, sizeof (http_session)); cgi_get_param_by_name (cgi, "NOHEADER", http_noheader, sizeof (http_noheader)); cgi_get_param_by_name (cgi, "NEWUSER", http_newuser, sizeof (http_newuser)); cgi_get_param_by_name (cgi, "NEWPASS1", http_newpass1, sizeof (http_newpass1)); cgi_get_param_by_name (cgi, "NEWPASS2", http_newpass2, sizeof (http_newpass2)); cgi_get_param_by_name (cgi, "DELUSER", http_deluser, sizeof (http_deluser)); cgi_get_param_by_name (cgi, "MODUSER", http_moduser, sizeof (http_moduser)); cgi_get_param_by_name (cgi, "MODPASS1", http_modpass1, sizeof (http_modpass1)); cgi_get_param_by_name (cgi, "MODPASS2", http_modpass2, sizeof (http_modpass2)); cgi_get_param_by_name (cgi, "MODOLDPASS", http_modoldpass, sizeof (http_modoldpass)); cgi_get_param_by_name (cgi, "FILE", http_getfile, sizeof (http_getfile)); cgi_get_param_by_name (cgi, "resource", http_resource, sizeof (http_resource)); cgi_get_param_by_name (cgi, "play_mjpg", http_play_mjpg, sizeof (http_play_mjpg)); // if (cgi_get_param_by_name(cgi,"style", http_style, sizeof(http_style))==1) // { // //cgi_get_cookie("HTSTYLE", http_style, sizeof(http_style)); // strncpy(style, http_style, sizeof(http_style)); // cgi_http_header_set_cookie("HTSTYLE", style); // } // Si se ha solicitado una hoja de estilo, la entregamos if (cgi_get_param_by_name (cgi, "css", http_temp, sizeof (http_temp)) == 1) { syslog (LOG_NOTICE, "printing style: %s\n", http_temp); odcgi_print_file (http_temp); cgi_free (cgi); return 0; } /* // Si se ha solicitado el javascript específico, lo entregamos if (cgi_get_param_by_name(cgi, "js", http_temp, sizeof(http_temp))==1) { syslog(LOG_NOTICE, "printing script: %s\n", http_temp); odcgi_print_file(http_temp); return 0; } */ if (strlen (http_session) == 0) { cgi_get_cookie ("HTSESSID", http_session, sizeof (http_session)); syslog (LOG_NOTICE, "session from cookie: %s\n", http_session); } /* get gui type */ if (strcmp (http_gui, "XML") == 0) gui = xml; if (strcmp (http_gui, "none") == 0) gui = none; /* login process */ if (odcgi_login (&env, http_user, http_pass, http_session, sizeof (http_session)) == -1) { syslog (LOG_NOTICE, "login failed: %s-%s\n", http_user, http_pass); cgi_free (cgi); return -1; } // syslog(LOG_NOTICE, "env.user: %s\n", env.user); // syslog(LOG_NOTICE, "http_user: %s\n", http_user); /* check logout */ if (odcgi_logout (&env, http_logout)) { cgi_free (cgi); return -1; } /* --------------------------------------------------------------------- * Login OK: odcgi is setuid root * --------------------------------------------------------------------- */ //syslog(LOG_NOTICE, "[odcgi] userid: %d\n", getuid()); /* root has not access */ if (odcgi_check_root (http_user)) { cgi_free (cgi); return -1; } /* --------------------------------------------------------------------- * Login OK: * + admin has root privileges * + normal user has Linux privileges * --------------------------------------------------------------------- */ syslog (LOG_NOTICE, "[odcgi] user: %s, uid: %d, guid: %d\n", env.user, getuid (), getgid ()); /* NO USER MANAGEMENT FUNCTIONS IN // adds a new user if (odcgi_add_user (http_newuser, http_newpass1, http_newpass2) == -1) { cgi_free (cgi); return -1; } // delete user if (odcgi_del_user (http_deluser) == -1) { cgi_free (cgi); return -1; } // modify user password if (odcgi_mod_user (http_moduser, http_modoldpass, http_modpass1, http_modpass2) == -1) { cgi_free (cgi); return -1; } */ /* set session */ /* Privilege separation: drop root privileges */ // syslog(LOG_NOTICE, "set session %s\n", http_session); // syslog(LOG_NOTICE, "[odcgi] session_set_ids user: %s\n", env.user); session_set_ids (env.user); syslog (LOG_NOTICE, "[odcgi] dropped privileges user: %s, uid: %d, guid: %d\n", env.user, getuid (), getgid ()); /* File reference with user permissions applied */ if (strlen (http_getfile) > 5) { char buffer[1024] = "/media/"; strcat (buffer, http_getfile); if (http_send_file (buffer)) { cgi_free (cgi); return 0; } else { //! @todo Mostrar error } } /* play mjpg file */ if (strlen (http_play_mjpg) > 3) { syslog (LOG_NOTICE, "play: %s\n", http_play_mjpg); mjpg_play (http_play_mjpg); cgi_free (cgi); return 0; } switch (gui) { case xml: cgi_http_header_begin ("text/xml"); break; case html: cgi_http_header_begin ("text/html"); break; default: cgi_http_header_begin ("text/plain"); } /* Resource reference */ //TODO Verificar permisos de usuario if (strlen (http_resource) > 3) { syslog (LOG_NOTICE, "Serving resource %s\n", http_resource); if (mjpg_streaming_rsc (http_resource)) { cgi_free (cgi); return 0; } else { //printf("<div id='connfail'><p class='error'>%s</p></div>\n", // T(ODCGI_ERROR__CONNECTION_FAILURE)); cgi_free (cgi); return 0; } } syslog (LOG_NOTICE, "1.session: %s\n", http_session); cgi_http_header_set_cookie ("HTSESSID", http_session); // cgi_get_cookie("HTSTYLE", style, sizeof(style)); // cgi_http_header_set_cookie("HTSTYLE", style); cgi_http_header_end (); /* --------------------------------------------------------------------- * User privileges * ---------------------------------------------------------------------*/ size_t len = cgi->decoded_url->size; char path_info[256 + len]; path_info[0] = 0; sstrncpy (path_info, cgi_get_path_info (cgi), sizeof (path_info)); syslog (LOG_NOTICE, "path_info %s - %d\n", path_info, strlen (path_info)); // If any POST/GET vars matches with submit_X.sh, X.sh is the target // then replace 'path_info'. char options[256 + len]; int index = 0; char varname[256]; char varvalue[256 + len]; int has_option = 0; char scriptname[256] = ""; char path[256 + len]; path[0] = 0; while (cgi_get_param_by_index (cgi, index, varname, sizeof (varname), varvalue, sizeof (varvalue))) { // Replace "+" for " " for (int i=0;i<sizeof(varvalue);i++) { if (varvalue[i]=='+') varvalue[i]=' '; } syslog (LOG_DEBUG, "CGIParam %d %s=%s\n", index, varname, varvalue); if (strcmp (varname, "GUI") == 0) { // Ignore } else if (strcmp (varname, "odcgioptionsel") == 0) { sstrncat (options, varvalue, sizeof (options)); sstrncat (options, " ", sizeof (options)); has_option = 1; } else if (strncmp (varname, "submit_", 7) == 0) { syslog (LOG_NOTICE, "Submit redirection found at %s\n", varname); sstrncpy (scriptname, varname + 7, sizeof (scriptname)); //sstrncpy(path_info, scriptname, sizeof(path_info)); snprintf (path, sizeof (path), "/usr/local/opendomo/%s", scriptname); syslog (LOG_DEBUG, "debugging %s - %s [%s]\n", scriptname, path, options); break; } index++; } /* Check PATH variable */ if (strlen (path_info) == 0) strcpy (path_info, "/"); /* filters */ if (!match (path_info, "^/[a-záéíóúàèäëïöüñçA-ZÁÉÍÓÚÀÈÄËÏÖÜÑÇ0-9_/]*\\.{0,1}[a-záéíóúàèäëïöüñçA-ZÁÉÍÓÚÀÈÄËÏÖÜÑÇ0-9_/+ =?:]*$")) { odcgi_print_header ("error", env.user); syslog (LOG_ERR, "%s\n", ODCGI_ERROR__INVALID_PATH); odcgi_msg_error (ODCGI_ERROR__INVALID_PATH, "Invalid character found in the command."); printf ("\n<!-- PATH_INFO: %s-->\n", path_info); odcgi_print_footer ("", 0, cgi); cgi_free (cgi); return -1; } int err = 0; char *param_regex = "[$;'\\\"]"; if (strstr (cgi_get_query_string (cgi), "..")) err = 1; else if (strstr (cgi_get_decoded_url (cgi), "..")) err = 2; else if (strlen (cgi_get_query_string (cgi)) > 0 && match (cgi_get_query_string (cgi), param_regex)) err = 3; else if (strlen (cgi_get_decoded_url (cgi)) > 0 && match (cgi_get_decoded_url (cgi), param_regex)) err = 4; if (err!=0) { odcgi_print_header ("error", env.user); syslog (LOG_ERR, "%s\n", ODCGI_ERROR__INVALID_PATH); odcgi_msg_error (ODCGI_ERROR__INVALID_PATH, "Invalid character found in the parameters."); printf ("\n<!-- PATH ERROR: %d (not allowed) \n\t%s \n\t %s -->\n", err, cgi_get_query_string (cgi), cgi_get_decoded_url (cgi)); odcgi_print_footer ("", 0, cgi); cgi_free (cgi); return -1; } // If PATH is not modified, use the default path in CONF_DIR. if (path[0] == 0) { snprintf (path, sizeof (path), "%s/%s", OD_CFG_ROOT_DIR, path_info); } /* root directory */ if (chdir (OD_CFG_ROOT_DIR) != 0) { odcgi_print_header ("error", env.user); syslog (LOG_ERR, "%s\n", ODCGI_ERROR__ROOT_PATH_ACCESS); odcgi_msg_error (ODCGI_ERROR__ROOT_PATH_ACCESS, "Cannot access the configuration directory. " "Missing privileges or misconfiguration"); odcgi_print_footer ("", 0, cgi); cgi_free (cgi); return -1; } char name[256 + len]; char value[256 + len]; char prename[256 + len]; char *shname; string_t *cmd = string_alloc (""); file_t fs; strcpy (scriptname, basename (path)); /* HTML-head begin */ odcgi_print_header (scriptname, env.user); printf ("<!-- path: %s, path_info: %s-->\n", path, path_info); /* Check NOHEADER */ if ((gui == html) && (atoi (http_noheader) != 1)) { string_assign_str (cmd, "/usr/bin/categories.sh "); string_append (cmd, path_info); script_exec (cmd->str, "header", &env); if (strlen (path_info) < 2) { printf (" <div class='applicationTitle'><h1>OpenDomo</h1></div>\n"); } else { printf (" <div class='root'><a href='" OD_URI "/'> </a></div>\n"); } } sstrncpy (prename, path, sizeof (prename)); shname = strtok (prename, " "); file_set_filename (&fs, shname); strcpy (scriptname, basename (path)); /* if dir: list contents */ if (file_is_dir (&fs)) { string_assign_str (cmd, "/usr/bin/list.sh "); string_append (cmd, path_info); string_append (cmd, " contents"); script_exec (cmd->str, "main", &env); } else { /* if file: execute */ // The path might be a redirection (no actual link in ..opendomo/root/) if (!file_is_file (&fs)) { snprintf (path, sizeof (path), "/usr/local/opendomo/%s", basename (scriptname)); printf ("\n<!-- debug paths: %s / %s [%s] -->\n", path, path_info, scriptname); file_set_filename (&fs, path); if (!file_is_file (&fs)) // If it's still not a valid path, abort { odcgi_msg_error (ODCGI_ERROR__SCRIPT_NOT_FOUND, "The script was not found. " "Maybe the function you are requiring " "is not installed in this system"); printf ("<!-- BASENAME: %s -->\n", basename (scriptname)); odcgi_print_footer ("", 0, cgi); cgi_free (cgi); return 1; } } //printf("<!-- debug path: %s -->\n", path); //char *p = strrchr(path, '/'); if (has_option /*&& p */ ) { string_assign_str (cmd, path); string_append (cmd, " "); string_append (cmd, options); } else { string_assign_str (cmd, path); string_append (cmd, " "); } printf ("\n<!-- decoded_url: %s \n\tquery_string: %s-->\n", cgi->decoded_url->str, cgi->query_string->str); int i = 0; while (cgi_get_param_by_index (cgi, i++, name, sizeof (name), value, sizeof (value))) { if (strcmp (name, ODCGI_SESSION_NAME) == 0) { // Ignoring session name var ... } else if (strncmp (name, "GUI", 3) == 0) { // Ignoring GUI param } else if (strncmp (name, "submit_", 7) == 0) { // Ignoring possible submit redirection ... } else { //for (i = 0; i < sizeof(value); i++){ // if (value[i]=='+') value[i]=' '; //} // Avoid overwritting a defined environment var if (getenv (name) == NULL) setenv (name, value, 1); string_append (cmd, " \""); string_append (cmd, value); string_append (cmd, "\" "); } } string_replace (cmd, "+", " "); string_replace (cmd, "'", "'"); printf ("<!-- cmd (file): %s -->\n", cmd->str); //fflush(stdout); // Force flush, otherwise an error will preceed stdout // Check the returned value of script_exec() int ret = script_exec (cmd->str, "main", &env); if (ret != 0) { /* else: empty div */ printf ("<div id='main'><p class='error'>%s</p></div>", ODCGI_ERROR__SCRIPT_NOT_FOUND); } } /* Print scripts */ //odcgi_print_script(path); DEPRECATED /* HTML end */ if (atoi (http_noheader) != 1) { odcgi_print_footer ("", BUTTON_LOGOUT + BUTTON_DEBUG, cgi); } string_free (cmd); cgi_free (cgi); closelog (); return 0; }
int main(int argc, char **argv) { int fd, lockfd; char conf_str[1024]; char lockfile[PATH_MAX]; char user[32], group[32]; char *trace_dir = NULL; parse_clargs(argc, argv); /* First initialize logging, so we can log errors */ noit_log_init(); noit_log_stream_add_stream(noit_debug, noit_stderr); noit_log_stream_add_stream(noit_error, noit_stderr); /* Next load the configs */ noit_conf_init(APPNAME); if(noit_conf_load(config_file) == -1) { fprintf(stderr, "Cannot load config: '%s'\n", config_file); exit(-1); } /* Reinitialize the logging system now that we have a config */ snprintf(user, sizeof(user), "%d", getuid()); snprintf(group, sizeof(group), "%d", getgid()); if(noit_security_usergroup(droptouser, droptogroup, noit_true)) { noitL(noit_stderr, "Failed to drop privileges, exiting.\n"); exit(-1); } noit_conf_log_init(APPNAME); cli_log_switches(); if(noit_security_usergroup(user, group, noit_true)) { noitL(noit_stderr, "Failed to regain privileges, exiting.\n"); exit(-1); } if(debug) noit_debug->enabled = 1; if(!glider) noit_conf_get_string(NULL, "/" APPNAME "/watchdog/@glider", &glider); noit_watchdog_glider(glider); noit_conf_get_string(NULL, "/" APPNAME "/watchdog/@tracedir", &trace_dir); if(trace_dir) noit_watchdog_glider_trace_dir(trace_dir); /* Lastly, run through all other system inits */ if(!noit_conf_get_stringbuf(NULL, "/" APPNAME "/eventer/@implementation", conf_str, sizeof(conf_str))) { noitL(noit_stderr, "Cannot find '%s' in configuration\n", "/" APPNAME "/eventer/@implementation"); exit(-1); } if(eventer_choose(conf_str) == -1) { noitL(noit_stderr, "Cannot choose eventer %s\n", conf_str); exit(-1); } if(configure_eventer() != 0) { noitL(noit_stderr, "Cannot configure eventer\n"); exit(-1); } noit_watchdog_prefork_init(); if(chdir("/") != 0) { noitL(noit_stderr, "Failed chdir(\"/\"): %s\n", strerror(errno)); exit(-1); } /* Acquire the lock so that we can throw an error if it doesn't work. * If we've started -D, we'll have the lock. * If not we will daemon and must reacquire the lock. */ lockfd = -1; lockfile[0] = '\0'; if(noit_conf_get_stringbuf(NULL, "/" APPNAME "/@lockfile", lockfile, sizeof(lockfile))) { if((lockfd = noit_lockfile_acquire(lockfile)) < 0) { noitL(noit_stderr, "Failed to acquire lock: %s\n", lockfile); exit(-1); } } if(foreground) return child_main(); /* This isn't inherited across forks... */ if(lockfd >= 0) noit_lockfile_release(lockfd); fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if(fork()) exit(0); setsid(); if(fork()) exit(0); /* Reacquire the lock */ if(*lockfile) { if(noit_lockfile_acquire(lockfile) < 0) { noitL(noit_stderr, "Failed to acquire lock: %s\n", lockfile); exit(-1); } } signal(SIGHUP, SIG_IGN); return noit_watchdog_start_child("noitd", child_main, 0); }
/*! \brief Save the schematic file * \par Function Description * This function saves the current schematic file in the toplevel object. * * \param [in,out] toplevel The TOPLEVEL object containing the schematic. * \param [in] filename The file name to save the schematic to. * \return 1 on success, 0 on failure. */ int f_save(TOPLEVEL *toplevel, const char *filename) { gchar *backup_filename; gchar *real_filename; gchar *only_filename; gchar *dirname; mode_t saved_umask, mask; struct stat st; /* Get the real filename and file permissions */ real_filename = follow_symlinks (filename, NULL); if (real_filename == NULL) { s_log_message (_("Can't get the real filename of %s."), filename); return 0; } /* Get the directory in which the real filename lives */ dirname = g_path_get_dirname (real_filename); only_filename = g_path_get_basename(real_filename); /* Do a backup if it's not an undo file backup and it was never saved. */ if (toplevel->page_current->saved_since_first_loaded == 0) { if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) && (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) ) { backup_filename = g_strdup_printf("%s%c%s~", dirname, G_DIR_SEPARATOR, only_filename); /* Make the backup file read-write before saving a new one */ if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) { if (chmod(backup_filename, S_IREAD|S_IWRITE) != 0) { s_log_message (_("Could NOT set previous backup file [%s] read-write\n"), backup_filename); } } if (rename(real_filename, backup_filename) != 0) { s_log_message (_("Can't save backup file: %s."), backup_filename); } else { /* Make the backup file readonly so a 'rm *' command will ask the user before deleting it */ saved_umask = umask(0); mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH); mask = (~mask)&0777; mask &= ((~saved_umask) & 0777); if (chmod(backup_filename, mask) != 0) { s_log_message (_("Could NOT set backup file [%s] readonly\n"), backup_filename); } umask(saved_umask); } g_free(backup_filename); } } /* If there is not an existing file with that name, compute the * permissions and uid/gid that we will use for the newly-created file. */ if (stat (real_filename, &st) != 0) { struct stat dir_st; int result; /* Use default permissions */ saved_umask = umask(0); st.st_mode = 0666 & ~saved_umask; umask(saved_umask); #ifdef HAVE_CHOWN st.st_uid = getuid (); result = stat (dirname, &dir_st); if (result == 0 && (dir_st.st_mode & S_ISGID)) st.st_gid = dir_st.st_gid; else st.st_gid = getgid (); #endif /* HAVE_CHOWN */ } g_free (dirname); g_free (only_filename); if (o_save(toplevel, real_filename)) { toplevel->page_current->saved_since_first_loaded = 1; /* Reset the last saved timer */ g_get_current_time (&toplevel->page_current->last_load_or_save_time); toplevel->page_current->ops_since_last_backup = 0; toplevel->page_current->do_autosave_backup = 0; /* Restore permissions. */ chmod (real_filename, st.st_mode); #ifdef HAVE_CHOWN if (chown (real_filename, st.st_uid, st.st_gid)) { /* Error occured with chown */ #warning FIXME: What do we do? } #endif g_free (real_filename); return 1; } else { g_free (real_filename); return 0; } }
RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_file_RhoFileApi_nativeInit (JNIEnv *env, jclass) { clsFileApi = getJNIClass(RHODES_JAVA_CLASS_RHOFILEAPI); if (!clsFileApi) return; midCopy = getJNIClassStaticMethod(env, clsFileApi, "copy", "(Ljava/lang/String;)Z"); if (!midCopy) return; midOpen = getJNIClassStaticMethod(env, clsFileApi, "openInPackage", "(Ljava/lang/String;)Ljava/io/InputStream;"); if (!midOpen) return; midClose = getJNIClassStaticMethod(env, clsFileApi, "close", "(Ljava/io/InputStream;)V"); if (!midClose) return; midRead = getJNIClassStaticMethod(env, clsFileApi, "read", "(Ljava/io/InputStream;[B)I"); if (!midRead) return; midSeek = getJNIClassStaticMethod(env, clsFileApi, "seek", "(Ljava/io/InputStream;I)V"); if (!midSeek) return; midGetChildren = getJNIClassStaticMethod(env, clsFileApi, "getChildren", "(Ljava/lang/String;)[Ljava/lang/String;"); if (!midGetChildren) return; midReloadStatTable = getJNIClassStaticMethod(env, clsFileApi, "reloadStatTable", "()V"); if (!midReloadStatTable) return; const char *libc = "/system/lib/libc.so"; void *pc = dlopen(libc, RTLD_LAZY); __sflags = (func_sflags_t)dlsym(pc, "__sflags"); __sfp = (func_sfp_t)dlsym(pc, "__sfp"); real_access = (func_access_t)dlsym(pc, "access"); real_close = (func_close_t)dlsym(pc, "close"); real_dup = (func_dup_t)dlsym(pc, "dup"); real_dup2 = (func_dup2_t)dlsym(pc, "dup2"); real_chown = (func_chown_t)dlsym(pc, "chown"); real_fchown = (func_fchown_t)dlsym(pc, "fchown"); real_lchown = (func_lchown_t)dlsym(pc, "lchown"); real_link = (func_link_t)dlsym(pc, "link"); real_symlink = (func_symlink_t)dlsym(pc, "symlink"); real_readlink = (func_readlink_t)dlsym(pc, "readlink"); real_mkdir = (func_mkdir_t)dlsym(pc, "mkdir"); real_fchdir = (func_fchdir_t)dlsym(pc, "fchdir"); real_fcntl = (func_fcntl_t)dlsym(pc, "fcntl"); real_fsync = (func_fsync_t)dlsym(pc, "fsync"); real_fdatasync = (func_fdatasync_t)dlsym(pc, "fdatasync"); if (real_fdatasync == NULL) { //Android 2.1 have no fdatasync call. Use fsync instead RHO_LOG("No fdatasync implementation, using fsync instead"); real_fdatasync = real_fsync; } real_flock = (func_flock_t)dlsym(pc, "flock"); real_fstat = (func_fstat_t)dlsym(pc, "fstat"); real_ftruncate = (func_ftruncate_t)dlsym(pc, "ftruncate"); real_lseek = (func_lseek_t)dlsym(pc, "lseek"); real_lseek64 = (func_lseek64_t)dlsym(pc, "lseek64"); real_lstat = (func_lstat_t)dlsym(pc, "lstat"); real_open = (func_open_t)dlsym(pc, "open"); real_read = (func_read_t)dlsym(pc, "read"); real_select = (func_select_t)dlsym(pc, "select"); real_stat = (func_stat_t)dlsym(pc, "stat"); real_unlink = (func_unlink_t)dlsym(pc, "unlink"); real_write = (func_write_t)dlsym(pc, "write"); real_getdents = (func_getdents_t)dlsym(pc, "getdents"); real_rmdir = (func_rmdir_t)dlsym(pc, "rmdir"); real_opendir = (func_opendir_t)dlsym(pc, "opendir"); real_fdopendir = (func_fdopendir_t)dlsym(pc, "fdopendir"); real_readdir = (func_readdir_t)dlsym(pc, "readdir"); real_readdir_r = (func_readdir_r_t)dlsym(pc, "readdir_r"); real_closedir = (func_closedir_t)dlsym(pc, "closedir"); real_rewinddir = (func_rewinddir_t)dlsym(pc, "rewinddir"); real_dirfd = (func_dirfd_t)dlsym(pc, "dirfd"); real_scandir = (func_scandir_t)dlsym(pc, "scandir"); dlclose(pc); // This is just to get typical stat of file std::string librhodes = rho_root_path() + "../lib/librhodes.so"; RHO_LOG("Native library: %s", librhodes.c_str()); real_stat(librhodes.c_str(), &librhodes_st); librhodes_st.st_mode = S_IFREG|S_IRWXU; librhodes_st.st_nlink = 1; librhodes_st.st_uid = getuid(); librhodes_st.st_gid = getgid(); RHO_LOG("Library stat (mode: %d, uid: %d, gid: %d)", librhodes_st.st_mode, librhodes_st.st_uid, librhodes_st.st_gid); }
/* ================= Sys_GetGameAPI Loads the game dll ================= */ void *Sys_GetGameAPI (void *parms) { void *(*GetGameAPI) (void *); FILE *fp; char name[MAX_OSPATH]; char *path; char *str_p; #if defined __i386__ const char *gamename = "gamei386.so"; #elif defined __x86_64__ const char *gamename = "gamex86_64.so"; #elif defined __alpha__ const char *gamename = "gameaxp.so"; #elif defined __powerpc__ const char *gamename = "gameppc.so"; #elif defined __sparc__ const char *gamename = "gamesparc.so"; #elif defined __gcw__ const char *gamename = "gamegcw.so"; #else const char *gamename = "gamegcw.so"; #endif setreuid(getuid(), getuid()); setegid(getgid()); if (game_library) Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame"); Com_Printf("------- Loading %s -------\n", gamename); // now run through the search paths path = NULL; while (1) { path = FS_NextPath (path); if (!path) { snprintf(name, MAX_OSPATH, "%s/%s", getenv("PWD"), gamename); printf("%s\n" ,name); fp = fopen(name, "rb"); if (fp == NULL) return NULL; // couldn't find one anywhere fclose(fp); } else { snprintf (name, MAX_OSPATH, "%s/%s", path, gamename); /* skip it if it just doesn't exist */ fp = fopen(name, "rb"); if (fp == NULL) continue; fclose(fp); } game_library = dlopen (name, RTLD_NOW); if (game_library) { Com_MDPrintf ("LoadLibrary (%s)\n",name); break; } else { Com_Printf ("LoadLibrary (%s):", name); path = dlerror(); str_p = strchr(path, ':'); // skip the path (already shown) if (str_p == NULL) str_p = path; else str_p++; Com_Printf ("%s\n", str_p); return NULL; } } GetGameAPI = (void *)dlsym (game_library, "GetGameAPI"); if (!GetGameAPI) { Sys_UnloadGame (); return NULL; } return GetGameAPI (parms); }
void selfCheck() { // 'access' function tests based on uid, 'eaccess' ignores ACLs, have to set uid/gid. setgid(xware_gid); setuid(xware_uid); // uid after gid, otherwise fail on setting gid. if (verbose_mode) { printf("# [DEBUG] uid=%d, euid=%d, xware_uid=%d\n", getuid(), geteuid(), xware_uid); } // check uid if (getuid() != xware_uid) { fprintf(stderr, "Not running as xware user.\n"); exit(EXIT_FAILURE); } // check euid if (geteuid() != xware_uid) { fprintf(stderr, "Not running as xware user.\n"); exit(EXIT_FAILURE); } if (verbose_mode) { printf("# [DEBUG] gid=%d, egid=%d, xware_gid=%d\n", getgid(), getegid(), xware_gid); } // check gid if (getgid() != xware_gid) { fprintf(stderr, "Not running as xware group.\n"); exit(EXIT_FAILURE); } // check egid if (getegid() != xware_gid) { fprintf(stderr, "Not running as xware group.\n"); exit(EXIT_FAILURE); } // check supplementary groups nGrpList2 = getgroups(NGROUPS_MAX, grpList2); if (nGrpList2 == -1) { perror("getgroups"); exit(EXIT_FAILURE); } if (verbose_mode) { printf("# [DEBUG] xware is a member of: "); int i = 0; for (i = 0; i < nGrpList1; i++) { printf("%d\t", grpList1[i]); } printf("\n"); printf("# [DEBUG] post-setgroups, calling process groups: "); for (i = 0; i < nGrpList2; i++) { printf("%d\t", grpList2[i]); } printf("\n"); } if ( (nGrpList1 != nGrpList2) || (memcmp(grpList1, grpList2, nGrpList2 * sizeof(gid_t)) != 0)) { fprintf(stderr, "Failed to clear supplementary groups.\n"); exit(EXIT_FAILURE); } }
int main(void) { printf("uid = %d, gid = %d\n", getuid(), getgid()); return 0; }
static void regain_privilege(void) { setegid(getgid()); seteuid(getuid()); }