]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cmd/lxc_user_nic.c
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
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.
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.
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.
24 #include <arpa/inet.h>
29 #include <linux/netlink.h>
30 #include <linux/rtnetlink.h>
31 #include <linux/sockios.h>
33 #include <net/if_arp.h>
34 #include <netinet/in.h>
42 #include <sys/ioctl.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
47 #include <sys/types.h>
54 #include "raw_syscalls.h"
55 #include "syscall_wrappers.h"
59 #include "include/strlcpy.h"
62 #define usernic_debug_stream(stream, format, ...) \
64 fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
65 __func__, __VA_ARGS__); \
68 #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
70 static void usage(char *me
, bool fail
)
72 fprintf(stderr
, "Usage: %s create {lxcpath} {name} {pid} {type} "
73 "{bridge} {nicname}\n", me
);
74 fprintf(stderr
, "Usage: %s delete {lxcpath} {name} "
75 "{/proc/<pid>/ns/net} {type} {bridge} {nicname}\n", me
);
76 fprintf(stderr
, "{nicname} is the name to use inside the container\n");
84 static int open_and_lock(char *path
)
89 fd
= open(path
, O_RDWR
| O_CREAT
, S_IWUSR
| S_IRUSR
);
91 CMD_SYSERROR("Failed to open \"%s\"\n", path
);
96 lk
.l_whence
= SEEK_SET
;
100 ret
= fcntl(fd
, F_SETLKW
, &lk
);
102 CMD_SYSERROR("Failed to lock \"%s\"\n", path
);
110 static char *get_username(void)
113 struct passwd
*pwentp
= NULL
;
119 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
123 buf
= malloc(bufsize
);
127 ret
= getpwuid_r(getuid(), &pwent
, buf
, bufsize
, &pwentp
);
130 usernic_error("%s", "Could not find matched password record\n");
132 CMD_SYSERROR("Failed to get username: %u\n", getuid());
137 username
= strdup(pwent
.pw_name
);
143 static void free_groupnames(char **groupnames
)
150 for (i
= 0; groupnames
[i
]; i
++)
156 static char **get_groupnames(void)
163 struct group
*grentp
= NULL
;
167 ngroups
= getgroups(0, NULL
);
169 CMD_SYSERROR("Failed to get number of groups the user belongs to\n");
171 } else if (ngroups
== 0) {
175 group_ids
= malloc(sizeof(gid_t
) * ngroups
);
177 CMD_SYSERROR("Failed to allocate memory while getting groups the user belongs to\n");
181 ret
= getgroups(ngroups
, group_ids
);
184 CMD_SYSERROR("Failed to get process groups\n");
188 groupnames
= malloc(sizeof(char *) * (ngroups
+ 1));
191 CMD_SYSERROR("Failed to allocate memory while getting group names\n");
195 memset(groupnames
, 0, sizeof(char *) * (ngroups
+ 1));
197 bufsize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
201 buf
= malloc(bufsize
);
204 free_groupnames(groupnames
);
205 CMD_SYSERROR("Failed to allocate memory while getting group names\n");
209 for (i
= 0; i
< ngroups
; i
++) {
210 ret
= getgrgid_r(group_ids
[i
], &grent
, buf
, bufsize
, &grentp
);
213 usernic_error("%s", "Could not find matched group record\n");
215 CMD_SYSERROR("Failed to get group name: %u\n", group_ids
[i
]);
218 free_groupnames(groupnames
);
222 groupnames
[i
] = strdup(grent
.gr_name
);
223 if (!groupnames
[i
]) {
224 usernic_error("Failed to copy group name \"%s\"", grent
.gr_name
);
227 free_groupnames(groupnames
);
238 static bool name_is_in_groupnames(char *name
, char **groupnames
)
241 if (!strcmp(name
, *groupnames
))
252 struct alloted_s
*next
;
255 static struct alloted_s
*append_alloted(struct alloted_s
**head
, char *name
,
258 struct alloted_s
*cur
, *al
;
260 if (!head
|| !name
) {
261 /* Sanity check. Parameters should not be null. */
262 usernic_error("%s\n", "Unexpected NULL argument");
266 al
= malloc(sizeof(struct alloted_s
));
268 CMD_SYSERROR("Failed to allocate memory\n");
272 al
->name
= strdup(name
);
294 static void free_alloted(struct alloted_s
**head
)
296 struct alloted_s
*cur
;
310 /* The configuration file consists of lines of the form:
312 * user type bridge count
314 * @group type bridge count
316 * Return the count entry for the calling user if there is one. Else
319 static int get_alloted(char *me
, char *intype
, char *link
,
320 struct alloted_s
**alloted
)
323 char name
[100], type
[100], br
[100];
330 fin
= fopen(LXC_USERNIC_CONF
, "r");
332 CMD_SYSERROR("Failed to open \"%s\"\n", LXC_USERNIC_CONF
);
336 groups
= get_groupnames();
337 while ((getline(&line
, &len
, fin
)) != -1) {
338 ret
= sscanf(line
, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name
,
343 if (strlen(name
) == 0)
346 if (strcmp(name
, me
)) {
350 if (!name_is_in_groupnames(name
+ 1, groups
))
354 if (strcmp(type
, intype
))
357 if (strcmp(link
, br
))
360 /* Found the user or group with the appropriate settings,
361 * therefore finish the search. What to do if there are more
362 * than one applicable lines? not specified in the docs. Since
363 * getline is implemented with realloc, we don't need to free
364 * line until exiting func.
366 * If append_alloted returns NULL, e.g. due to a malloc error,
367 * we set count to 0 and break the loop, allowing cleanup and
368 * then exiting from main().
370 if (!append_alloted(alloted
, name
, n
)) {
378 free_groupnames(groups
);
382 /* Now return the total number of nics that this user can create. */
386 static char *get_eol(char *s
, char *e
)
388 while ((s
< e
) && *s
&& (*s
!= '\n'))
394 static char *get_eow(char *s
, char *e
)
396 while ((s
< e
) && *s
&& !isblank(*s
) && (*s
!= '\n'))
402 static char *find_line(char *buf_start
, char *buf_end
, char *name
,
403 char *net_type
, char *net_link
, char *net_dev
,
404 bool *owner
, bool *found
, bool *keep
)
406 char *end_of_line
, *end_of_word
, *line
;
408 while (buf_start
< buf_end
) {
410 char netdev_name
[IFNAMSIZ
];
416 end_of_line
= get_eol(buf_start
, buf_end
);
417 if (end_of_line
>= buf_end
)
421 if (*buf_start
== '#')
424 while ((buf_start
< buf_end
) && isblank(*buf_start
))
427 /* Check whether the line contains the caller's name. */
428 end_of_word
= get_eow(buf_start
, buf_end
);
433 if (strncmp(buf_start
, name
, strlen(name
)))
438 buf_start
= end_of_word
+ 1;
439 while ((buf_start
< buf_end
) && isblank(*buf_start
))
442 /* Check whether line is of the right network type. */
443 end_of_word
= get_eow(buf_start
, buf_end
);
448 if (strncmp(buf_start
, net_type
, strlen(net_type
)))
451 buf_start
= end_of_word
+ 1;
452 while ((buf_start
< buf_end
) && isblank(*buf_start
))
455 /* Check whether line is contains the right link. */
456 end_of_word
= get_eow(buf_start
, buf_end
);
461 if (strncmp(buf_start
, net_link
, strlen(net_link
)))
464 buf_start
= end_of_word
+ 1;
465 while ((buf_start
< buf_end
) && isblank(*buf_start
))
468 /* Check whether line contains the right network device. */
469 end_of_word
= get_eow(buf_start
, buf_end
);
474 len
= end_of_word
- buf_start
;
479 memcpy(netdev_name
, buf_start
, len
);
480 netdev_name
[len
] = '\0';
481 *keep
= lxc_nic_exists(netdev_name
);
483 if (net_dev
&& !strcmp(netdev_name
, net_dev
))
489 buf_start
= end_of_line
+ 1;
495 static int instantiate_veth(char *veth1
, char *veth2
)
499 ret
= lxc_veth_create(veth1
, veth2
);
502 CMD_SYSERROR("Failed to create %s-%s\n", veth1
, veth2
);
506 /* Changing the high byte of the mac address to 0xfe, the bridge
507 * interface will always keep the host's mac address and not take the
508 * mac address of a container.
510 ret
= setup_private_host_hw_addr(veth1
);
513 CMD_SYSERROR("Failed to change mac address of host interface %s\n", veth1
);
516 return netdev_set_flag(veth1
, IFF_UP
);
519 static int get_mtu(char *name
)
523 idx
= if_nametoindex(name
);
527 return netdev_get_mtu(idx
);
530 static int create_nic(char *nic
, char *br
, int pid
, char **cnic
)
532 char veth1buf
[IFNAMSIZ
], veth2buf
[IFNAMSIZ
];
535 ret
= snprintf(veth1buf
, IFNAMSIZ
, "%s", nic
);
536 if (ret
< 0 || ret
>= IFNAMSIZ
) {
537 usernic_error("%s", "Could not create nic name\n");
541 ret
= snprintf(veth2buf
, IFNAMSIZ
, "%sp", veth1buf
);
542 if (ret
< 0 || ret
>= IFNAMSIZ
) {
543 usernic_error("%s\n", "Could not create nic name");
547 /* create the nics */
548 ret
= instantiate_veth(veth1buf
, veth2buf
);
550 usernic_error("%s", "Error creating veth tunnel\n");
554 if (strcmp(br
, "none")) {
555 /* copy the bridge's mtu to both ends */
558 ret
= lxc_netdev_set_mtu(veth1buf
, mtu
);
560 usernic_error("Failed to set mtu to %d on %s\n",
565 ret
= lxc_netdev_set_mtu(veth2buf
, mtu
);
567 usernic_error("Failed to set mtu to %d on %s\n",
573 /* attach veth1 to bridge */
574 ret
= lxc_bridge_attach(br
, veth1buf
);
576 usernic_error("Error attaching %s to %s\n", veth1buf
, br
);
581 /* pass veth2 to target netns */
582 ret
= lxc_netdev_move_by_name(veth2buf
, pid
, NULL
);
584 usernic_error("Error moving %s to network namespace of %d\n",
589 *cnic
= strdup(veth2buf
);
591 usernic_error("Failed to copy string \"%s\"\n", veth2buf
);
598 lxc_netdev_delete_by_name(veth1buf
);
608 static bool cull_entries(int fd
, char *name
, char *net_type
, char *net_link
,
609 char *net_dev
, bool *found_nicname
)
612 char *buf
, *buf_end
, *buf_start
;
616 struct entry_line
*entry_lines
= NULL
;
618 ret
= fstat(fd
, &sb
);
620 CMD_SYSERROR("Failed to fstat\n");
627 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
628 if (buf
== MAP_FAILED
) {
629 CMD_SYSERROR("Failed to establish shared memory mapping\n");
634 buf_end
= buf
+ sb
.st_size
;
635 while ((buf_start
= find_line(buf_start
, buf_end
, name
, net_type
,
636 net_link
, net_dev
, &(bool){true}, &found
,
638 struct entry_line
*newe
;
640 newe
= realloc(entry_lines
, sizeof(*entry_lines
) * (n
+ 1));
643 lxc_strmunmap(buf
, sb
.st_size
);
648 *found_nicname
= true;
651 entry_lines
[n
].start
= buf_start
;
652 entry_lines
[n
].len
= get_eol(buf_start
, buf_end
) - entry_lines
[n
].start
;
653 entry_lines
[n
].keep
= keep
;
656 buf_start
+= entry_lines
[n
- 1].len
+ 1;
657 if (buf_start
>= buf_end
)
663 for (i
= 0; i
< n
; i
++) {
664 if (!entry_lines
[i
].keep
)
667 memcpy(buf_start
, entry_lines
[i
].start
, entry_lines
[i
].len
);
668 buf_start
+= entry_lines
[i
].len
;
675 ret
= ftruncate(fd
, buf_start
- buf
);
676 lxc_strmunmap(buf
, sb
.st_size
);
678 CMD_SYSERROR("Failed to set new file size\n");
683 static int count_entries(char *buf
, off_t len
, char *name
, char *net_type
, char *net_link
)
690 while ((buf
= find_line(buf
, buf_end
, name
, net_type
, net_link
, NULL
,
691 &owner
, &(bool){true}, &(bool){true}))) {
695 buf
= get_eol(buf
, buf_end
) + 1;
703 /* The dbfile has lines of the format: user type bridge nicname. */
704 static char *get_nic_if_avail(int fd
, struct alloted_s
*names
, int pid
,
705 char *intype
, char *br
, int allowed
, char **cnic
)
709 char *newline
, *owner
;
710 char nicname
[IFNAMSIZ
];
715 for (n
= names
; n
!= NULL
; n
= n
->next
)
716 cull_entries(fd
, n
->name
, intype
, br
, NULL
, NULL
);
723 ret
= fstat(fd
, &sb
);
725 CMD_SYSERROR("Failed to fstat\n");
729 if (sb
.st_size
> 0) {
730 buf
= lxc_strmmap(NULL
, sb
.st_size
, PROT_READ
| PROT_WRITE
,
732 if (buf
== MAP_FAILED
) {
733 CMD_SYSERROR("Failed to establish shared memory mapping\n");
739 for (n
= names
; n
!= NULL
; n
= n
->next
) {
742 count
= count_entries(buf
, sb
.st_size
, n
->name
, intype
, br
);
743 if (count
>= n
->allowed
)
750 lxc_strmunmap(buf
, sb
.st_size
);
756 ret
= snprintf(nicname
, sizeof(nicname
), "vethXXXXXX");
757 if (ret
< 0 || (size_t)ret
>= sizeof(nicname
))
760 if (!lxc_mkifname(nicname
))
763 ret
= create_nic(nicname
, br
, pid
, cnic
);
765 usernic_error("%s", "Failed to create new nic\n");
787 slen
= strlen(owner
) + strlen(intype
) + strlen(br
) + strlen(nicname
) + 4;
788 newline
= malloc(slen
+ 1);
791 CMD_SYSERROR("Failed allocate memory\n");
795 ret
= snprintf(newline
, slen
+ 1, "%s %s %s %s\n", owner
, intype
, br
, nicname
);
796 if (ret
< 0 || (size_t)ret
>= (slen
+ 1)) {
797 if (lxc_netdev_delete_by_name(nicname
) != 0)
798 usernic_error("Error unlinking %s\n", nicname
);
804 /* Note that the file needs to be truncated to the size **without** the
805 * \0 byte! Files are not \0-terminated!
807 ret
= ftruncate(fd
, sb
.st_size
+ slen
);
809 CMD_SYSERROR("Failed to truncate file\n");
811 buf
= lxc_strmmap(NULL
, sb
.st_size
+ slen
, PROT_READ
| PROT_WRITE
,
813 if (buf
== MAP_FAILED
) {
814 CMD_SYSERROR("Failed to establish shared memory mapping\n");
816 if (lxc_netdev_delete_by_name(nicname
) != 0)
817 usernic_error("Error unlinking %s\n", nicname
);
823 /* Note that the memory needs to be moved in the buffer **without** the
824 * \0 byte! Files are not \0-terminated!
826 memmove(buf
+ sb
.st_size
, newline
, slen
);
828 lxc_strmunmap(buf
, sb
.st_size
+ slen
);
830 return strdup(nicname
);
833 static bool create_db_dir(char *fnam
)
841 (void)strlcpy(p
, fnam
, len
+ 1);
846 while (*p
&& *p
!= '/')
854 ret
= mkdir(fnam
, 0755);
855 if (ret
< 0 && errno
!= EEXIST
) {
856 CMD_SYSERROR("Failed to create %s\n", fnam
);
866 static char *lxc_secure_rename_in_ns(int pid
, char *oldname
, char *newname
,
867 int *container_veth_ifidx
)
871 uid_t ruid
, suid
, euid
;
872 char ifname
[IFNAMSIZ
];
873 char *string_ret
= NULL
, *name
= NULL
;
874 int fd
= -1, ifindex
= -1;
876 pid_self
= lxc_raw_getpid();
878 ofd
= lxc_preserve_ns(pid_self
, "net");
880 usernic_error("Failed opening network namespace path for %d", pid_self
);
884 fd
= lxc_preserve_ns(pid
, "net");
886 usernic_error("Failed opening network namespace path for %d", pid
);
887 goto do_partial_cleanup
;
890 ret
= getresuid(&ruid
, &euid
, &suid
);
892 CMD_SYSERROR("Failed to retrieve real, effective, and saved user IDs\n");
893 goto do_partial_cleanup
;
896 ret
= setns(fd
, CLONE_NEWNET
);
900 CMD_SYSERROR("Failed to setns() to the network namespace of "
901 "the container with PID %d\n", pid
);
902 goto do_partial_cleanup
;
905 ret
= setresuid(ruid
, ruid
, 0);
907 CMD_SYSERROR("Failed to drop privilege by setting effective "
908 "user id and real user id to %d, and saved user "
910 /* It's ok to jump to do_full_cleanup here since setresuid()
911 * will succeed when trying to set real, effective, and saved to
912 * values they currently have.
914 goto do_full_cleanup
;
917 /* Check if old interface exists. */
918 ifindex
= if_nametoindex(oldname
);
920 CMD_SYSERROR("Failed to get netdev index\n");
921 goto do_full_cleanup
;
924 /* When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
925 * netlink will replace the format specifier with an appropriate index.
926 * So we pass "eth%d".
933 ret
= lxc_netdev_rename_by_name(oldname
, name
);
936 usernic_error("Error %d renaming netdev %s to %s in container\n",
937 ret
, oldname
, newname
? newname
: "eth%d");
938 goto do_full_cleanup
;
941 /* Retrieve new name for interface. */
942 if (!if_indextoname(ifindex
, ifname
)) {
943 CMD_SYSERROR("Failed to get new netdev name\n");
944 goto do_full_cleanup
;
947 /* Allocation failure for strdup() is checked below. */
948 name
= strdup(ifname
);
950 *container_veth_ifidx
= ifindex
;
953 ret
= setresuid(ruid
, euid
, suid
);
955 CMD_SYSERROR("Failed to restore privilege by setting "
956 "effective user id to %d, real user id to %d, "
957 "and saved user ID to %d\n", ruid
, euid
, suid
);
962 ret
= setns(ofd
, CLONE_NEWNET
);
964 CMD_SYSERROR("Failed to setns() to original network namespace "
974 if (!string_ret
&& name
)
982 /* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
983 * then it is either the caller's netns or one which it created.
985 static bool may_access_netns(int pid
)
989 uid_t ruid
, suid
, euid
;
990 bool may_access
= false;
992 ret
= getresuid(&ruid
, &euid
, &suid
);
994 CMD_SYSERROR("Failed to retrieve real, effective, and saved user IDs\n");
998 ret
= setresuid(ruid
, ruid
, euid
);
1000 CMD_SYSERROR("Failed to drop privilege by setting effective "
1001 "user id and real user id to %d, and saved user "
1002 "ID to %d\n", ruid
, euid
);
1006 ret
= snprintf(s
, 200, "/proc/%d/ns/net", pid
);
1007 if (ret
< 0 || ret
>= 200)
1010 ret
= access(s
, R_OK
);
1014 CMD_SYSERROR("Uid %d may not access %s\n", (int)ruid
, s
);
1017 ret
= setresuid(ruid
, euid
, suid
);
1019 CMD_SYSERROR("Failed to restore user id to %d, real user id "
1020 "to %d, and saved user ID to %d\n", ruid
, euid
, suid
);
1027 struct user_nic_args
{
1037 #define LXC_USERNIC_CREATE 0
1038 #define LXC_USERNIC_DELETE 1
1040 static bool is_privileged_over_netns(int netns_fd
)
1044 uid_t euid
, ruid
, suid
;
1047 pid_self
= lxc_raw_getpid();
1049 ofd
= lxc_preserve_ns(pid_self
, "net");
1051 usernic_error("Failed opening network namespace path for %d", pid_self
);
1055 ret
= getresuid(&ruid
, &euid
, &suid
);
1057 CMD_SYSERROR("Failed to retrieve real, effective, and saved user IDs\n");
1058 goto do_partial_cleanup
;
1061 ret
= setns(netns_fd
, CLONE_NEWNET
);
1063 CMD_SYSERROR("Failed to setns() to network namespace\n");
1064 goto do_partial_cleanup
;
1067 ret
= setresuid(ruid
, ruid
, 0);
1069 CMD_SYSERROR("Failed to drop privilege by setting effective "
1070 "user id and real user id to %d, and saved user "
1072 /* It's ok to jump to do_full_cleanup here since setresuid()
1073 * will succeed when trying to set real, effective, and saved to
1074 * values they currently have.
1076 goto do_full_cleanup
;
1079 /* Test whether we are privileged over the network namespace. To do this
1080 * we try to delete the loopback interface which is not possible. If we
1081 * are privileged over the network namespace we will get ENOTSUP. If we
1082 * are not privileged over the network namespace we will get EPERM.
1084 ret
= lxc_netdev_delete_by_name("lo");
1085 if (ret
== -ENOTSUP
)
1089 ret
= setresuid(ruid
, euid
, suid
);
1091 CMD_SYSERROR("Failed to restore privilege by setting "
1092 "effective user id to %d, real user id to %d, "
1093 "and saved user ID to %d\n", ruid
, euid
, suid
);
1097 ret
= setns(ofd
, CLONE_NEWNET
);
1099 CMD_SYSERROR("Failed to setns() to original network namespace "
1100 "of PID %d\n", ofd
);
1109 int main(int argc
, char *argv
[])
1111 int fd
, n
, pid
, request
, ret
;
1113 struct user_nic_args args
;
1114 int container_veth_ifidx
= -1, host_veth_ifidx
= -1, netns_fd
= -1;
1115 char *cnic
= NULL
, *nicname
= NULL
;
1116 struct alloted_s
*alloted
= NULL
;
1118 if (argc
< 7 || argc
> 8) {
1119 usage(argv
[0], true);
1120 _exit(EXIT_FAILURE
);
1123 memset(&args
, 0, sizeof(struct user_nic_args
));
1126 args
.lxc_path
= argv
[2];
1127 args
.lxc_name
= argv
[3];
1129 args
.type
= argv
[5];
1130 args
.link
= argv
[6];
1132 args
.veth_name
= argv
[7];
1134 if (!strcmp(args
.cmd
, "create")) {
1135 request
= LXC_USERNIC_CREATE
;
1136 } else if (!strcmp(args
.cmd
, "delete")) {
1137 request
= LXC_USERNIC_DELETE
;
1139 usage(argv
[0], true);
1140 _exit(EXIT_FAILURE
);
1143 /* Set a sane env, because we are setuid-root. */
1146 usernic_error("%s", "Failed to clear environment\n");
1147 _exit(EXIT_FAILURE
);
1150 ret
= setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
1152 usernic_error("%s", "Failed to set PATH, exiting\n");
1153 _exit(EXIT_FAILURE
);
1156 me
= get_username();
1158 usernic_error("%s", "Failed to get username\n");
1159 _exit(EXIT_FAILURE
);
1162 if (request
== LXC_USERNIC_CREATE
) {
1163 ret
= lxc_safe_int(args
.pid
, &pid
);
1165 usernic_error("Could not read pid: %s\n", args
.pid
);
1166 _exit(EXIT_FAILURE
);
1168 } else if (request
== LXC_USERNIC_DELETE
) {
1169 char opath
[LXC_PROC_PID_FD_LEN
];
1171 /* Open the path with O_PATH which will not trigger an actual
1172 * open(). Don't report an errno to the caller to not leak
1173 * information whether the path exists or not.
1174 * When stracing setuid is stripped so this is not a concern
1177 netns_fd
= open(args
.pid
, O_PATH
| O_CLOEXEC
);
1179 usernic_error("Failed to open \"%s\"\n", args
.pid
);
1180 _exit(EXIT_FAILURE
);
1183 if (!fhas_fs_type(netns_fd
, NSFS_MAGIC
)) {
1184 usernic_error("Path \"%s\" does not refer to a network namespace path\n", args
.pid
);
1186 _exit(EXIT_FAILURE
);
1189 ret
= snprintf(opath
, sizeof(opath
), "/proc/self/fd/%d", netns_fd
);
1190 if (ret
< 0 || (size_t)ret
>= sizeof(opath
)) {
1192 _exit(EXIT_FAILURE
);
1195 /* Now get an fd that we can use in setns() calls. */
1196 ret
= open(opath
, O_RDONLY
| O_CLOEXEC
);
1198 CMD_SYSERROR("Failed to open \"%s\"\n", args
.pid
);
1200 _exit(EXIT_FAILURE
);
1207 if (!create_db_dir(LXC_USERNIC_DB
)) {
1208 usernic_error("%s", "Failed to create directory for db file\n");
1213 _exit(EXIT_FAILURE
);
1216 fd
= open_and_lock(LXC_USERNIC_DB
);
1218 usernic_error("Failed to lock %s\n", LXC_USERNIC_DB
);
1223 _exit(EXIT_FAILURE
);
1226 if (request
== LXC_USERNIC_CREATE
) {
1227 if (!may_access_netns(pid
)) {
1228 usernic_error("User %s may not modify netns for pid %d\n", me
, pid
);
1229 _exit(EXIT_FAILURE
);
1231 } else if (request
== LXC_USERNIC_DELETE
) {
1234 has_priv
= is_privileged_over_netns(netns_fd
);
1237 usernic_error("%s", "Process is not privileged over "
1238 "network namespace\n");
1239 _exit(EXIT_FAILURE
);
1243 n
= get_alloted(me
, args
.type
, args
.link
, &alloted
);
1246 if (request
== LXC_USERNIC_DELETE
) {
1248 struct alloted_s
*it
;
1249 bool found_nicname
= false;
1251 if (!is_ovs_bridge(args
.link
)) {
1252 usernic_error("%s", "Deletion of non ovs type network "
1253 "devices not implemented\n");
1255 free_alloted(&alloted
);
1256 _exit(EXIT_FAILURE
);
1259 /* Check whether the network device we are supposed to delete
1260 * exists in the db. If it doesn't we will not delete it as we
1261 * need to assume the network device is not under our control.
1262 * As a side effect we also clear any invalid entries from the
1265 for (it
= alloted
; it
; it
= it
->next
)
1266 cull_entries(fd
, it
->name
, args
.type
, args
.link
,
1267 args
.veth_name
, &found_nicname
);
1269 free_alloted(&alloted
);
1271 if (!found_nicname
) {
1272 usernic_error("Caller is not allowed to delete network "
1273 "device \"%s\"\n", args
.veth_name
);
1274 _exit(EXIT_FAILURE
);
1277 ret
= lxc_ovs_delete_port(args
.link
, args
.veth_name
);
1279 usernic_error("Failed to remove port \"%s\" from "
1280 "openvswitch bridge \"%s\"",
1281 args
.veth_name
, args
.link
);
1282 _exit(EXIT_FAILURE
);
1285 _exit(EXIT_SUCCESS
);
1289 nicname
= get_nic_if_avail(fd
, alloted
, pid
, args
.type
,
1290 args
.link
, n
, &cnic
);
1293 free_alloted(&alloted
);
1296 usernic_error("%s", "Quota reached\n");
1297 _exit(EXIT_FAILURE
);
1300 /* Now rename the link. */
1301 newname
= lxc_secure_rename_in_ns(pid
, cnic
, args
.veth_name
,
1302 &container_veth_ifidx
);
1304 usernic_error("%s", "Failed to rename the link\n");
1306 ret
= lxc_netdev_delete_by_name(cnic
);
1308 usernic_error("Failed to delete \"%s\"\n", cnic
);
1311 _exit(EXIT_FAILURE
);
1314 host_veth_ifidx
= if_nametoindex(nicname
);
1315 if (!host_veth_ifidx
) {
1318 CMD_SYSERROR("Failed to get netdev index\n");
1319 _exit(EXIT_FAILURE
);
1322 /* Write names of veth pairs and their ifindeces to stout:
1323 * (e.g. eth0:731:veth9MT2L4:730)
1325 fprintf(stdout
, "%s:%d:%s:%d\n", newname
, container_veth_ifidx
, nicname
,
1331 _exit(EXIT_SUCCESS
);