]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxc_user_nic.c
ovl_rsync: make sure to umount
[mirror_lxc.git] / src / lxc / lxc_user_nic.c
index 7d91b2b419b6a66717879b2f6e7e5b7284aac5fe..af7f8b4599a5dd6af3c6bcce7ac3f4a5f9e7b625 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdbool.h>
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/file.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
 #include <sys/param.h>
-#include <sched.h>
+
 #include "config.h"
 #include "utils.h"
+#include "network.h"
 
-#if ISTEST
-#define CONF_FILE "/tmp/lxc-usernet"
-#define DB_FILE "/tmp/nics"
-#else
-#define CONF_FILE LXC_USERNIC_CONF
-#define DB_FILE LXC_USERNIC_DB
-#endif
-
-#include "nl.h"
-
-#ifndef IFLA_LINKMODE
-#  define IFLA_LINKMODE 17
-#endif
-
-#ifndef IFLA_LINKINFO
-#  define IFLA_LINKINFO 18
-#endif
-
-#ifndef IFLA_NET_NS_PID
-#  define IFLA_NET_NS_PID 19
-#endif
-
-#ifndef IFLA_INFO_KIND
-# define IFLA_INFO_KIND 1
-#endif
-
-#ifndef IFLA_VLAN_ID
-# define IFLA_VLAN_ID 1
-#endif
-
-#ifndef IFLA_INFO_DATA
-#  define IFLA_INFO_DATA 2
-#endif
-
-#ifndef VETH_INFO_PEER
-# define VETH_INFO_PEER 1
-#endif
-
-#ifndef IFLA_MACVLAN_MODE
-# define IFLA_MACVLAN_MODE 1
-#endif
-
-void usage(char *me, bool fail)
+static void usage(char *me, bool fail)
 {
        fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
        fprintf(stderr, " nicname is the name to use inside the container\n");
@@ -137,46 +97,224 @@ static char *get_username(void)
        return pwd->pw_name;
 }
 
