static int open_and_lock(char *path) { int fd, ret; struct flock lk; fd = open(path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR); if (fd < 0) { usernic_error("Failed to open \"%s\": %s\n", path, strerror(errno)); return -1; } lk.l_type = F_WRLCK; lk.l_whence = SEEK_SET; lk.l_start = 0; lk.l_len = 0; ret = fcntl(fd, F_SETLKW, &lk); if (ret < 0) { usernic_error("Failed to lock \"%s\": %s\n", path, strerror(errno)); close(fd); return -1; } return fd; }
static char *get_username(void) { __do_free char *buf = NULL; struct passwd pwent; struct passwd *pwentp = NULL; size_t bufsize; int ret; bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) bufsize = 1024; buf = malloc(bufsize); if (!buf) return NULL; ret = getpwuid_r(getuid(), &pwent, buf, bufsize, &pwentp); if (!pwentp) { if (ret == 0) usernic_error("%s", "Could not find matched password record\n"); CMD_SYSERROR("Failed to get username: %u\n", getuid()); return NULL; } return strdup(pwent.pw_name); }
static int instantiate_veth(char *veth1, char *veth2) { int ret; ret = lxc_veth_create(veth1, veth2); if (ret < 0) { usernic_error("Failed to create %s-%s : %s.\n", veth1, veth2, strerror(-ret)); return -1; } /* Changing the high byte of the mac address to 0xfe, the bridge * interface will always keep the host's mac address and not take the * mac address of a container. */ ret = setup_private_host_hw_addr(veth1); if (ret < 0) usernic_error("Failed to change mac address of host interface " "%s : %s\n", veth1, strerror(-ret)); return netdev_set_flag(veth1, IFF_UP); }
static char *get_username(void) { struct passwd *pwd; pwd = getpwuid(getuid()); if (!pwd) { usernic_error("Failed to get username: %s\n", strerror(errno)); return NULL; } return pwd->pw_name; }
static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n) { struct alloted_s *cur, *al; if (!head || !name) { /* Sanity check. Parameters should not be null. */ usernic_error("%s\n", "Unexpected NULL argument"); return NULL; } al = malloc(sizeof(struct alloted_s)); if (!al) { usernic_error("Failed to allocate memory: %s\n", strerror(errno)); return NULL; } al->name = strdup(name); if (!al->name) { free(al); return NULL; } al->allowed = n; al->next = NULL; if (!*head) { *head = al; return al; } cur = *head; while (cur->next) cur = cur->next; cur->next = al; return al; }
static int create_nic(char *nic, char *br, int pid, char **cnic) { char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ]; int mtu, ret; ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic); if (ret < 0 || ret >= IFNAMSIZ) { usernic_error("%s", "Could not create nic name\n"); return -1; } ret = snprintf(veth2buf, IFNAMSIZ, "%sp", veth1buf); if (ret < 0 || ret >= IFNAMSIZ) { usernic_error("%s\n", "Could not create nic name"); return -1; } /* create the nics */ ret = instantiate_veth(veth1buf, veth2buf); if (ret < 0) { usernic_error("%s", "Error creating veth tunnel\n"); return -1; } if (strcmp(br, "none")) { /* copy the bridge's mtu to both ends */ mtu = get_mtu(br); if (mtu > 0) { ret = lxc_netdev_set_mtu(veth1buf, mtu); if (ret < 0) { usernic_error("Failed to set mtu to %d on %s\n", mtu, veth1buf); goto out_del; } ret = lxc_netdev_set_mtu(veth2buf, mtu); if (ret < 0) { usernic_error("Failed to set mtu to %d on %s\n", mtu, veth2buf); goto out_del; } } /* attach veth1 to bridge */ ret = lxc_bridge_attach(br, veth1buf); if (ret < 0) { usernic_error("Error attaching %s to %s\n", veth1buf, br); goto out_del; } } /* pass veth2 to target netns */ ret = lxc_netdev_move_by_name(veth2buf, pid, NULL); if (ret < 0) { usernic_error("Error moving %s to network namespace of %d\n", veth2buf, pid); goto out_del; } *cnic = strdup(veth2buf); if (!*cnic) { usernic_error("Failed to copy string \"%s\"\n", veth2buf); return -1; } return 0; out_del: lxc_netdev_delete_by_name(veth1buf); return -1; }
/* The configuration file consists of lines of the form: * * user type bridge count * or * @group type bridge count * * Return the count entry for the calling user if there is one. Else * return -1. */ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted) { int n, ret; char name[100], type[100], br[100]; char **groups; FILE *fin; int count = 0; size_t len = 0; char *line = NULL; fin = fopen(LXC_USERNIC_CONF, "r"); if (!fin) { usernic_error("Failed to open \"%s\": %s\n", LXC_USERNIC_CONF, strerror(errno)); return -1; } groups = get_groupnames(); while ((getline(&line, &len, fin)) != -1) { ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n); if (ret != 4) continue; if (strlen(name) == 0) continue; if (strcmp(name, me)) { if (name[0] != '@') continue; if (!name_is_in_groupnames(name + 1, groups)) continue; } if (strcmp(type, intype)) continue; if (strcmp(link, br)) continue; /* Found the user or group with the appropriate settings, * therefore finish the search. What to do if there are more * than one applicable lines? not specified in the docs. Since * getline is implemented with realloc, we don't need to free * line until exiting func. * * If append_alloted returns NULL, e.g. due to a malloc error, * we set count to 0 and break the loop, allowing cleanup and * then exiting from main(). */ if (!append_alloted(alloted, name, n)) { count = 0; break; } count += n; } free_groupnames(groups); fclose(fin); free(line); /* Now return the total number of nics that this user can create. */ return count; }