int lxc_read_from_file(const char *filename, void* buf, size_t count) { int fd = -1, saved_errno; ssize_t ret; process_lock(); fd = open(filename, O_RDONLY | O_CLOEXEC); process_unlock(); if (fd < 0) return -1; if (!buf || !count) { char buf2[100]; size_t count2 = 0; while ((ret = read(fd, buf2, 100)) > 0) count2 += ret; if (ret >= 0) ret = count2; } else { memset(buf, 0, count); ret = read(fd, buf, count); } if (ret < 0) ERROR("read %s: %s", filename, strerror(errno)); saved_errno = errno; process_lock(); close(fd); process_unlock(); errno = saved_errno; return ret; }
int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) { FILE *f; int err = 0; char *line = NULL; size_t len = 0; process_lock(); f = fopen(file, "r"); process_unlock(); if (!f) { SYSERROR("failed to open %s", file); return -1; } while (getline(&line, &len, f) != -1) { err = callback(line, data); if (err) { ERROR("Failed to parse config: %s", line); break; } } if (line) free(line); process_lock(); fclose(f); process_unlock(); return err; }
static void lxc_monitor_fifo_send(struct lxc_msg *msg, const char *lxcpath) { int fd,ret; char fifo_path[PATH_MAX]; BUILD_BUG_ON(sizeof(*msg) > PIPE_BUF); /* write not guaranteed atomic */ ret = lxc_monitor_fifo_name(lxcpath, fifo_path, sizeof(fifo_path), 0); if (ret < 0) return; process_lock(); fd = open(fifo_path, O_WRONLY); process_unlock(); if (fd < 0) { /* it is normal for this open to fail when there is no monitor * running, so we don't log it */ return; } ret = write(fd, msg, sizeof(*msg)); if (ret != sizeof(*msg)) { process_lock(); close(fd); process_unlock(); SYSERROR("failed to write monitor fifo %s", fifo_path); return; } process_lock(); close(fd); process_unlock(); }
int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline) { int fd, saved_errno; ssize_t ret; process_lock(); fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666); process_unlock(); if (fd < 0) return -1; ret = lxc_write_nointr(fd, buf, count); if (ret < 0) goto out_error; if ((size_t)ret != count) goto out_error; if (add_newline) { ret = lxc_write_nointr(fd, "\n", 1); if (ret != 1) goto out_error; } process_lock(); close(fd); process_unlock(); return 0; out_error: saved_errno = errno; process_lock(); close(fd); process_unlock(); errno = saved_errno; return -1; }
static char *apparmor_process_label_get(pid_t pid) { char path[100], *space; int ret; char *buf = NULL; int sz = 0; FILE *f; ret = snprintf(path, 100, "/proc/%d/attr/current", pid); if (ret < 0 || ret >= 100) { ERROR("path name too long"); return NULL; } again: process_lock(); f = fopen(path, "r"); process_unlock(); if (!f) { SYSERROR("opening %s\n", path); if (buf) free(buf); return NULL; } sz += 1024; buf = realloc(buf, sz); if (!buf) { ERROR("out of memory"); process_lock(); fclose(f); process_unlock(); return NULL; } memset(buf, 0, sz); ret = fread(buf, 1, sz - 1, f); process_lock(); fclose(f); process_unlock(); if (ret < 0) { ERROR("reading %s\n", path); free(buf); return NULL; } if (ret >= sz) goto again; space = index(buf, '\n'); if (space) *space = '\0'; space = index(buf, ' '); if (space) *space = '\0'; return buf; }
int lxclock(struct lxc_lock *l, int timeout) { int ret = -1, saved_errno = errno; struct flock lk; switch(l->type) { case LXC_LOCK_ANON_SEM: if (!timeout) { ret = sem_wait(l->u.sem); if (ret == -1) saved_errno = errno; } else { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { ret = -2; goto out; } ts.tv_sec += timeout; ret = sem_timedwait(l->u.sem, &ts); if (ret == -1) saved_errno = errno; } break; case LXC_LOCK_FLOCK: ret = -2; if (timeout) { ERROR("Error: timeout not supported with flock"); ret = -2; goto out; } if (!l->u.f.fname) { ERROR("Error: filename not set for flock"); ret = -2; goto out; } process_lock(); if (l->u.f.fd == -1) { l->u.f.fd = open(l->u.f.fname, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR); if (l->u.f.fd == -1) { process_unlock(); ERROR("Error opening %s", l->u.f.fname); goto out; } } lk.l_type = F_WRLCK; lk.l_whence = SEEK_SET; lk.l_start = 0; lk.l_len = 0; ret = fcntl(l->u.f.fd, F_SETLKW, &lk); process_unlock(); if (ret == -1) saved_errno = errno; break; } out: errno = saved_errno; return ret; }
/* routines used by monitor publishers (containers) */ int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path, size_t fifo_path_sz, int do_mkdirp) { int ret; const char *rundir; rundir = get_rundir(); if (do_mkdirp) { ret = snprintf(fifo_path, fifo_path_sz, "%s/lxc/%s", rundir, lxcpath); if (ret < 0 || ret >= fifo_path_sz) { ERROR("rundir/lxcpath (%s/%s) too long for monitor fifo", rundir, lxcpath); return -1; } process_lock(); ret = mkdir_p(fifo_path, 0755); process_unlock(); if (ret < 0) { ERROR("unable to create monitor fifo dir %s", fifo_path); return ret; } } ret = snprintf(fifo_path, fifo_path_sz, "%s/lxc/%s/monitor-fifo", rundir, lxcpath); if (ret < 0 || ret >= fifo_path_sz) { ERROR("rundir/lxcpath (%s/%s) too long for monitor fifo", rundir, lxcpath); return -1; } return 0; }
int process_login (void) { char pword[MAX_USER_NAME]; char user[MAX_USER_PASSWORD]; int u1count = 0; memset (user, 0, sizeof(user)); memset (pword, 0, sizeof(pword)); retry: if (u1count == MAX_TRY) { process_lock (); u1count = 0; goto login; } else { login: write_string ("\nlogin:"******"\nPassword:"******"\nIncorrect Login, Please try again"); u1count++; goto retry; } set_current_user_name (user); } write_string ("\n"); return 0; }
int lxcunlock(struct lxc_lock *l) { int ret = 0, saved_errno = errno; struct flock lk; switch(l->type) { case LXC_LOCK_ANON_SEM: if (!l->u.sem) ret = -2; else { ret = sem_post(l->u.sem); saved_errno = errno; } break; case LXC_LOCK_FLOCK: process_lock(); if (l->u.f.fd != -1) { lk.l_type = F_UNLCK; lk.l_whence = SEEK_SET; lk.l_start = 0; lk.l_len = 0; ret = fcntl(l->u.f.fd, F_SETLK, &lk); if (ret < 0) saved_errno = errno; close(l->u.f.fd); l->u.f.fd = -1; } else ret = -2; process_unlock(); break; } errno = saved_errno; return ret; }
/* * lxc_putlock() is only called when a container_new() fails, * or during container_put(), which is already guaranteed to * only be done by one task. * So the only exclusion we need to provide here is for regular * thread safety (i.e. file descriptor table changes). */ void lxc_putlock(struct lxc_lock *l) { if (!l) return; switch(l->type) { case LXC_LOCK_ANON_SEM: if (l->u.sem) { sem_close(l->u.sem); free(l->u.sem); l->u.sem = NULL; } break; case LXC_LOCK_FLOCK: process_lock(); if (l->u.f.fd != -1) { close(l->u.f.fd); l->u.f.fd = -1; } process_unlock(); if (l->u.f.fname) { free(l->u.f.fname); l->u.f.fname = NULL; } break; } free(l); }
static inline int lock_fclose(FILE *f) { int ret; process_lock(); ret = fclose(f); process_unlock(); return ret; }
/* routines used by monitor subscribers (lxc-monitor) */ int lxc_monitor_close(int fd) { int ret; process_lock(); ret = close(fd); process_unlock(); return ret; }
int lxc_read_seccomp_config(struct lxc_conf *conf) { FILE *f; int ret; if (!conf->seccomp) return 0; #if HAVE_SCMP_FILTER_CTX /* XXX for debug, pass in SCMP_ACT_TRAP */ conf->seccomp_ctx = seccomp_init(SCMP_ACT_ERRNO(31)); ret = !conf->seccomp_ctx; #else ret = seccomp_init(SCMP_ACT_ERRNO(31)) < 0; #endif if (ret) { ERROR("failed initializing seccomp"); return -1; } /* turn of no-new-privs. We don't want it in lxc, and it breaks * with apparmor */ if (seccomp_attr_set( #if HAVE_SCMP_FILTER_CTX conf->seccomp_ctx, #endif SCMP_FLTATR_CTL_NNP, 0)) { ERROR("failed to turn off n-new-privs\n"); return -1; } process_lock(); f = fopen(conf->seccomp, "r"); process_unlock(); if (!f) { SYSERROR("failed to open seccomp policy file %s\n", conf->seccomp); return -1; } ret = parse_config(f, conf); process_lock(); fclose(f); process_unlock(); return ret; }
int lxc_monitor_open(const char *lxcpath) { struct sockaddr_un addr; int fd,ret; int retry,backoff_ms[] = {10, 50, 100}; size_t len; if (lxc_monitor_sock_name(lxcpath, &addr) < 0) return -1; process_lock(); fd = socket(PF_UNIX, SOCK_STREAM, 0); process_unlock(); if (fd < 0) { ERROR("socket : %s", strerror(errno)); return -1; } len = strlen(&addr.sun_path[1]) + 1; if (len >= sizeof(addr.sun_path) - 1) { ret = -1; errno = ENAMETOOLONG; goto err1; } for (retry = 0; retry < sizeof(backoff_ms)/sizeof(backoff_ms[0]); retry++) { ret = connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len); if (ret == 0 || errno != ECONNREFUSED) break; ERROR("connect : backing off %d", backoff_ms[retry]); usleep(backoff_ms[retry] * 1000); } if (ret < 0) { ERROR("connect : %s", strerror(errno)); goto err1; } return fd; err1: process_lock(); close(fd); process_unlock(); return ret; }
int lxc_utmp_add_timer(struct lxc_epoll_descr *descr, lxc_mainloop_callback_t callback, void *data) { int fd, result; struct itimerspec timeout; struct lxc_utmp *utmp_data = (struct lxc_utmp *)data; process_lock(); fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); process_unlock(); if (fd < 0) { SYSERROR("failed to create timer"); return -1; } DEBUG("Setting up utmp shutdown timer"); /* set a one second timeout. Repeated. */ timeout.it_value.tv_sec = 1; timeout.it_value.tv_nsec = 0; timeout.it_interval.tv_sec = 1; timeout.it_interval.tv_nsec = 0; result = timerfd_settime(fd, 0, &timeout, NULL); if (result < 0) { SYSERROR("timerfd_settime:"); return -1; } if (lxc_mainloop_add_handler(descr, fd, callback, utmp_data)) { SYSERROR("failed to add utmp timer to mainloop"); process_lock(); close(fd); process_unlock(); return -1; } utmp_data->timer_fd = fd; return 0; }
/* * return block size of dev->src */ static int blk_getsize(struct bdev *bdev, unsigned long *size) { int fd, ret; char *path = bdev->src; if (strcmp(bdev->type, "loop") == 0) path = bdev->src + 5; process_lock(); fd = open(path, O_RDONLY); process_unlock(); if (fd < 0) return -1; ret = ioctl(fd, BLKGETSIZE64, size); process_lock(); close(fd); process_unlock(); return ret; }
static lxc_state_t freezer_state(const char *name, const char *lxcpath) { char *cgabspath = NULL; char freezer[MAXPATHLEN]; char status[MAXPATHLEN]; FILE *file; int ret; cgabspath = lxc_cgroup_get_hierarchy_abs_path("freezer", name, lxcpath); if (!cgabspath) return -1; ret = snprintf(freezer, MAXPATHLEN, "%s/freezer.state", cgabspath); if (ret < 0 || ret >= MAXPATHLEN) goto out; process_lock(); file = fopen(freezer, "r"); process_unlock(); if (!file) { ret = -1; goto out; } ret = fscanf(file, "%s", status); process_lock(); fclose(file); process_unlock(); if (ret == EOF) { SYSERROR("failed to read %s", freezer); ret = -1; goto out; } ret = lxc_str2state(status); out: free(cgabspath); return ret; }
int sha1sum_file(char *fnam, unsigned char *digest) { char *buf; int ret; FILE *f; long flen; if (!fnam) return -1; process_lock(); f = fopen_cloexec(fnam, "r"); process_unlock(); if (f < 0) { SYSERROR("Error opening template"); return -1; } if (fseek(f, 0, SEEK_END) < 0) { SYSERROR("Error seeking to end of template"); lock_fclose(f); return -1; } if ((flen = ftell(f)) < 0) { SYSERROR("Error telling size of template"); lock_fclose(f); return -1; } if (fseek(f, 0, SEEK_SET) < 0) { SYSERROR("Error seeking to start of template"); lock_fclose(f); return -1; } if ((buf = malloc(flen+1)) == NULL) { SYSERROR("Out of memory"); lock_fclose(f); return -1; } if (fread(buf, 1, flen, f) != flen) { SYSERROR("Failure reading template"); free(buf); lock_fclose(f); return -1; } if (lock_fclose(f) < 0) { SYSERROR("Failre closing template"); free(buf); return -1; } buf[flen] = '\0'; ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest); free(buf); return ret; }
static int _real_caps_last_cap(void) { int fd; int result = -1; /* try to get the maximum capability over the kernel * interface introduced in v3.2 */ process_lock(); fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY); process_unlock(); if (fd >= 0) { char buf[32]; char *ptr; int n; if ((n = read(fd, buf, 31)) >= 0) { buf[n] = '\0'; result = strtol(buf, &ptr, 10); if (!ptr || (*ptr != '\0' && *ptr != '\n') || result == LONG_MIN || result == LONG_MAX) result = -1; } process_lock(); close(fd); process_unlock(); } /* try to get it manually by trying to get the status of * each capability indiviually from the kernel */ if (result < 0) { int cap = 0; while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++; result = cap - 1; } return result; }
/* aa_getcon is not working right now. Use our hand-rolled version below */ static int apparmor_enabled(void) { struct stat statbuf; FILE *fin; char e; int ret; ret = stat(AA_MOUNT_RESTR, &statbuf); if (ret != 0) return 0; process_lock(); fin = fopen(AA_ENABLED_FILE, "r"); process_unlock(); if (!fin) return 0; ret = fscanf(fin, "%c", &e); process_lock(); fclose(fin); process_unlock(); if (ret == 1 && e == 'Y') return 1; return 0; }
static BOOL blocking_lock_record_process(blocking_lock_record *blr) { switch(blr->com_type) { case SMBlock: return process_lock(blr); case SMBlockread: return process_lockread(blr); case SMBlockingX: return process_lockingX(blr); default: DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); } return False; /* Keep compiler happy. */ }
static char *lxclock_name(const char *p, const char *n) { int ret; int len; char *dest; const char *rundir; /* lockfile will be: * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root * or * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root */ /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */ len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2; rundir = get_rundir(); len += strlen(rundir); if ((dest = malloc(len)) == NULL) return NULL; ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p); if (ret < 0 || ret >= len) { free(dest); return NULL; } process_lock(); ret = mkdir_p(dest, 0755); process_unlock(); if (ret < 0) { free(dest); return NULL; } ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n); if (ret < 0 || ret >= len) { free(dest); return NULL; } return dest; }
int lxc_utmp_del_timer(struct lxc_epoll_descr *descr, struct lxc_utmp *utmp_data) { int result; DEBUG("Clearing utmp shutdown timer"); result = lxc_mainloop_del_handler(descr, utmp_data->timer_fd); if (result < 0) SYSERROR("failed to del utmp timer from mainloop"); /* shutdown timer_fd */ process_lock(); close(utmp_data->timer_fd); process_unlock(); utmp_data->timer_fd = -1; if (result < 0) return -1; else return 0; }
/** * \brief Control request event handler * * This implementation handles the control requests for the GuiderPort device */ void EVENT_USB_Device_ControlRequest() { if (is_control()) { if (is_incoming()) { switch (USB_ControlRequest.bRequest) { case FOCUSER_RESET: process_reset(); break; case FOCUSER_SET: process_set(); break; case FOCUSER_LOCK: process_lock(); break; case FOCUSER_STOP: process_stop(); break; case FOCUSER_SERIAL: process_serial(); break; } } if (is_outgoing()) { switch (USB_ControlRequest.bRequest) { case FOCUSER_GET: process_get(); break; case FOCUSER_RCVR: process_rcvr(); break; case FOCUSER_SAVED: process_saved(); break; } } } }
static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) { struct dirent dirent, *direntp; DIR *dir; int ret, failed=0; char pathname[MAXPATHLEN]; process_lock(); dir = opendir(dirname); process_unlock(); if (!dir) { ERROR("%s: failed to open %s", __func__, dirname); return 0; } while (!readdir_r(dir, &dirent, &direntp)) { struct stat mystat; int rc; if (!direntp) break; if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) continue; rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name); if (rc < 0 || rc >= MAXPATHLEN) { ERROR("pathname too long"); failed=1; continue; } ret = lstat(pathname, &mystat); if (ret) { ERROR("%s: failed to stat %s", __func__, pathname); failed=1; continue; } if (mystat.st_dev != pdev) continue; if (S_ISDIR(mystat.st_mode)) { if (!_recursive_rmdir_onedev(pathname, pdev)) failed=1; } else { if (unlink(pathname) < 0) { ERROR("%s: failed to delete %s", __func__, pathname); failed=1; } } } if (rmdir(dirname) < 0) { ERROR("%s: failed to delete %s", __func__, dirname); failed=1; } process_lock(); ret = closedir(dir); process_unlock(); if (ret) { ERROR("%s: failed to close directory %s", __func__, dirname); failed=1; } return !failed; }
/* * Given a bdev (presumably blockdev-based), detect the fstype * by trying mounting (in a private mntns) it. * @bdev: bdev to investigate * @type: preallocated char* in which to write the fstype * @len: length of passed in char* * Returns length of fstype, of -1 on error */ static int detect_fs(struct bdev *bdev, char *type, int len) { int p[2], ret; size_t linelen; pid_t pid; FILE *f; char *sp1, *sp2, *sp3, *line = NULL; char *srcdev; if (!bdev || !bdev->src || !bdev->dest) return -1; srcdev = bdev->src; if (strcmp(bdev->type, "loop") == 0) srcdev = bdev->src + 5; process_lock(); ret = pipe(p); process_unlock(); if (ret < 0) return -1; if ((pid = fork()) < 0) return -1; if (pid > 0) { int status; process_lock(); close(p[1]); process_unlock(); memset(type, 0, len); ret = read(p[0], type, len-1); process_lock(); close(p[0]); process_unlock(); if (ret < 0) { SYSERROR("error reading from pipe"); wait(&status); return -1; } else if (ret == 0) { ERROR("child exited early - fstype not found"); wait(&status); return -1; } wait(&status); type[len-1] = '\0'; INFO("detected fstype %s for %s", type, srcdev); return ret; } process_unlock(); // we're no longer sharing if (unshare(CLONE_NEWNS) < 0) exit(1); ret = mount_unknow_fs(srcdev, bdev->dest, 0); if (ret < 0) { ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest); exit(1); } // if symlink, get the real dev name char devpath[MAXPATHLEN]; char *l = linkderef(srcdev, devpath); if (!l) exit(1); f = fopen("/proc/self/mounts", "r"); if (!f) exit(1); while (getline(&line, &linelen, f) != -1) { sp1 = index(line, ' '); if (!sp1) exit(1); *sp1 = '\0'; if (strcmp(line, l)) continue; sp2 = index(sp1+1, ' '); if (!sp2) exit(1); *sp2 = '\0'; sp3 = index(sp2+1, ' '); if (!sp3) exit(1); *sp3 = '\0'; sp2++; if (write(p[1], sp2, strlen(sp2)) != strlen(sp2)) exit(1); exit(0); } exit(1); }
const char *lxc_global_config_value(const char *option_name) { static const char *options[][2] = { { "lvm_vg", DEFAULT_VG }, { "lvm_thin_pool", DEFAULT_THIN_POOL }, { "zfsroot", DEFAULT_ZFSROOT }, { "lxcpath", LXCPATH }, { "cgroup.pattern", DEFAULT_CGROUP_PATTERN }, { "cgroup.use", NULL }, { NULL, NULL }, }; /* Protected by a mutex to eliminate conflicting load and store operations */ static const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; const char *(*ptr)[2]; const char *value; size_t i; char buf[1024], *p, *p2; FILE *fin = NULL; for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) { if (!strcmp(option_name, (*ptr)[0])) break; } if (!(*ptr)[0]) { errno = EINVAL; return NULL; } static_lock(); if (values[i]) { value = values[i]; static_unlock(); return value; } static_unlock(); process_lock(); fin = fopen_cloexec(LXC_GLOBAL_CONF, "r"); process_unlock(); if (fin) { while (fgets(buf, 1024, fin)) { if (buf[0] == '#') continue; p = strstr(buf, option_name); if (!p) continue; /* see if there was just white space in front * of the option name */ for (p2 = buf; p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p = strchr(p, '='); if (!p) continue; /* see if there was just white space after * the option name */ for (p2 += strlen(option_name); p2 < p; p2++) { if (*p2 != ' ' && *p2 != '\t') break; } if (p2 < p) continue; p++; while (*p && (*p == ' ' || *p == '\t')) p++; if (!*p) continue; static_lock(); values[i] = copy_global_config_value(p); static_unlock(); goto out; } } /* could not find value, use default */ static_lock(); values[i] = (*ptr)[1]; /* special case: if default value is NULL, * and there is no config, don't view that * as an error... */ if (!values[i]) errno = 0; static_unlock(); out: process_lock(); if (fin) fclose(fin); process_unlock(); static_lock(); value = values[i]; static_unlock(); return value; }
int lxc_attach_to_ns(pid_t pid, int which) { char path[MAXPATHLEN]; /* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>, * the file for user namepsaces in /proc/$pid/ns will be called * 'user' once the kernel supports it */ static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" }; static int flags[] = { CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWUSER, CLONE_NEWNET }; static const int size = sizeof(ns) / sizeof(char *); int fd[size]; int i, j, saved_errno; snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid); if (access(path, X_OK)) { ERROR("Does this kernel version support 'attach' ?"); return -1; } for (i = 0; i < size; i++) { /* ignore if we are not supposed to attach to that * namespace */ if (which != -1 && !(which & flags[i])) { fd[i] = -1; continue; } snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]); process_lock(); fd[i] = open(path, O_RDONLY | O_CLOEXEC); process_unlock(); if (fd[i] < 0) { saved_errno = errno; /* close all already opened file descriptors before * we return an error, so we don't leak them */ process_lock(); for (j = 0; j < i; j++) close(fd[j]); process_unlock(); errno = saved_errno; SYSERROR("failed to open '%s'", path); return -1; } } for (i = 0; i < size; i++) { if (fd[i] >= 0 && setns(fd[i], 0) != 0) { saved_errno = errno; for (j = i; j < size; j++) close(fd[j]); errno = saved_errno; SYSERROR("failed to set namespace '%s'", ns[i]); return -1; } process_lock(); close(fd[i]); process_unlock(); } return 0; }
struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) { struct lxc_proc_context_info *info = calloc(1, sizeof(*info)); FILE *proc_file; char proc_fn[MAXPATHLEN]; char *line = NULL; size_t line_bufsz = 0; int ret, found; if (!info) { SYSERROR("Could not allocate memory."); return NULL; } /* read capabilities */ snprintf(proc_fn, MAXPATHLEN, "/proc/%d/status", pid); process_lock(); proc_file = fopen(proc_fn, "r"); process_unlock(); if (!proc_file) { SYSERROR("Could not open %s", proc_fn); goto out_error; } found = 0; while (getline(&line, &line_bufsz, proc_file) != -1) { ret = sscanf(line, "CapBnd: %llx", &info->capability_mask); if (ret != EOF && ret > 0) { found = 1; break; } } if (line) free(line); process_lock(); fclose(proc_file); process_unlock(); if (!found) { SYSERROR("Could not read capability bounding set from %s", proc_fn); errno = ENOENT; goto out_error; } /* read personality */ snprintf(proc_fn, MAXPATHLEN, "/proc/%d/personality", pid); process_lock(); proc_file = fopen(proc_fn, "r"); process_unlock(); if (!proc_file) { SYSERROR("Could not open %s", proc_fn); goto out_error; } ret = fscanf(proc_file, "%lx", &info->personality); process_lock(); fclose(proc_file); process_unlock(); if (ret == EOF || ret == 0) { SYSERROR("Could not read personality from %s", proc_fn); errno = ENOENT; goto out_error; } info->lsm_label = lsm_process_label_get(pid); return info; out_error: free(info); return NULL; }
char *lxc_attach_getpwshell(uid_t uid) { /* local variables */ pid_t pid; int pipes[2]; int ret; int fd; char *result = NULL; /* we need to fork off a process that runs the * getent program, and we need to capture its * output, so we use a pipe for that purpose */ process_lock(); ret = pipe(pipes); process_unlock(); if (ret < 0) return NULL; pid = fork(); if (pid < 0) { process_lock(); close(pipes[0]); close(pipes[1]); process_unlock(); return NULL; } if (pid) { /* parent process */ FILE *pipe_f; char *line = NULL; size_t line_bufsz = 0; int found = 0; int status; process_lock(); close(pipes[1]); process_unlock(); process_lock(); pipe_f = fdopen(pipes[0], "r"); process_unlock(); while (getline(&line, &line_bufsz, pipe_f) != -1) { char *token; char *saveptr = NULL; long value; char *endptr = NULL; int i; /* if we already found something, just continue * to read until the pipe doesn't deliver any more * data, but don't modify the existing data * structure */ if (found) continue; /* trim line on the right hand side */ for (i = strlen(line); i > 0 && (line[i - 1] == '\n' || line[i - 1] == '\r'); --i) line[i - 1] = '\0'; /* split into tokens: first user name */ token = strtok_r(line, ":", &saveptr); if (!token) continue; /* next: dummy password field */ token = strtok_r(NULL, ":", &saveptr); if (!token) continue; /* next: user id */ token = strtok_r(NULL, ":", &saveptr); value = token ? strtol(token, &endptr, 10) : 0; if (!token || !endptr || *endptr || value == LONG_MIN || value == LONG_MAX) continue; /* dummy sanity check: user id matches */ if ((uid_t) value != uid) continue; /* skip fields: gid, gecos, dir, go to next field 'shell' */ for (i = 0; i < 4; i++) { token = strtok_r(NULL, ":", &saveptr); if (!token) break; } if (!token) continue; if (result) free(result); result = strdup(token); /* sanity check that there are no fields after that */ token = strtok_r(NULL, ":", &saveptr); if (token) continue; found = 1; } free(line); process_lock(); fclose(pipe_f); process_unlock(); again: if (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) goto again; return NULL; } /* some sanity checks: if anything even hinted at going * wrong: we can't be sure we have a valid result, so * we assume we don't */ if (!WIFEXITED(status)) return NULL; if (WEXITSTATUS(status) != 0) return NULL; if (!found) return NULL; return result; } else { /* child process */ char uid_buf[32]; char *arguments[] = { "getent", "passwd", uid_buf, NULL }; process_unlock(); // we're no longer sharing close(pipes[0]); /* we want to capture stdout */ dup2(pipes[1], 1); close(pipes[1]); /* get rid of stdin/stderr, so we try to associate it * with /dev/null */ fd = open("/dev/null", O_RDWR); if (fd < 0) { close(0); close(2); } else { dup2(fd, 0); dup2(fd, 2); close(fd); } /* finish argument list */ ret = snprintf(uid_buf, sizeof(uid_buf), "%ld", (long) uid); if (ret <= 0) exit(-1); /* try to run getent program */ (void) execvp("getent", arguments); exit(-1); } }