static int config_network_type(const char *key, char *value, struct lxc_conf *lxc_conf) { struct lxc_list *network = &lxc_conf->network; struct lxc_netdev *netdev; struct lxc_list *list; netdev = malloc(sizeof(*netdev)); if (!netdev) { SYSERROR("failed to allocate memory"); return -1; } memset(netdev, 0, sizeof(*netdev)); lxc_list_init(&netdev->ipv4); lxc_list_init(&netdev->ipv6); list = malloc(sizeof(*list)); if (!list) { SYSERROR("failed to allocate memory"); return -1; } lxc_list_init(list); list->elem = netdev; lxc_list_add_tail(network, list); if (!strcmp(value, "veth")) netdev->type = LXC_NET_VETH; else if (!strcmp(value, "macvlan")) netdev->type = LXC_NET_MACVLAN; else if (!strcmp(value, "vlan")) netdev->type = LXC_NET_VLAN; else if (!strcmp(value, "phys")) netdev->type = LXC_NET_PHYS; else if (!strcmp(value, "empty")) netdev->type = LXC_NET_EMPTY; else { ERROR("invalid network type %s", value); return -1; } return 0; }
/* This is a variation of get_list below it. This version allows two additional * features. If a list is passed to it, it adds to it. It allows for empty * entries (i.e. "group1,,group2") generating and empty list entry. */ static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) { char *workstr = NULL; char *workptr = NULL; char *next_ptr = NULL; struct lxc_list *worklist; struct lxc_list *workstr_list; workstr = strdup(input); if (!workstr) return NULL; workstr_list = str_list; if (!workstr_list) { workstr_list = malloc(sizeof(*workstr_list)); lxc_list_init(workstr_list); } for (workptr = workstr; workptr; workptr = next_ptr) { /* We can't use strtok_r here because it collapses multiple * delimiters into 1 making empty fields impossible... */ next_ptr = strchr(workptr, *delimiter); if (next_ptr) *next_ptr++ = '\0'; /* At this point, we'd like to check to see if this group is * already contained in the list and ignore it if it is... This * also helps us with any corner cases where a string begins or * ends with a delimiter. */ if (list_contains_entry(workptr, workstr_list)) { if (*workptr) fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr); else fprintf(stderr, "Duplicate NULL group in list - ignoring\n"); } else { worklist = malloc(sizeof(*worklist)); if (!worklist) break; worklist->elem = strdup(workptr); if (!worklist->elem) { free(worklist); break; } lxc_list_add_tail(workstr_list, worklist); } } free(workstr); return workstr_list; }
static struct lxc_list *get_list(char *input, char *delimiter) { char *workstr = NULL; char *workptr = NULL; char *sptr = NULL; char *token = NULL; struct lxc_list *worklist; struct lxc_list *workstr_list; workstr_list = malloc(sizeof(*workstr_list)); lxc_list_init(workstr_list); workstr = strdup(input); if (!workstr) { free(workstr_list); return NULL; } for (workptr = workstr;;workptr = NULL) { token = strtok_r(workptr, delimiter, &sptr); if (!token) { break; } worklist = malloc(sizeof(*worklist)); if (!worklist) break; worklist->elem = strdup(token); if (!worklist->elem) { free(worklist); break; } lxc_list_add_tail(workstr_list, worklist); } free(workstr); return workstr_list; }
int main(int argc, char *argv[]) { int c; unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS; char ttyname0[256], ttyname1[256], ttyname2[256]; int status; int ret; int pid; char *default_args[] = {"/bin/sh", NULL}; char buf[1]; int pipe1[2], // child tells parent it has unshared pipe2[2]; // parent tells child it is mapped and may proceed memset(ttyname0, '\0', sizeof(ttyname0)); memset(ttyname1, '\0', sizeof(ttyname1)); memset(ttyname2, '\0', sizeof(ttyname2)); if (isatty(0)) { ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0)); if (ret < 0) { perror("unable to open stdin."); exit(1); } ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1)); if (ret < 0) { printf("Warning: unable to open stdout, continuing."); memset(ttyname1, '\0', sizeof(ttyname1)); } ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2)); if (ret < 0) { printf("Warning: unable to open stderr, continuing."); memset(ttyname2, '\0', sizeof(ttyname2)); } } lxc_list_init(&active_map); while ((c = getopt(argc, argv, "m:h")) != EOF) { switch (c) { case 'm': if (parse_map(optarg)) usage(argv[0]); break; case 'h': default: usage(argv[0]); } }; if (lxc_list_empty(&active_map)) { if (find_default_map()) { fprintf(stderr, "You have no allocated subuids or subgids\n"); exit(1); } } argv = &argv[optind]; argc = argc - optind; if (argc < 1) { argv = default_args; argc = 1; } if (pipe(pipe1) < 0 || pipe(pipe2) < 0) { perror("pipe"); exit(1); } if ((pid = fork()) == 0) { // Child. close(pipe1[0]); close(pipe2[1]); opentty(ttyname0, 0); opentty(ttyname1, 1); opentty(ttyname2, 2); ret = unshare(flags); if (ret < 0) { perror("unshare"); return 1; } buf[0] = '1'; if (write(pipe1[1], buf, 1) < 1) { perror("write pipe"); exit(1); } if (read(pipe2[0], buf, 1) < 1) { perror("read pipe"); exit(1); } if (buf[0] != '1') { fprintf(stderr, "parent had an error, child exiting\n"); exit(1); } close(pipe1[1]); close(pipe2[0]); return do_child((void*)argv); } close(pipe1[1]); close(pipe2[0]); if (read(pipe1[0], buf, 1) < 1) { perror("read pipe"); exit(1); } buf[0] = '1'; if (lxc_map_ids(&active_map, pid)) { fprintf(stderr, "error mapping child\n"); ret = 0; } if (write(pipe2[1], buf, 1) < 0) { perror("write to pipe"); exit(1); } if ((ret = waitpid(pid, &status, __WALL)) < 0) { printf("waitpid() returns %d, errno %d\n", ret, errno); exit(1); } exit(WEXITSTATUS(status)); }
int main(int argc, char *argv[]) { int c, pid, ret, status; char buf[1]; int pipe_fds1[2], /* child tells parent it has unshared */ pipe_fds2[2]; /* parent tells child it is mapped and may proceed */ unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS; char ttyname0[256] = {0}, ttyname1[256] = {0}, ttyname2[256] = {0}; char *default_args[] = {"/bin/sh", NULL}; lxc_log_fd = STDERR_FILENO; if (isatty(STDIN_FILENO)) { ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0)); if (ret < 0) { CMD_SYSERROR("Failed to open stdin"); _exit(EXIT_FAILURE); } ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1)); if (ret < 0) { CMD_SYSINFO("Failed to open stdout. Continuing"); ttyname1[0] = '\0'; } ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2)); if (ret < 0) { CMD_SYSINFO("Failed to open stderr. Continuing"); ttyname2[0] = '\0'; } } lxc_list_init(&active_map); while ((c = getopt(argc, argv, "m:h")) != EOF) { switch (c) { case 'm': ret = parse_map(optarg); if (ret < 0) { usage(argv[0]); _exit(EXIT_FAILURE); } break; case 'h': usage(argv[0]); _exit(EXIT_SUCCESS); default: usage(argv[0]); _exit(EXIT_FAILURE); } }; if (lxc_list_empty(&active_map)) { ret = find_default_map(); if (ret < 0) { fprintf(stderr, "Failed to find subuid or subgid allocation\n"); _exit(EXIT_FAILURE); } } argv = &argv[optind]; argc = argc - optind; if (argc < 1) argv = default_args; ret = pipe2(pipe_fds1, O_CLOEXEC); if (ret < 0) { CMD_SYSERROR("Failed to open new pipe"); _exit(EXIT_FAILURE); } ret = pipe2(pipe_fds2, O_CLOEXEC); if (ret < 0) { CMD_SYSERROR("Failed to open new pipe"); close(pipe_fds1[0]); close(pipe_fds1[1]); _exit(EXIT_FAILURE); } pid = fork(); if (pid < 0) { close(pipe_fds1[0]); close(pipe_fds1[1]); close(pipe_fds2[0]); close(pipe_fds2[1]); _exit(EXIT_FAILURE); } if (pid == 0) { close(pipe_fds1[0]); close(pipe_fds2[1]); opentty(ttyname0, STDIN_FILENO); opentty(ttyname1, STDOUT_FILENO); opentty(ttyname2, STDERR_FILENO); ret = unshare(flags); if (ret < 0) { CMD_SYSERROR("Failed to unshare mount and user namespace"); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } buf[0] = '1'; ret = lxc_write_nointr(pipe_fds1[1], buf, 1); if (ret != 1) { CMD_SYSERROR("Failed to write to pipe file descriptor %d", pipe_fds1[1]); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } ret = lxc_read_nointr(pipe_fds2[0], buf, 1); if (ret != 1) { CMD_SYSERROR("Failed to read from pipe file descriptor %d", pipe_fds2[0]); close(pipe_fds1[1]); close(pipe_fds2[0]); _exit(EXIT_FAILURE); } close(pipe_fds1[1]); close(pipe_fds2[0]); if (buf[0] != '1') { fprintf(stderr, "Received unexpected value from parent process\n"); _exit(EXIT_FAILURE); } ret = do_child((void *)argv); if (ret < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); } close(pipe_fds1[1]); close(pipe_fds2[0]); ret = lxc_read_nointr(pipe_fds1[0], buf, 1); if (ret <= 0) CMD_SYSERROR("Failed to read from pipe file descriptor %d", pipe_fds1[0]); buf[0] = '1'; ret = lxc_map_ids(&active_map, pid); if (ret < 0) fprintf(stderr, "Failed to write id mapping for child process\n"); ret = lxc_write_nointr(pipe_fds2[1], buf, 1); if (ret < 0) { CMD_SYSERROR("Failed to write to pipe file descriptor %d", pipe_fds2[1]); _exit(EXIT_FAILURE); } ret = waitpid(pid, &status, __WALL); if (ret < 0) { CMD_SYSERROR("Failed to wait on child process"); _exit(EXIT_FAILURE); } _exit(WEXITSTATUS(status)); }
static int config_network_ipv4(const char *key, char *value, struct lxc_conf *lxc_conf) { struct lxc_netdev *netdev; struct lxc_inetdev *inetdev; struct lxc_list *list; char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL; netdev = network_netdev(key, value, &lxc_conf->network); if (!netdev) return -1; inetdev = malloc(sizeof(*inetdev)); if (!inetdev) { SYSERROR("failed to allocate ipv4 address"); return -1; } memset(inetdev, 0, sizeof(*inetdev)); list = malloc(sizeof(*list)); if (!list) { SYSERROR("failed to allocate memory"); return -1; } lxc_list_init(list); list->elem = inetdev; addr = value; cursor = strstr(addr, " "); if (cursor) { *cursor = '\0'; bcast = cursor + 1; } slash = strstr(addr, "/"); if (slash) { *slash = '\0'; prefix = slash + 1; } if (!addr) { ERROR("no address specified"); return -1; } if (!inet_pton(AF_INET, addr, &inetdev->addr)) { SYSERROR("invalid ipv4 address: %s", value); return -1; } if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) { SYSERROR("invalid ipv4 broadcast address: %s", value); return -1; } /* no prefix specified, determine it from the network class */ inetdev->prefix = prefix ? atoi(prefix) : config_ip_prefix(&inetdev->addr); /* if no broadcast address, let compute one from the * prefix and address */ if (!bcast) { inetdev->bcast.s_addr = inetdev->addr.s_addr; inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> inetdev->prefix); }