]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
Fixed an error
[mirror_lxc.git] / src / lxc / lxc_user_nic.c
1 /*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #define _GNU_SOURCE /* See feature_test_macros(7) */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/file.h>
30 #include <alloca.h>
31 #include <string.h>
32 #include <sched.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <errno.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 #include <sys/ioctl.h>
39 #include <linux/netlink.h>
40 #include <arpa/inet.h>
41 #include <net/if.h>
42 #include <net/if_arp.h>
43 #include <netinet/in.h>
44 #include <linux/if_bridge.h>
45 #include <linux/netlink.h>
46 #include <linux/rtnetlink.h>
47 #include <linux/sockios.h>
48 #include <sys/param.h>
49
50 #include "config.h"
51 #include "utils.h"
52 #include "network.h"
53
54 static void usage(char *me, bool fail)
55 {
56 fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
57 fprintf(stderr, " nicname is the name to use inside the container\n");
58 exit(fail ? 1 : 0);
59 }
60
61 static int open_and_lock(char *path)
62 {
63 int fd;
64 struct flock lk;
65
66 fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
67 if (fd < 0) {
68 fprintf(stderr, "Failed to open %s: %s\n",
69 path, strerror(errno));
70 return(fd);
71 }
72
73 lk.l_type = F_WRLCK;
74 lk.l_whence = SEEK_SET;
75 lk.l_start = 0;
76 lk.l_len = 0;
77 if (fcntl(fd, F_SETLKW, &lk) < 0) {
78 fprintf(stderr, "Failed to lock %s: %s\n",
79 path, strerror(errno));
80 close(fd);
81 return -1;
82 }
83
84 return fd;
85 }
86
87
88 static char *get_username(void)
89 {
90 struct passwd *pwd = getpwuid(getuid());
91
92 if (pwd == NULL) {
93 perror("getpwuid");
94 return NULL;
95 }
96
97 return pwd->pw_name;
98 }
99
100 static char **get_groupnames(void)
101 {
102 int ngroups;
103 gid_t *group_ids;
104 int ret, i, j;
105 char **groupnames;
106 struct group *gr;
107
108 ngroups = getgroups(0, NULL);
109
110 if (ngroups == -1) {
111 fprintf(stderr, "Failed to get number of groups user belongs to\n");
112 return NULL;
113 }
114
115 group_ids = (gid_t *)malloc(sizeof(gid_t)*ngroups);
116 ret = getgroups(ngroups, group_ids);
117
118 if (ret < 0) {
119 free(group_ids);
120 fprintf(stderr, "Failed to get process groups\n");
121 return NULL;
122 }
123
124 groupnames = (char **)malloc(sizeof(char *)*(ngroups+1));
125
126 for (i=0; i<ngroups; i++ ) {
127 gr = getgrgid(group_ids[i]);
128
129 if (gr == NULL) {
130 fprintf(stderr, "Failed to get group name\n");
131 free(group_ids);
132 for (j=0; j<i; j++) {
133 free(groupnames[j]);
134 }
135 free(groupnames);
136 return NULL;
137 }
138
139 groupnames[i] = strdup(gr->gr_name);
140
141 if (groupnames[i] == NULL) {
142 fprintf(stderr, "Failed to copy group name: %s", gr->gr_name);
143 free(group_ids);
144 for (j=0; j<i; j++) {
145 free(groupnames[j]);
146 }
147 free(groupnames);
148 return NULL;
149 }
150 }
151
152 groupnames[ngroups] = NULL;
153
154 free(group_ids);
155
156 return groupnames;
157 }
158
159 static void free_groupnames(char **groupnames)
160 {
161 char **group;
162 for (group=groupnames; group != NULL; group++)
163 free(*group);
164 free(groupnames);
165 }
166
167 static bool name_is_in_groupnames(char *name, char **groupnames)
168 {
169 while (groupnames != NULL) {
170 if (strcmp(name, *groupnames) == 0)
171 return true;
172 groupnames++;
173 }
174 return false;
175 }
176
177 struct alloted_s {
178 char *name;
179 int allowed;
180 struct alloted_s *next;
181 };
182
183 static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n)
184 {
185 struct alloted_s *cur, *al;
186
187 if (head == NULL || name == NULL) {
188 // sanity check. parameters should not be null
189 return NULL;
190 }
191
192 al = (struct alloted_s *)malloc(sizeof(struct alloted_s));
193
194 if (al == NULL) {
195 // unable to allocate memory to new struct
196 return NULL;
197 }
198
199 al->name = strdup(name);
200 al->allowed = n;
201 al->next = NULL;
202
203 if (*head == NULL) {
204 *head = al;
205 return al;
206 }
207
208 cur = *head;
209 while (cur->next != NULL)
210 cur = cur->next;
211
212 cur->next = al;
213 return al;
214 }
215
216 static void free_alloted(struct alloted_s **head)
217 {
218 struct alloted_s *cur;
219
220 if (head == NULL) {
221 return;
222 }
223
224 cur = *head;
225
226 while (cur != NULL) {
227 cur = cur->next;
228 free((*head)->name);
229 free(*head);
230 *head = cur;
231 }
232 }
233
234 /* The configuration file consists of lines of the form:
235 *
236 * user type bridge count
237 * or
238 * @group type bridge count
239 *
240 * Return the count entry for the calling user if there is one. Else
241 * return -1.
242 */
243 static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted)
244 {
245 FILE *fin = fopen(LXC_USERNIC_CONF, "r");
246 char *line = NULL;
247 char name[100], type[100], br[100];
248 size_t len = 0;
249 int n, ret, count = 0;
250 char **groups;
251
252 if (!fin) {
253 fprintf(stderr, "Failed to open %s: %s\n", LXC_USERNIC_CONF,
254 strerror(errno));
255 return -1;
256 }
257
258 groups = get_groupnames();
259 while ((getline(&line, &len, fin)) != -1) {
260 ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
261
262 if (ret != 4)
263 continue;
264
265 if (strlen(name) == 0)
266 continue;
267
268 if (strcmp(name, me) != 0)
269 {
270 if (name[0] != '@')
271 continue;
272 if (!name_is_in_groupnames(name+1, groups))
273 continue;
274 }
275 if (strcmp(type, intype) != 0)
276 continue;
277 if (strcmp(link, br) != 0)
278 continue;
279
280 /* found the user or group with the appropriate settings, therefore finish the search.
281 * what to do if there are more than one applicable lines? not specified in the docs.
282 * since getline is implemented with realloc, we don't need to free line until exiting func.
283 */
284 append_alloted(alloted, name, n);
285 count += n;
286 break;
287 }
288
289 free_groupnames(groups);
290 fclose(fin);
291 free(line);
292 return count;
293 }
294
295 static char *get_eol(char *s, char *e)
296 {
297 while (s<e && *s && *s != '\n')
298 s++;
299 return s;
300 }
301
302 static char *get_eow(char *s, char *e)
303 {
304 while (s<e && *s && !isblank(*s) && *s != '\n')
305 s++;
306 return s;
307 }
308
309 static char *find_line(char *p, char *e, char *u, char *t, char *l)
310 {
311 char *p1, *p2, *ret;
312
313 while (p<e && (p1 = get_eol(p, e)) < e) {
314 ret = p;
315 if (*p == '#')
316 goto next;
317 while (p<e && isblank(*p)) p++;
318 p2 = get_eow(p, e);
319 if (!p2 || p2-p != strlen(u) || strncmp(p, u, strlen(u)) != 0)
320 goto next;
321 p = p2+1;
322 while (p<e && isblank(*p)) p++;
323 p2 = get_eow(p, e);
324 if (!p2 || p2-p != strlen(t) || strncmp(p, t, strlen(t)) != 0)
325 goto next;
326 p = p2+1;
327 while (p<e && isblank(*p)) p++;
328 p2 = get_eow(p, e);
329 if (!p2 || p2-p != strlen(l) || strncmp(p, l, strlen(l)) != 0)
330 goto next;
331 return ret;
332 next:
333 p = p1 + 1;
334 }
335
336 return NULL;
337 }
338
339 static bool nic_exists(char *nic)
340 {
341 char path[MAXPATHLEN];
342 int ret;
343 struct stat sb;
344
345 if (strcmp(nic, "none") == 0)
346 return true;
347 ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
348 if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
349 return false;
350 ret = stat(path, &sb);
351 if (ret != 0)
352 return false;
353 return true;
354 }
355
356 static int instantiate_veth(char *n1, char **n2)
357 {
358 int err;
359
360 err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
361 if (err < 0 || err >= IFNAMSIZ) {
362 fprintf(stderr, "nic name too long\n");
363 return -1;
364 }
365
366 err = lxc_veth_create(n1, *n2);
367 if (err) {
368 fprintf(stderr, "failed to create %s-%s : %s\n", n1, *n2,
369 strerror(-err));
370 return -1;
371 }
372
373 /* changing the high byte of the mac address to 0xfe, the bridge interface
374 * will always keep the host's mac address and not take the mac address
375 * of a container */
376 err = setup_private_host_hw_addr(n1);
377 if (err) {
378 fprintf(stderr, "failed to change mac address of host interface '%s' : %s\n",
379 n1, strerror(-err));
380 }
381
382 return netdev_set_flag(n1, IFF_UP);
383 }
384
385 static int get_mtu(char *name)
386 {
387 int idx = if_nametoindex(name);
388 return netdev_get_mtu(idx);
389 }
390
391 static bool create_nic(char *nic, char *br, int pid, char **cnic)
392 {
393 char *veth1buf, *veth2buf;
394 veth1buf = alloca(IFNAMSIZ);
395 veth2buf = alloca(IFNAMSIZ);
396 int ret, mtu;
397
398 ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
399 if (ret < 0 || ret >= IFNAMSIZ) {
400 fprintf(stderr, "host nic name too long\n");
401 return false;
402 }
403
404 /* create the nics */
405 if (instantiate_veth(veth1buf, &veth2buf) < 0) {
406 fprintf(stderr, "Error creating veth tunnel\n");
407 return false;
408 }
409
410 if (strcmp(br, "none") != 0) {
411 /* copy the bridge's mtu to both ends */
412 mtu = get_mtu(br);
413 if (mtu != -1) {
414 if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
415 lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
416 fprintf(stderr, "Failed setting mtu\n");
417 goto out_del;
418 }
419 }
420
421 /* attach veth1 to bridge */
422 if (lxc_bridge_attach(br, veth1buf) < 0) {
423 fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
424 goto out_del;
425 }
426 }
427
428 /* pass veth2 to target netns */
429 ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
430 if (ret < 0) {
431 fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
432 goto out_del;
433 }
434 *cnic = strdup(veth2buf);
435 return true;
436
437 out_del:
438 lxc_netdev_delete_by_name(veth1buf);
439 return false;
440 }
441
442 /*
443 * Get a new nic.
444 * *dest will container the name (vethXXXXXX) which is attached
445 * on the host to the lxc bridge
446 */
447 static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
448 {
449 char template[IFNAMSIZ];
450 snprintf(template, sizeof(template), "vethXXXXXX");
451 *dest = lxc_mkifname(template);
452
453 if (!create_nic(*dest, br, pid, cnic)) {
454 return false;
455 }
456 return true;
457 }
458
459 static bool get_nic_from_line(char *p, char **nic)
460 {
461 char user[100], type[100], br[100];
462 int ret;
463
464 ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
465 if (ret != 4)
466 return false;
467 return true;
468 }
469
470 struct entry_line {
471 char *start;
472 int len;
473 bool keep;
474 };
475
476 static bool cull_entries(int fd, char *me, char *t, char *br)
477 {
478 struct stat sb;
479 char *buf, *p, *e, *nic;
480 off_t len;
481 struct entry_line *entry_lines = NULL;
482 int i, n = 0;
483
484 nic = alloca(100);
485
486 if (fstat(fd, &sb) < 0) {
487 fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
488 return false;
489 }
490 len = sb.st_size;
491 if (len == 0)
492 return true;
493 buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
494 if (buf == MAP_FAILED) {
495 fprintf(stderr, "Failed to create mapping: %s\n", strerror(errno));
496 return false;
497 }
498
499 p = buf;
500 e = buf + len;
501 while ((p = find_line(p, e, me, t, br)) != NULL) {
502 struct entry_line *newe = realloc(entry_lines, sizeof(*entry_lines)*(n+1));
503 if (!newe) {
504 free(entry_lines);
505 return false;
506 }
507 entry_lines = newe;
508 entry_lines[n].start = p;
509 entry_lines[n].len = get_eol(p, e) - entry_lines[n].start;
510 entry_lines[n].keep = true;
511 n++;
512 if (!get_nic_from_line(p, &nic))
513 continue;
514 if (nic && !nic_exists(nic))
515 entry_lines[n-1].keep = false;
516 p += entry_lines[n-1].len + 1;
517 if (p >= e)
518 break;
519 }
520 p = buf;
521 for (i=0; i<n; i++) {
522 if (!entry_lines[i].keep)
523 continue;
524 memcpy(p, entry_lines[i].start, entry_lines[i].len);
525 p += entry_lines[i].len;
526 *p = '\n';
527 p++;
528 }
529 free(entry_lines);
530 munmap(buf, sb.st_size);
531 if (ftruncate(fd, p-buf))
532 fprintf(stderr, "Failed to set new file size\n");
533 return true;
534 }
535
536 static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
537 {
538 char *e = &buf[len];
539 int count = 0;
540 while ((buf = find_line(buf, e, me, t, br)) != NULL) {
541 count++;
542 buf = get_eol(buf, e)+1;
543 if (buf >= e)
544 break;
545 }
546
547 return count;
548 }
549
550 /*
551 * The dbfile has lines of the format:
552 * user type bridge nicname
553 */
554 static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
555 {
556 off_t len, slen;
557 struct stat sb;
558 char *buf = NULL, *newline;
559 int ret, count = 0;
560 char *owner;
561 struct alloted_s *n;
562
563 for (n=names; n!=NULL; n=n->next)
564 cull_entries(fd, n->name, intype, br);
565
566 if (allowed == 0)
567 return false;
568
569 owner = names->name;
570
571 if (fstat(fd, &sb) < 0) {
572 fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
573 return false;
574 }
575 len = sb.st_size;
576 if (len != 0) {
577 buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
578 if (buf == MAP_FAILED) {
579 fprintf(stderr, "Failed to create mapping\n");
580 return false;
581 }
582
583 owner = NULL;
584 for (n=names; n!=NULL; n=n->next) {
585 count = count_entries(buf, len, n->name, intype, br);
586
587 if (count >= n->allowed)
588 continue;
589
590 owner = n->name;
591 break;
592 }
593 }
594
595 if (owner == NULL)
596 return false;
597
598 if (!get_new_nicname(nicname, br, pid, cnic))
599 return false;
600 /* owner ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
601 slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
602 newline = alloca(slen);
603 ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, *nicname);
604 if (ret < 0 || ret >= slen) {
605 if (lxc_netdev_delete_by_name(*nicname) != 0)
606 fprintf(stderr, "Error unlinking %s!\n", *nicname);
607 return false;
608 }
609 if (len)
610 munmap(buf, len);
611 if (ftruncate(fd, len + slen))
612 fprintf(stderr, "Failed to set new file size\n");
613 buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
614 if (buf == MAP_FAILED) {
615 fprintf(stderr, "Failed to create mapping after extending: %s\n", strerror(errno));
616 if (lxc_netdev_delete_by_name(*nicname) != 0)
617 fprintf(stderr, "Error unlinking %s!\n", *nicname);
618 return false;
619 }
620 strcpy(buf+len, newline);
621 munmap(buf, len+slen);
622 return true;
623 }
624
625 static bool create_db_dir(char *fnam)
626 {
627 char *p = alloca(strlen(fnam)+1);
628
629 strcpy(p, fnam);
630 fnam = p;
631 p = p + 1;
632 again:
633 while (*p && *p != '/') p++;
634 if (!*p)
635 return true;
636 *p = '\0';
637 if (mkdir(fnam, 0755) && errno != EEXIST) {
638 fprintf(stderr, "failed to create %s\n", fnam);
639 *p = '/';
640 return false;
641 }
642 *(p++) = '/';
643 goto again;
644 }
645
646 #define VETH_DEF_NAME "eth%d"
647
648 static int rename_in_ns(int pid, char *oldname, char **newnamep)
649 {
650 char nspath[MAXPATHLEN];
651 int fd = -1, ofd = -1, ret, ifindex = -1;
652 bool grab_newname = false;
653
654 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
655 if (ret < 0 || ret >= MAXPATHLEN)
656 return -1;
657 if ((ofd = open(nspath, O_RDONLY)) < 0) {
658 fprintf(stderr, "Opening %s\n", nspath);
659 return -1;
660 }
661 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid);
662 if (ret < 0 || ret >= MAXPATHLEN)
663 goto out_err;
664
665 if ((fd = open(nspath, O_RDONLY)) < 0) {
666 fprintf(stderr, "Opening %s\n", nspath);
667 goto out_err;
668 }
669 if (setns(fd, 0) < 0) {
670 fprintf(stderr, "setns to container network namespace\n");
671 goto out_err;
672 }
673 close(fd); fd = -1;
674 if (!*newnamep) {
675 grab_newname = true;
676 *newnamep = VETH_DEF_NAME;
677 if (!(ifindex = if_nametoindex(oldname))) {
678 fprintf(stderr, "failed to get netdev index\n");
679 goto out_err;
680 }
681 }
682 if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) {
683 fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep);
684 goto out_err;
685 }
686 if (grab_newname) {
687 char ifname[IFNAMSIZ], *namep = ifname;
688 if (!if_indextoname(ifindex, namep)) {
689 fprintf(stderr, "Failed to get new netdev name\n");
690 goto out_err;
691 }
692 *newnamep = strdup(namep);
693 if (!*newnamep)
694 goto out_err;
695 }
696 if (setns(ofd, 0) < 0) {
697 fprintf(stderr, "Error returning to original netns\n");
698 close(ofd);
699 return -1;
700 }
701 close(ofd);
702
703 return 0;
704
705 out_err:
706 if (ofd >= 0)
707 close(ofd);
708 if (setns(ofd, 0) < 0)
709 fprintf(stderr, "Error returning to original network namespace\n");
710 if (fd >= 0)
711 close(fd);
712 return -1;
713 }
714
715 /*
716 * If the caller (real uid, not effective uid) may read the
717 * /proc/[pid]/ns/net, then it is either the caller's netns or one
718 * which it created.
719 */
720 static bool may_access_netns(int pid)
721 {
722 int ret;
723 char s[200];
724 uid_t ruid, suid, euid;
725 bool may_access = false;
726
727 ret = getresuid(&ruid, &euid, &suid);
728 if (ret) {
729 fprintf(stderr, "Failed to get my uids: %s\n", strerror(errno));
730 return false;
731 }
732 ret = setresuid(ruid, ruid, euid);
733 if (ret) {
734 fprintf(stderr, "Failed to set temp uids to (%d,%d,%d): %s\n",
735 (int)ruid, (int)ruid, (int)euid, strerror(errno));
736 return false;
737 }
738 ret = snprintf(s, 200, "/proc/%d/ns/net", pid);
739 if (ret < 0 || ret >= 200) // can't happen
740 return false;
741 ret = access(s, R_OK);
742 if (ret) {
743 fprintf(stderr, "Uid %d may not access %s: %s\n",
744 (int)ruid, s, strerror(errno));
745 }
746 may_access = ret == 0;
747 ret = setresuid(ruid, euid, suid);
748 if (ret) {
749 fprintf(stderr, "Failed to restore uids to (%d,%d,%d): %s\n",
750 (int)ruid, (int)euid, (int)suid, strerror(errno));
751 may_access = false;
752 }
753 return may_access;
754 }
755
756 int main(int argc, char *argv[])
757 {
758 int n, fd;
759 bool gotone = false;
760 char *me;
761 char *nicname = alloca(40);
762 char *cnic = NULL; // created nic name in container is returned here.
763 char *vethname = NULL;
764 int pid;
765 struct alloted_s *alloted = NULL;
766
767 /* set a sane env, because we are setuid-root */
768 if (clearenv() < 0) {
769 fprintf(stderr, "Failed to clear environment");
770 exit(1);
771 }
772 if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
773 fprintf(stderr, "Failed to set PATH, exiting\n");
774 exit(1);
775 }
776 if ((me = get_username()) == NULL) {
777 fprintf(stderr, "Failed to get username\n");
778 exit(1);
779 }
780
781 if (argc < 4)
782 usage(argv[0], true);
783 if (argc >= 5)
784 vethname = argv[4];
785
786 errno = 0;
787 pid = (int) strtol(argv[1], NULL, 10);
788 if (errno) {
789 fprintf(stderr, "Could not read pid: %s\n", argv[1]);
790 exit(1);
791 }
792
793 if (!create_db_dir(LXC_USERNIC_DB)) {
794 fprintf(stderr, "Failed to create directory for db file\n");
795 exit(1);
796 }
797
798 if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
799 fprintf(stderr, "Failed to lock %s\n", LXC_USERNIC_DB);
800 exit(1);
801 }
802
803 if (!may_access_netns(pid)) {
804 fprintf(stderr, "User %s may not modify netns for pid %d\n",
805 me, pid);
806 exit(1);
807 }
808
809 n = get_alloted(me, argv[2], argv[3], &alloted);
810 if (n > 0)
811 gotone = get_nic_if_avail(fd, alloted, pid, argv[2], argv[3], n, &nicname, &cnic);
812
813 close(fd);
814 free_alloted(&alloted);
815 if (!gotone) {
816 fprintf(stderr, "Quota reached\n");
817 exit(1);
818 }
819
820 // Now rename the link
821 if (rename_in_ns(pid, cnic, &vethname) < 0) {
822 fprintf(stderr, "Failed to rename the link\n");
823 exit(1);
824 }
825
826 // write the name of the interface pair to the stdout - like eth0:veth9MT2L4
827 fprintf(stdout, "%s:%s\n", vethname, nicname);
828 exit(0);
829 }