+static void free_groupnames(char **groupnames)
+{
+       int i;
+       if (!groupnames)
+               return;
+       for (i = 0; groupnames[i]; i++)
+               free(groupnames[i]);
+       free(groupnames);
+}
+
+static char **get_groupnames(void)
+{
+       int ngroups;
+       gid_t *group_ids;
+       int ret, i;
+       char **groupnames;
+       struct group *gr;
+
+       ngroups = getgroups(0, NULL);
+
+       if (ngroups == -1) {
+               fprintf(stderr, "Failed to get number of groups user belongs to: %s\n", strerror(errno));
+               return NULL;
+       }
+       if (ngroups == 0)
+               return NULL;
+
+       group_ids = (gid_t *)malloc(sizeof(gid_t)*ngroups);
+
+       if (group_ids == NULL) {
+               fprintf(stderr, "Out of memory while getting groups the user belongs to\n");
+               return NULL;
+       }
+
+       ret = getgroups(ngroups, group_ids);
+
+       if (ret < 0) {
+               free(group_ids);
+               fprintf(stderr, "Failed to get process groups: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       groupnames = (char **)malloc(sizeof(char *)*(ngroups+1));
+
+       if (groupnames == NULL) {
+               free(group_ids);
+               fprintf(stderr, "Out of memory while getting group names\n");
+               return NULL;
+       }
+
+       memset(groupnames, 0, sizeof(char *)*(ngroups+1));
+
+       for (i=0; i<ngroups; i++ ) {
+               gr = getgrgid(group_ids[i]);
+
+               if (gr == NULL) {
+                       fprintf(stderr, "Failed to get group name\n");
+                       free(group_ids);
+                       free_groupnames(groupnames);
+                       return NULL;
+               }
+
+               groupnames[i] = strdup(gr->gr_name);
+
+               if (groupnames[i] == NULL) {
+                       fprintf(stderr, "Failed to copy group name: %s", gr->gr_name);
+                       free(group_ids);
+                       free_groupnames(groupnames);
+                       return NULL;
+               }
+       }
+
+       free(group_ids);
+
+       return groupnames;
+}
+
+static bool name_is_in_groupnames(char *name, char **groupnames)
+{
+       while (groupnames != NULL) {
+               if (strcmp(name, *groupnames) == 0)
+                       return true;
+               groupnames++;
+       }
+       return false;
+}
+
+struct alloted_s {
+       char *name;
+       int allowed;
+       struct alloted_s *next;
+};
+
+static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n)
+{
+       struct alloted_s *cur, *al;
+
+       if (head == NULL || name == NULL) {
+               // sanity check. parameters should not be null
+               fprintf(stderr, "NULL parameters to append_alloted not allowed\n");
+               return NULL;
+       }
+
+       al = (struct alloted_s *)malloc(sizeof(struct alloted_s));
+
+       if (al == NULL) {
+               // unable to allocate memory to new struct
+               fprintf(stderr, "Out of memory in append_alloted\n");
+               return NULL;
+       }
+
+       al->name = strdup(name);
+
+       if (al->name == NULL) {
+               free(al);
+               return NULL;
+       }
+
+       al->allowed = n;
+       al->next = NULL;
+
+       if (*head == NULL) {
+               *head = al;
+               return al;
+       }
+
+       cur = *head;
+       while (cur->next != NULL)
+               cur = cur->next;
+
+       cur->next = al;
+       return al;
+}
+
+static void free_alloted(struct alloted_s **head)
+{
+       struct alloted_s *cur;
+
+       if (head == NULL) {
+               return;
+       }
+
+       cur = *head;
+
+       while (cur != NULL) {
+               cur = cur->next;
+               free((*head)->name);
+               free(*head);
+               *head = cur;
+       }
+}
+
 /* 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)
+static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted)
 {
-       FILE *fin = fopen(CONF_FILE, "r");
+       FILE *fin = fopen(LXC_USERNIC_CONF, "r");
        char *line = NULL;
-       char user[100], type[100], br[100];
+       char name[100], type[100], br[100];
        size_t len = 0;
-       int n = -1, ret;
+       int n, ret, count = 0;
+       char **groups;
 
        if (!fin) {
-               fprintf(stderr, "Failed to open %s: %s\n", CONF_FILE,
+               fprintf(stderr, "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", user, type, br, &n);
+               ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
 
                if (ret != 4)
                        continue;
-               if (strcmp(user, me) != 0)
+
+               if (strlen(name) == 0)
                        continue;
+
+               if (strcmp(name, me) != 0)
+               {
+                       if (name[0] != '@')
+                               continue;
+                       if (!name_is_in_groupnames(name+1, groups))
+                               continue;
+               }
                if (strcmp(type, intype) != 0)
                        continue;
                if (strcmp(link, br) != 0)
                        continue;
-               free(line);
-               fclose(fin);
-               return n;
+
+               /* 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) == NULL) {
+                       count = 0;
+                       break;
+               }
+               count += n;
        }
+
+       free_groupnames(groups);
        fclose(fin);
-       if (line)
-               free(line);
-       return -1;
+       free(line);
+
+       // now return the total number of nics that this user can create
+       return count;
 }
 
 static char *get_eol(char *s, char *e)
@@ -196,7 +334,7 @@ static char *get_eow(char *s, char *e)
 static char *find_line(char *p, char *e, char *u, char *t, char *l)
 {
        char *p1, *p2, *ret;
-       
+
        while (p<e  && (p1 = get_eol(p, e)) < e) {
                ret = p;
                if (*p == '#')
@@ -229,212 +367,18 @@ static bool nic_exists(char *nic)
        int ret;
        struct stat sb;
 
-#if ISTEST
-       ret = snprintf(path, MAXPATHLEN, "/tmp/lxcnettest/%s", nic);
-#else
+       if (strcmp(nic, "none") == 0)
+               return true;
        ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
-#endif
        if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
-               return true;
+               return false;
        ret = stat(path, &sb);
        if (ret != 0)
                return false;
        return true;
 }
 
-struct link_req {
-       struct nlmsg nlmsg;
-       struct ifinfomsg ifinfomsg;
-};
-
-#if ! ISTEST
-
-static int lxc_veth_create(const char *name1, const char *name2)
-{
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
-       struct link_req *link_req;
-       struct rtattr *nest1, *nest2, *nest3;
-       int len, err;
-
-       err = netlink_open(&nlh, NETLINK_ROUTE);
-       if (err)
-               return err;
-
-       err = -EINVAL;
-       len = strlen(name1);
-       if (len == 1 || len >= IFNAMSIZ)
-               goto out;
-
-       len = strlen(name2);
-       if (len == 1 || len >= IFNAMSIZ)
-               goto out;
-
-       err = -ENOMEM;
-       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!nlmsg)
-               goto out;
-
-       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!answer)
-               goto out;
-
-       link_req = (struct link_req *)nlmsg;
-       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
-       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       nlmsg->nlmsghdr.nlmsg_flags =
-               NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
-       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
-
-       err = -EINVAL;
-       nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
-       if (!nest1)
-               goto out;
-
-       if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
-               goto out;
-
-       nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
-       if (!nest2)
-               goto out;
-
-       nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
-       if (!nest3)
-               goto out;
-
-       nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
-
-       if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
-               goto out;
-
-       nla_end_nested(nlmsg, nest3);
-
-       nla_end_nested(nlmsg, nest2);
-
-       nla_end_nested(nlmsg, nest1);
-
-       if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
-               goto out;
-
-       err = netlink_transaction(&nlh, nlmsg, answer);
-out:
-       netlink_close(&nlh);
-       nlmsg_free(answer);
-       nlmsg_free(nlmsg);
-       return err;
-}
-
-static int lxc_netdev_move(char *ifname, pid_t pid)
-{
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL;
-       struct link_req *link_req;
-       int err, index;
-
-       index = if_nametoindex(ifname);
-       if (!ifname)
-               return -EINVAL;
-
-       err = netlink_open(&nlh, NETLINK_ROUTE);
-       if (err)
-               return err;
-
-       err = -ENOMEM;
-       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!nlmsg)
-               goto out;
-
-       link_req = (struct link_req *)nlmsg;
-       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
-       link_req->ifinfomsg.ifi_index = index;
-       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
-       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
-
-       if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
-               goto out;
-
-       err = netlink_transaction(&nlh, nlmsg, nlmsg);
-out:
-       netlink_close(&nlh);
-       nlmsg_free(nlmsg);
-       return err;
-}
-
-static int setup_private_host_hw_addr(char *veth1)
-{
-       struct ifreq ifr;
-       int err;
-       int sockfd;
-
-       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sockfd < 0)
-               return -errno;
-
-       snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
-       err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
-       if (err < 0) {
-               close(sockfd);
-               return -errno;
-       }
-
-       ifr.ifr_hwaddr.sa_data[0] = 0xfe;
-       err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
-       close(sockfd);
-       if (err < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int netdev_set_flag(const char *name, int flag)
-{
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
-       struct link_req *link_req;
-       int index, len, err;
-
-       err = netlink_open(&nlh, NETLINK_ROUTE);
-       if (err)
-               return err;
-
-       err = -EINVAL;
-       len = strlen(name);
-       if (len == 1 || len >= IFNAMSIZ)
-               goto out;
-
-       err = -ENOMEM;
-       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!nlmsg)
-               goto out;
-
-       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!answer)
-               goto out;
-
-       err = -EINVAL;
-       index = if_nametoindex(name);
-       if (!index)
-               goto out;
-
-       link_req = (struct link_req *)nlmsg;
-       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
-       link_req->ifinfomsg.ifi_index = index;
-       link_req->ifinfomsg.ifi_change |= IFF_UP;
-       link_req->ifinfomsg.ifi_flags |= flag;
-       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
-       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
-
-       err = netlink_transaction(&nlh, nlmsg, answer);
-out:
-       netlink_close(&nlh);
-       nlmsg_free(nlmsg);
-       nlmsg_free(answer);
-       return err;
-}
-
-static int instanciate_veth(char *n1, char **n2)
+static int instantiate_veth(char *n1, char **n2)
 {
        int err;
 
@@ -456,110 +400,25 @@ static int instanciate_veth(char *n1, char **n2)
         * of a container */
        err = setup_private_host_hw_addr(n1);
        if (err) {
-               fprintf(stderr, "failed to change mac address of host interface '%s' : %s",
+               fprintf(stderr, "failed to change mac address of host interface '%s' : %s\n",
                        n1, strerror(-err));
        }
 
        return netdev_set_flag(n1, IFF_UP);
 }
 
-static int lxc_bridge_attach(const char *bridge, const char *ifname)
-{
-       int fd, index, err;
-       struct ifreq ifr;
-
-       if (strlen(ifname) >= IFNAMSIZ)
-               return -EINVAL;
-
-       index = if_nametoindex(ifname);
-       if (!index)
-               return -EINVAL;
-
-       fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (fd < 0)
-               return -errno;
-
-       strncpy(ifr.ifr_name, bridge, IFNAMSIZ-1);
-       ifr.ifr_name[IFNAMSIZ-1] = '\0';
-       ifr.ifr_ifindex = index;
-       err = ioctl(fd, SIOCBRADDIF, &ifr);
-       close(fd);
-       if (err)
-               err = -errno;
-
-       return err;
-}
-
-static int lxc_netdev_delete_by_index(int ifindex)
-{
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
-       struct link_req *link_req;
-       int err;
-
-       err = netlink_open(&nlh, NETLINK_ROUTE);
-       if (err)
-               return err;
-
-       err = -ENOMEM;
-       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!nlmsg)
-               goto out;
-
-       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!answer)
-               goto out;
-
-       link_req = (struct link_req *)nlmsg;
-       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
-       link_req->ifinfomsg.ifi_index = ifindex;
-       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
-       nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
-
-       err = netlink_transaction(&nlh, nlmsg, answer);
-out:
-       netlink_close(&nlh);
-       nlmsg_free(answer);
-       nlmsg_free(nlmsg);
-       return err;
-}
-
-static int lxc_netdev_delete_by_name(const char *name)
+static int get_mtu(char *name)
 {
-       int index;
-
-       index = if_nametoindex(name);
-       if (!index)
-               return -EINVAL;
-
-       return lxc_netdev_delete_by_index(index);
-}
-#else
-static int lxc_netdev_delete_by_name(const char *name)
-{
-       char path[200];
-       sprintf(path, "/tmp/lxcnettest/%s", name);
-       return unlink(path);
+       int idx = if_nametoindex(name);
+       return netdev_get_mtu(idx);
 }
 
-#endif
-
 static bool create_nic(char *nic, char *br, int pid, char **cnic)
 {
-#if ISTEST
-       char path[200];
-       sprintf(path, "/tmp/lxcnettest/%s", nic);
-       int fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
-       if (fd < 0)
-               return false;
-       close(fd);
-       return true;
-#else
        char *veth1buf, *veth2buf;
        veth1buf = alloca(IFNAMSIZ);
        veth2buf = alloca(IFNAMSIZ);
-       int ret;
+       int ret, mtu;
 
        ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
        if (ret < 0 || ret >= IFNAMSIZ) {
@@ -568,19 +427,31 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
        }
 
        /* create the nics */
-       if (instanciate_veth(veth1buf, &veth2buf) < 0) {
+       if (instantiate_veth(veth1buf, &veth2buf) < 0) {
                fprintf(stderr, "Error creating veth tunnel\n");
                return false;
        }
 
-       /* attach veth1 to bridge */
-       if (lxc_bridge_attach(br, veth1buf) < 0) {
-               fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
-               goto out_del;
+       if (strcmp(br, "none") != 0) {
+               /* copy the bridge's mtu to both ends */
+               mtu = get_mtu(br);
+               if (mtu != -1) {
+                       if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
+                                       lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
+                               fprintf(stderr, "Failed setting mtu\n");
+                               goto out_del;
+                       }
+               }
+
+               /* attach veth1 to bridge */
+               if (lxc_bridge_attach(br, veth1buf) < 0) {
+                       fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
+                       goto out_del;
+               }
        }
 
        /* pass veth2 to target netns */
-       ret = lxc_netdev_move(veth2buf, pid);
+       ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
        if (ret < 0) {
                fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
                goto out_del;
@@ -591,25 +462,23 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
 out_del:
        lxc_netdev_delete_by_name(veth1buf);
        return false;
-#endif
 }
 
 /*
  * Get a new nic.
- * *dest will container the name (lxcuser-%d) which is attached
+ * *dest will container the name (vethXXXXXX) which is attached
  * on the host to the lxc bridge
  */
-static void get_new_nicname(char **dest, char *br, int pid, char **cnic)
+static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
 {
-       int i = 0;
-       // TODO - speed this up.  For large installations we won't
-       // want n stats for every nth container startup.
-       while (1) {
-               sprintf(*dest, "lxcuser-%d", i);
-               if (!nic_exists(*dest) && create_nic(*dest, br, pid, cnic))
-                       return;
-               i++;
+       char template[IFNAMSIZ];
+       snprintf(template, sizeof(template), "vethXXXXXX");
+       *dest = lxc_mkifname(template);
+
+       if (!create_nic(*dest, br, pid, cnic)) {
+               return false;
        }
+       return true;
 }
 
 static bool get_nic_from_line(char *p, char **nic)
@@ -639,7 +508,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
 
        nic = alloca(100);
 
-       fstat(fd, &sb);
+       if (fstat(fd, &sb) < 0) {
+               fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+               return false;
+       }
        len = sb.st_size;
        if (len == 0)
                return true;
@@ -652,7 +524,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
        p = buf;
        e = buf + len;
        while ((p = find_line(p, e, me, t, br)) != NULL) {
-               struct entry_line *newe = realloc(entry_lines, n+1);
+               struct entry_line *newe = realloc(entry_lines, sizeof(*entry_lines)*(n+1));
                if (!newe) {
                        free(entry_lines);
                        return false;
@@ -669,7 +541,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
                p += entry_lines[n-1].len + 1;
                if (p >= e)
                        break;
-       }
+       }
        p = buf;
        for (i=0; i<n; i++) {
                if (!entry_lines[i].keep)
@@ -704,16 +576,27 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
  * The dbfile has lines of the format:
  * user type bridge nicname
  */
-static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
+static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
 {
        off_t len, slen;
        struct stat sb;
        char *buf = NULL, *newline;
        int ret, count = 0;
+       char *owner;
+       struct alloted_s *n;
 
-       cull_entries(fd, me, intype, br);
+       for (n=names; n!=NULL; n=n->next)
+               cull_entries(fd, n->name, intype, br);
 
-       fstat(fd, &sb);
+       if (allowed == 0)
+               return false;
+
+       owner = names->name;
+
+       if (fstat(fd, &sb) < 0) {
+               fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+               return false;
+       }
        len = sb.st_size;
        if (len != 0) {
                buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
@@ -722,17 +605,27 @@ static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br,
                        return false;
                }
 
-               count = count_entries(buf, len, me, intype, br);
-               if (count >= allowed)
-                       return false;
+               owner = NULL;
+               for (n=names; n!=NULL; n=n->next) {
+                       count = count_entries(buf, len, n->name, intype, br);
+
+                       if (count >= n->allowed)
+                               continue;
+
+                       owner = n->name;
+                       break;
+               }
        }
 
+       if (owner == NULL)
+               return false;
 
-       get_new_nicname(nicname, br, pid, cnic);
-       /* me  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
-       slen = strlen(me) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
+       if (!get_new_nicname(nicname, br, pid, cnic))
+               return false;
+       /* owner  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
+       slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
        newline = alloca(slen);
-       ret = snprintf(newline, slen, "%s %s %s %s\n", me, intype, br, *nicname);
+       ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, *nicname);
        if (ret < 0 || ret >= slen) {
                if (lxc_netdev_delete_by_name(*nicname) != 0)
                        fprintf(stderr, "Error unlinking %s!\n", *nicname);
@@ -775,69 +668,13 @@ again:
        goto again;
 }
 
-static int lxc_netdev_rename_by_index(int ifindex, const char *newname)
-{
-       struct nl_handler nlh;
-       struct nlmsg *nlmsg = NULL, *answer = NULL;
-       struct link_req *link_req;
-       int len, err;
-
-       err = netlink_open(&nlh, NETLINK_ROUTE);
-       if (err)
-               return err;
-
-       len = strlen(newname);
-       if (len == 1 || len >= IFNAMSIZ)
-               goto out;
-
-       err = -ENOMEM;
-       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!nlmsg)
-               goto out;
-
-       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
-       if (!answer)
-               goto out;
-
-       link_req = (struct link_req *)nlmsg;
-       link_req->ifinfomsg.ifi_family = AF_UNSPEC;
-       link_req->ifinfomsg.ifi_index = ifindex;
-       nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-       nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
-       nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
-
-       if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
-               goto out;
-
-       err = netlink_transaction(&nlh, nlmsg, answer);
-out:
-       netlink_close(&nlh);
-       nlmsg_free(answer);
-       nlmsg_free(nlmsg);
-       return err;
-}
-
-static int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
-{
-       int len, index;
-
-       len = strlen(oldname);
-       if (len == 1 || len >= IFNAMSIZ)
-               return -EINVAL;
-
-       index = if_nametoindex(oldname);
-       if (!index) {
-               fprintf(stderr, "Error getting ifindex for %s\n", oldname);
-               return -EINVAL;
-       }
-
-       return lxc_netdev_rename_by_index(index, newname);
-}
+#define VETH_DEF_NAME "eth%d"
 
-static int rename_in_ns(int pid, char *oldname, char *newname)
+static int rename_in_ns(int pid, char *oldname, char **newnamep)
 {
        char nspath[MAXPATHLEN];
-       int fd = -1, ofd = -1, ret;
+       int fd = -1, ofd = -1, ret, ifindex = -1;
+       bool grab_newname = false;
 
        ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
        if (ret < 0 || ret >= MAXPATHLEN)
@@ -859,10 +696,28 @@ static int rename_in_ns(int pid, char *oldname, char *newname)
                goto out_err;
        }
        close(fd); fd = -1;
-       if ((ret = lxc_netdev_rename_by_name(oldname, newname)) < 0) {
-               fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, newname);
+       if (!*newnamep) {
+               grab_newname = true;
+               *newnamep = VETH_DEF_NAME;
+               if (!(ifindex = if_nametoindex(oldname))) {
+                       fprintf(stderr, "failed to get netdev index\n");
+                       goto out_err;
+               }
+       }
+       if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) {
+               fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep);
                goto out_err;
        }
+       if (grab_newname) {
+               char ifname[IFNAMSIZ], *namep = ifname;
+               if (!if_indextoname(ifindex, namep)) {
+                       fprintf(stderr, "Failed to get new netdev name\n");
+                       goto out_err;
+               }
+               *newnamep = strdup(namep);
+               if (!*newnamep)
+                       goto out_err;
+       }
        if (setns(ofd, 0) < 0) {
                fprintf(stderr, "Error returning to original netns\n");
                close(ofd);
@@ -884,7 +739,7 @@ out_err:
 
 /*
  * If the caller (real uid, not effective uid) may read the
- * /proc/pid/net/ns, then it is either the caller's netns or one
+ * /proc/[pid]/ns/net, then it is either the caller's netns or one
  * which it created.
  */
 static bool may_access_netns(int pid)
@@ -930,9 +785,19 @@ int main(int argc, char *argv[])
        char *me;
        char *nicname = alloca(40);
        char *cnic = NULL; // created nic name in container is returned here.
-       char *vethname;
+       char *vethname = NULL;
        int pid;
+       struct alloted_s *alloted = NULL;
 
+       /* set a sane env, because we are setuid-root */
+       if (clearenv() < 0) {
+               fprintf(stderr, "Failed to clear environment");
+               exit(1);
+       }
+       if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
+               fprintf(stderr, "Failed to set PATH, exiting\n");
+               exit(1);
+       }
        if ((me = get_username()) == NULL) {
                fprintf(stderr, "Failed to get username\n");
                exit(1);
@@ -942,8 +807,6 @@ int main(int argc, char *argv[])
                usage(argv[0], true);
        if (argc >= 5)
                vethname = argv[4];
-       else
-               vethname = "eth0";
 
        errno = 0;
        pid = (int) strtol(argv[1], NULL, 10);
@@ -952,36 +815,40 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       if (!create_db_dir(DB_FILE)) {
+       if (!create_db_dir(LXC_USERNIC_DB)) {
                fprintf(stderr, "Failed to create directory for db file\n");
                exit(1);
        }
 
-       if ((fd = open_and_lock(DB_FILE)) < 0) {
-               fprintf(stderr, "Failed to lock %s\n", DB_FILE);
+       if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
+               fprintf(stderr, "Failed to lock %s\n", LXC_USERNIC_DB);
                exit(1);
        }
 
        if (!may_access_netns(pid)) {
                fprintf(stderr, "User %s may not modify netns for pid %d\n",
-                               me, pid);
+                       me, pid);
                exit(1);
        }
 
-       n = get_alloted(me, argv[2], argv[3]);
+       n = get_alloted(me, argv[2], argv[3], &alloted);
        if (n > 0)
-               gotone = get_nic_if_avail(fd, me, pid, argv[2], argv[3], n, &nicname, &cnic);
+               gotone = get_nic_if_avail(fd, alloted, pid, argv[2], argv[3], n, &nicname, &cnic);
+
        close(fd);
+       free_alloted(&alloted);
        if (!gotone) {
                fprintf(stderr, "Quota reached\n");
                exit(1);
        }
 
        // Now rename the link
-       if (rename_in_ns(pid, cnic, vethname) < 0) {
+       if (rename_in_ns(pid, cnic, &vethname) < 0) {
                fprintf(stderr, "Failed to rename the link\n");
                exit(1);
        }
 
+       // write the name of the interface pair to the stdout - like eth0:veth9MT2L4
+       fprintf(stdout, "%s:%s\n", vethname, nicname);
        exit(0);
 }