]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cmd/lxc_user_nic.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include <linux/netlink.h>
12 #include <linux/rtnetlink.h>
13 #include <linux/sockios.h>
15 #include <net/if_arp.h>
16 #include <netinet/in.h>
24 #include <sys/ioctl.h>
26 #include <sys/param.h>
27 #include <sys/socket.h>
29 #include <sys/types.h>
34 #include "file_utils.h"
36 #include "memory_utils.h"
40 #include "process_utils.h"
41 #include "string_utils.h"
42 #include "syscall_wrappers.h"
49 #define usernic_debug_stream(stream, format, ...) \
51 fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
52 __func__, __VA_ARGS__); \
55 #define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
57 #define cmd_error_errno(__ret__, __errno__, format, ...) \
59 typeof(__ret__) __internal_ret__ = (__ret__); \
60 errno = (__errno__); \
61 CMD_SYSERROR(format, ##__VA_ARGS__); \
65 __noreturn
static void usage(bool fail
)
67 fprintf(stderr
, "Description:\n");
68 fprintf(stderr
, " Manage nics in another network namespace\n\n");
70 fprintf(stderr
, "Usage:\n");
71 fprintf(stderr
, " lxc-user-nic [command]\n\n");
73 fprintf(stderr
, "Available Commands:\n");
74 fprintf(stderr
, " create {lxcpath} {name} {pid} {type} {bridge} {container nicname}\n");
75 fprintf(stderr
, " delete {lxcpath} {name} {/proc/<pid>/ns/net} {type} {bridge} {container nicname}\n");
83 static int open_and_lock(const char *path
)
85 __do_close
int fd
= -EBADF
;
89 fd
= open(path
, O_RDWR
| O_CREAT
, S_IWUSR
| S_IRUSR
| O_CLOEXEC
);
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
);
109 static char *get_username(void)
111 __do_free
char *buf
= NULL
;
113 struct passwd
*pwentp
= NULL
;
117 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
121 buf
= malloc(bufsize
);
125 ret
= getpwuid_r(getuid(), &pwent
, buf
, bufsize
, &pwentp
);
128 usernic_error("%s", "Could not find matched password record\n");
130 CMD_SYSERROR("Failed to get username: %u\n", getuid());
134 return strdup(pwent
.pw_name
);
138 static char **get_groupnames(void)
140 __do_free
char *buf
= NULL
;
141 __do_free gid_t
*group_ids
= NULL
;
142 __do_free_string_list
char **groupnames
= NULL
;
146 struct group
*grentp
= NULL
;
149 ngroups
= getgroups(0, NULL
);
151 CMD_SYSERROR("Failed to get number of groups the user belongs to\n");
158 group_ids
= malloc(sizeof(gid_t
) * ngroups
);
160 CMD_SYSERROR("Failed to allocate memory while getting groups the user belongs to\n");
164 ret
= getgroups(ngroups
, group_ids
);
166 CMD_SYSERROR("Failed to get process groups\n");
170 groupnames
= zalloc(sizeof(char *) * (ngroups
+ 1));
172 CMD_SYSERROR("Failed to allocate memory while getting group names\n");
176 bufsize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
180 buf
= malloc(bufsize
);
182 CMD_SYSERROR("Failed to allocate memory while getting group names\n");
186 for (i
= 0; i
< ngroups
; i
++) {
187 while ((ret
= getgrgid_r(group_ids
[i
], &grent
, buf
, bufsize
, &grentp
)) == ERANGE
) {
191 if (bufsize
> MAX_GRBUF_SIZE
) {
192 usernic_error("Failed to get group members: %u\n", group_ids
[i
]);
196 new_buf
= realloc(buf
, bufsize
);
198 usernic_error("Failed to allocate memory while getting group names: %s\n",
205 /* If a group is not found, just ignore it. */
209 groupnames
[i
] = strdup(grent
.gr_name
);
210 if (!groupnames
[i
]) {
211 usernic_error("Failed to copy group name \"%s\"", grent
.gr_name
);
216 return move_ptr(groupnames
);
219 static bool name_is_in_groupnames(char *name
, char **groupnames
)
222 if (!strcmp(name
, *groupnames
))
233 struct alloted_s
*next
;
236 static struct alloted_s
*append_alloted(struct alloted_s
**head
, char *name
, int n
)
238 __do_free
struct alloted_s
*al
= NULL
;
239 struct alloted_s
*cur
;
241 if (!head
|| !name
) {
242 /* Sanity check. Parameters should not be null. */
243 usernic_error("%s\n", "Unexpected NULL argument");
247 al
= zalloc(sizeof(struct alloted_s
));
249 CMD_SYSERROR("Failed to allocate memory\n");
253 al
->name
= strdup(name
);
272 static void free_alloted(struct alloted_s
**head
)
274 struct alloted_s
*cur
;
288 /* The configuration file consists of lines of the form:
290 * user type bridge count
292 * @group type bridge count
294 * Return the count entry for the calling user if there is one. Else
297 static int get_alloted(char *me
, char *intype
, char *link
,
298 struct alloted_s
**alloted
)
300 __do_free
char *line
= NULL
;
301 __do_fclose
FILE *fin
= NULL
;
302 __do_free_string_list
char **groups
= NULL
;
304 char name
[100], type
[100], br
[100];
308 fin
= fopen(LXC_USERNIC_CONF
, "re");
310 CMD_SYSERROR("Failed to open \"%s\"\n", LXC_USERNIC_CONF
);
314 groups
= get_groupnames();
315 while ((getline(&line
, &len
, fin
)) != -1) {
316 ret
= sscanf(line
, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name
,
321 if (is_empty_string(name
))
324 if (!strequal(name
, me
)) {
328 if (!name_is_in_groupnames(name
+ 1, groups
))
332 if (!strequal(type
, intype
))
335 if (!strequal(link
, br
))
339 * Found the user or group with the appropriate settings,
340 * therefore finish the search. What to do if there are is more
341 * than one applicable line? Currently this is not specified in
344 * If append_alloted returns NULL, e.g. due to a malloc error,
345 * we set count to 0 and break the loop, allowing cleanup and
346 * then exiting from main().
348 if (!append_alloted(alloted
, name
, n
)) {
356 /* Now return the total number of nics that this user can create. */
360 static char *get_eol(char *s
, char *e
)
362 while ((s
< e
) && *s
&& (*s
!= '\n'))
368 static char *get_eow(char *s
, char *e
)
370 while ((s
< e
) && *s
&& !isblank(*s
) && (*s
!= '\n'))
376 static char *find_line(char *buf_start
, char *buf_end
, char *name
,
377 char *net_type
, char *net_link
, char *net_dev
,
378 bool *owner
, bool *found
, bool *keep
)
380 char *end_of_line
, *end_of_word
, *line
;
382 while (buf_start
< buf_end
) {
384 char netdev_name
[IFNAMSIZ
];
390 end_of_line
= get_eol(buf_start
, buf_end
);
391 if (end_of_line
>= buf_end
)
395 if (*buf_start
== '#')
398 while ((buf_start
< buf_end
) && isblank(*buf_start
))
401 /* Check whether the line contains the caller's name. */
402 end_of_word
= get_eow(buf_start
, buf_end
);
407 if (strncmp(buf_start
, name
, strlen(name
)))
410 if (strlen(name
) == (size_t)(end_of_word
- buf_start
))
413 buf_start
= end_of_word
+ 1;
414 while ((buf_start
< buf_end
) && isblank(*buf_start
))
417 /* Check whether line is of the right network type. */
418 end_of_word
= get_eow(buf_start
, buf_end
);
423 if (strncmp(buf_start
, net_type
, strlen(net_type
)))
426 buf_start
= end_of_word
+ 1;
427 while ((buf_start
< buf_end
) && isblank(*buf_start
))
430 /* Check whether line is contains the right link. */
431 end_of_word
= get_eow(buf_start
, buf_end
);
436 if (strncmp(buf_start
, net_link
, strlen(net_link
)))
439 buf_start
= end_of_word
+ 1;
440 while ((buf_start
< buf_end
) && isblank(*buf_start
))
443 /* Check whether line contains the right network device. */
444 end_of_word
= get_eow(buf_start
, buf_end
);
449 len
= end_of_word
- buf_start
;
454 memcpy(netdev_name
, buf_start
, len
);
455 netdev_name
[len
] = '\0';
456 *keep
= lxc_nic_exists(netdev_name
);
458 if (net_dev
&& !strcmp(netdev_name
, net_dev
))
464 buf_start
= end_of_line
+ 1;
470 static int instantiate_veth(char *veth1
, char *veth2
, pid_t pid
, unsigned int mtu
)
474 ret
= lxc_veth_create(veth1
, veth2
, pid
, mtu
);
476 CMD_SYSERROR("Failed to create %s-%s\n", veth1
, veth2
);
477 return ret_errno(-ret
);
481 * Changing the high byte of the mac address to 0xfe, the bridge
482 * interface will always keep the host's mac address and not take the
483 * mac address of a container.
485 ret
= setup_private_host_hw_addr(veth1
);
487 CMD_SYSERROR("Failed to change mac address of host interface %s\n", veth1
);
488 return ret_errno(-ret
);
491 return netdev_set_flag(veth1
, IFF_UP
);
494 static int get_mtu(char *name
)
498 idx
= if_nametoindex(name
);
502 return netdev_get_mtu(idx
);
505 static int create_nic(char *nic
, char *br
, int pid
, char **cnic
)
507 unsigned int mtu
= 1500;
509 char veth1buf
[IFNAMSIZ
], veth2buf
[IFNAMSIZ
];
511 ret
= snprintf(veth1buf
, IFNAMSIZ
, "%s", nic
);
512 if (ret
< 0 || ret
>= IFNAMSIZ
) {
513 usernic_error("%s", "Could not create nic name\n");
517 ret
= snprintf(veth2buf
, IFNAMSIZ
, "%sp", veth1buf
);
518 if (ret
< 0 || ret
>= IFNAMSIZ
) {
519 usernic_error("%s\n", "Could not create nic name");
523 if (strcmp(br
, "none"))
528 /* create the nics */
529 ret
= instantiate_veth(veth1buf
, veth2buf
, pid
, mtu
);
531 usernic_error("%s", "Error creating veth tunnel\n");
535 if (strcmp(br
, "none")) {
537 ret
= lxc_netdev_set_mtu(veth1buf
, mtu
);
539 usernic_error("Failed to set mtu to %d on %s\n",
545 /* attach veth1 to bridge */
546 ret
= lxc_bridge_attach(br
, veth1buf
);
548 usernic_error("Error attaching %s to %s\n", veth1buf
, br
);
553 *cnic
= strdup(veth2buf
);
555 usernic_error("Failed to copy string \"%s\"\n", veth2buf
);
562 lxc_netdev_delete_by_name(veth1buf
);
572 static bool cull_entries(int fd
, char *name
, char *net_type
, char *net_link
,
573 char *net_dev
, bool *found_nicname
)
575 __do_free
char *buf
= NULL
;
576 __do_free
struct entry_line
*entry_lines
= NULL
;
580 char *buf_end
, *buf_start
;
583 ret
= fd_to_buf(fd
, &buf
, &length
);
585 CMD_SYSERROR("Failed to read database file\n");
588 if (lseek(fd
, 0, SEEK_SET
) < 0)
595 buf_end
= buf
+ length
;
596 while ((buf_start
= find_line(buf_start
, buf_end
, name
, net_type
,
597 net_link
, net_dev
, &(bool){true}, &found
,
599 struct entry_line
*newe
;
601 newe
= realloc(entry_lines
, sizeof(*entry_lines
) * (n
+ 1));
606 *found_nicname
= true;
609 entry_lines
[n
].start
= buf_start
;
610 entry_lines
[n
].len
= get_eol(buf_start
, buf_end
) - entry_lines
[n
].start
;
611 entry_lines
[n
].keep
= keep
;
614 buf_start
+= entry_lines
[n
- 1].len
+ 1;
615 if (buf_start
>= buf_end
)
621 for (int i
= 0; i
< n
; i
++) {
622 if (!entry_lines
[i
].keep
)
625 memcpy(buf_start
, entry_lines
[i
].start
, entry_lines
[i
].len
);
626 buf_start
+= entry_lines
[i
].len
;
631 return ftruncate(fd
, buf_start
- buf
) == 0;
634 static int count_entries(char *buf
, off_t len
, char *name
, char *net_type
, char *net_link
)
641 while ((buf
= find_line(buf
, buf_end
, name
, net_type
, net_link
, NULL
,
642 &owner
, &(bool){true}, &(bool){true}))) {
646 buf
= get_eol(buf
, buf_end
) + 1;
654 /* The dbfile has lines of the format: user type bridge nicname. */
655 static char *get_nic_if_avail(int fd
, struct alloted_s
*names
, int pid
,
656 char *intype
, char *br
, int allowed
, char **cnic
)
658 __do_free
char *buf
= NULL
, *newline
= NULL
;
663 char nicname
[IFNAMSIZ
];
667 for (n
= names
; n
!= NULL
; n
= n
->next
)
668 cull_entries(fd
, n
->name
, intype
, br
, NULL
, NULL
);
675 ret
= fd_to_buf(fd
, &buf
, &length
);
677 CMD_SYSERROR("Failed to read database file\n");
680 if (lseek(fd
, 0, SEEK_SET
) < 0)
686 for (n
= names
; n
!= NULL
; n
= n
->next
) {
689 count
= count_entries(buf
, length
, n
->name
, intype
, br
);
690 if (count
>= n
->allowed
)
703 * For POSIX integer uids the network device name schema is
705 * With four random characters passed to
706 * lxc_ifname_alnum_case_sensitive() we get 62^4 = 14776336
707 * combinations per uid. That's plenty of network devices for now.
709 if (uid
> 0 && uid
<= 65536)
710 ret
= snprintf(nicname
, sizeof(nicname
), "veth%d_XXXX", uid
);
712 ret
= snprintf(nicname
, sizeof(nicname
), "vethXXXXXX");
713 if (ret
< 0 || (size_t)ret
>= sizeof(nicname
))
716 if (!lxc_ifname_alnum_case_sensitive(nicname
))
719 ret
= create_nic(nicname
, br
, pid
, cnic
);
721 usernic_error("%s", "Failed to create new nic\n");
743 slen
= strlen(owner
) + strlen(intype
) + strlen(br
) + strlen(nicname
) + 4;
744 newline
= malloc(slen
+ 1);
746 CMD_SYSERROR("Failed allocate memory\n");
750 ret
= snprintf(newline
, slen
+ 1, "%s %s %s %s\n", owner
, intype
, br
, nicname
);
751 if (ret
< 0 || (size_t)ret
>= (slen
+ 1)) {
752 if (lxc_netdev_delete_by_name(nicname
) != 0)
753 usernic_error("Error unlinking %s\n", nicname
);
758 if (lxc_pwrite_nointr(fd
, newline
, slen
, length
) != slen
) {
759 CMD_SYSERROR("Failed to append new entry \"%s\" to database file", newline
);
761 if (lxc_netdev_delete_by_name(nicname
) != 0)
762 usernic_error("Error unlinking %s\n", nicname
);
767 ret
= ftruncate(fd
, length
+ slen
);
769 CMD_SYSERROR("Failed to truncate file\n");
771 if (lxc_netdev_delete_by_name(nicname
) != 0)
772 usernic_error("Error unlinking %s\n", nicname
);
777 return strdup(nicname
);
780 static bool create_db_dir(char *fnam
)
782 __do_free
char *copy
= NULL
;
786 copy
= must_copy_string(fnam
);
792 while (*p
&& *p
!= '/')
800 ret
= mkdir(fnam
, 0755);
801 if (ret
< 0 && errno
!= EEXIST
) {
802 CMD_SYSERROR("Failed to create %s\n", fnam
);
812 static char *lxc_secure_rename_in_ns(int pid
, char *oldname
, char *newname
,
813 int *container_veth_ifidx
)
815 __do_close
int fd
= -EBADF
, ofd
= -EBADF
;
819 uid_t ruid
, suid
, euid
;
820 char ifname
[IFNAMSIZ
];
822 pid_self
= lxc_raw_getpid();
824 ofd
= lxc_preserve_ns(pid_self
, "net");
826 return cmd_error_errno(NULL
, errno
, "Failed opening network namespace path for %d", pid_self
);
828 fd
= lxc_preserve_ns(pid
, "net");
830 return cmd_error_errno(NULL
, errno
, "Failed opening network namespace path for %d", pid
);
832 ret
= getresuid(&ruid
, &euid
, &suid
);
834 return cmd_error_errno(NULL
, errno
, "Failed to retrieve real, effective, and saved user IDs\n");
836 ret
= setns(fd
, CLONE_NEWNET
);
838 return cmd_error_errno(NULL
, errno
, "Failed to setns() to the network namespace of the container with PID %d\n", pid
);
840 ret
= setresuid(ruid
, ruid
, 0);
842 CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n", ruid
);
844 * It's ok to jump to do_full_cleanup here since setresuid()
845 * will succeed when trying to set real, effective, and saved
846 * to values they currently have.
851 /* Check if old interface exists. */
852 ifindex
= if_nametoindex(oldname
);
854 CMD_SYSERROR("Failed to get netdev index\n");
859 * When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
860 * netlink will replace the format specifier with an appropriate index.
861 * So we pass "eth%d".
863 ret
= lxc_netdev_rename_by_name(oldname
, newname
? newname
: "eth%d");
865 CMD_SYSERROR("Error %d renaming netdev %s to %s in container\n", ret
, oldname
, newname
? newname
: "eth%d");
869 /* Retrieve new name for interface. */
870 if (!if_indextoname(ifindex
, ifname
)) {
871 CMD_SYSERROR("Failed to get new netdev name\n");
878 ret
= setresuid(ruid
, euid
, suid
);
880 return cmd_error_errno(NULL
, errno
, "Failed to restore privilege by setting effective user id to %d, real user id to %d, and saved user ID to %d\n",
884 ret
= setns(ofd
, CLONE_NEWNET
);
886 return cmd_error_errno(NULL
, errno
, "Failed to setns() to original network namespace of PID %d\n", ofd
);
891 *container_veth_ifidx
= ifindex
;
892 return strdup(ifname
);
895 /* If the caller (real uid, not effective uid) may read the /proc/[pid]/ns/net,
896 * then it is either the caller's netns or one which it created.
898 static bool may_access_netns(int pid
)
902 uid_t ruid
, suid
, euid
;
903 bool may_access
= false;
905 ret
= getresuid(&ruid
, &euid
, &suid
);
907 CMD_SYSERROR("Failed to retrieve real, effective, and saved user IDs\n");
911 ret
= setresuid(ruid
, ruid
, euid
);
913 CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to %d\n",
918 ret
= snprintf(s
, 200, "/proc/%d/ns/net", pid
);
919 if (ret
< 0 || ret
>= 200)
922 ret
= access(s
, R_OK
);
926 CMD_SYSERROR("Uid %d may not access %s\n", (int)ruid
, s
);
929 ret
= setresuid(ruid
, euid
, suid
);
931 CMD_SYSERROR("Failed to restore user id to %d, real user id to %d, and saved user ID to %d\n",
939 struct user_nic_args
{
949 enum lxc_user_nic_command
{
950 LXC_USERNIC_CREATE
= 0,
951 LXC_USERNIC_DELETE
= 1,
954 static bool is_privileged_over_netns(int netns_fd
)
958 uid_t euid
, ruid
, suid
;
961 pid_self
= lxc_raw_getpid();
963 ofd
= lxc_preserve_ns(pid_self
, "net");
965 usernic_error("Failed opening network namespace path for %d", pid_self
);
969 ret
= getresuid(&ruid
, &euid
, &suid
);
971 CMD_SYSERROR("Failed to retrieve real, effective, and saved user IDs\n");
972 goto do_partial_cleanup
;
975 ret
= setns(netns_fd
, CLONE_NEWNET
);
977 CMD_SYSERROR("Failed to setns() to network namespace\n");
978 goto do_partial_cleanup
;
981 ret
= setresuid(ruid
, ruid
, 0);
983 CMD_SYSERROR("Failed to drop privilege by setting effective user id and real user id to %d, and saved user ID to 0\n",
985 /* It's ok to jump to do_full_cleanup here since setresuid()
986 * will succeed when trying to set real, effective, and saved to
987 * values they currently have.
989 goto do_full_cleanup
;
992 /* Test whether we are privileged over the network namespace. To do this
993 * we try to delete the loopback interface which is not possible. If we
994 * are privileged over the network namespace we will get ENOTSUP. If we
995 * are not privileged over the network namespace we will get EPERM.
997 ret
= lxc_netdev_delete_by_name("lo");
1002 ret
= setresuid(ruid
, euid
, suid
);
1004 CMD_SYSERROR("Failed to restore privilege by setting effective user id to %d, real user id to %d, and saved user ID to %d\n",
1009 ret
= setns(ofd
, CLONE_NEWNET
);
1011 CMD_SYSERROR("Failed to setns() to original network namespace of PID %d\n",
1021 static inline int validate_args(const struct user_nic_args
*args
, int argc
)
1023 int request
= -EINVAL
;
1025 if (!strcmp(args
->cmd
, "create"))
1026 request
= LXC_USERNIC_CREATE
;
1027 else if (!strcmp(args
->cmd
, "delete"))
1028 request
= LXC_USERNIC_DELETE
;
1033 int main(int argc
, char *argv
[])
1035 __do_free
char *me
= NULL
, *newname
= NULL
, *nicname
= NULL
;
1036 int fd
, n
, pid
, request
, ret
;
1037 struct user_nic_args args
;
1038 int container_veth_ifidx
= -1, host_veth_ifidx
= -1, netns_fd
= -1;
1040 struct alloted_s
*alloted
= NULL
;
1042 if (argc
< 7 || argc
> 8)
1045 memset(&args
, 0, sizeof(struct user_nic_args
));
1048 args
.lxc_path
= argv
[2];
1049 args
.lxc_name
= argv
[3];
1051 args
.type
= argv
[5];
1052 args
.link
= argv
[6];
1054 args
.veth_name
= argv
[7];
1056 request
= validate_args(&args
, argc
);
1060 /* Set a sane env, because we are setuid-root. */
1063 usernic_error("%s", "Failed to clear environment\n");
1064 _exit(EXIT_FAILURE
);
1067 ret
= setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
1069 usernic_error("%s", "Failed to set PATH, exiting\n");
1070 _exit(EXIT_FAILURE
);
1073 me
= get_username();
1075 usernic_error("%s", "Failed to get username\n");
1076 _exit(EXIT_FAILURE
);
1079 if (request
== LXC_USERNIC_CREATE
) {
1080 ret
= lxc_safe_int(args
.pid
, &pid
);
1082 usernic_error("Could not read pid: %s\n", args
.pid
);
1083 _exit(EXIT_FAILURE
);
1085 } else if (request
== LXC_USERNIC_DELETE
) {
1086 char opath
[LXC_PROC_PID_FD_LEN
];
1088 /* Open the path with O_PATH which will not trigger an actual
1089 * open(). Don't report an errno to the caller to not leak
1090 * information whether the path exists or not.
1091 * When stracing setuid is stripped so this is not a concern
1094 netns_fd
= open(args
.pid
, O_PATH
| O_CLOEXEC
);
1096 usernic_error("Failed to open \"%s\"\n", args
.pid
);
1097 _exit(EXIT_FAILURE
);
1100 if (!fhas_fs_type(netns_fd
, NSFS_MAGIC
)) {
1101 usernic_error("Path \"%s\" does not refer to a network namespace path\n", args
.pid
);
1103 _exit(EXIT_FAILURE
);
1106 ret
= snprintf(opath
, sizeof(opath
), "/proc/self/fd/%d", netns_fd
);
1107 if (ret
< 0 || (size_t)ret
>= sizeof(opath
)) {
1109 _exit(EXIT_FAILURE
);
1112 /* Now get an fd that we can use in setns() calls. */
1113 ret
= open(opath
, O_RDONLY
| O_CLOEXEC
);
1115 CMD_SYSERROR("Failed to open \"%s\"\n", args
.pid
);
1117 _exit(EXIT_FAILURE
);
1124 if (!create_db_dir(LXC_USERNIC_DB
)) {
1125 usernic_error("%s", "Failed to create directory for db file\n");
1130 _exit(EXIT_FAILURE
);
1133 fd
= open_and_lock(LXC_USERNIC_DB
);
1135 usernic_error("Failed to lock %s\n", LXC_USERNIC_DB
);
1140 _exit(EXIT_FAILURE
);
1143 if (request
== LXC_USERNIC_CREATE
) {
1144 if (!may_access_netns(pid
)) {
1145 usernic_error("User %s may not modify netns for pid %d\n", me
, pid
);
1146 _exit(EXIT_FAILURE
);
1148 } else if (request
== LXC_USERNIC_DELETE
) {
1151 has_priv
= is_privileged_over_netns(netns_fd
);
1154 usernic_error("%s", "Process is not privileged over network namespace\n");
1155 _exit(EXIT_FAILURE
);
1159 n
= get_alloted(me
, args
.type
, args
.link
, &alloted
);
1161 if (request
== LXC_USERNIC_DELETE
) {
1162 struct alloted_s
*it
;
1163 bool found_nicname
= false;
1165 if (!is_ovs_bridge(args
.link
)) {
1166 usernic_error("%s", "Deletion of non ovs type network devices not implemented\n");
1168 free_alloted(&alloted
);
1169 _exit(EXIT_FAILURE
);
1172 /* Check whether the network device we are supposed to delete
1173 * exists in the db. If it doesn't we will not delete it as we
1174 * need to assume the network device is not under our control.
1175 * As a side effect we also clear any invalid entries from the
1178 for (it
= alloted
; it
; it
= it
->next
)
1179 cull_entries(fd
, it
->name
, args
.type
, args
.link
,
1180 args
.veth_name
, &found_nicname
);
1182 free_alloted(&alloted
);
1184 if (!found_nicname
) {
1185 usernic_error("Caller is not allowed to delete network device \"%s\"\n", args
.veth_name
);
1186 _exit(EXIT_FAILURE
);
1189 ret
= lxc_ovs_delete_port(args
.link
, args
.veth_name
);
1191 usernic_error("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", args
.veth_name
, args
.link
);
1192 _exit(EXIT_FAILURE
);
1195 _exit(EXIT_SUCCESS
);
1199 nicname
= get_nic_if_avail(fd
, alloted
, pid
, args
.type
,
1200 args
.link
, n
, &cnic
);
1203 free_alloted(&alloted
);
1206 usernic_error("%s", "Quota reached\n");
1207 _exit(EXIT_FAILURE
);
1210 /* Now rename the link. */
1211 newname
= lxc_secure_rename_in_ns(pid
, cnic
, args
.veth_name
,
1212 &container_veth_ifidx
);
1214 usernic_error("%s", "Failed to rename the link\n");
1216 ret
= lxc_netdev_delete_by_name(cnic
);
1218 usernic_error("Failed to delete \"%s\"\n", cnic
);
1220 _exit(EXIT_FAILURE
);
1223 host_veth_ifidx
= if_nametoindex(nicname
);
1224 if (!host_veth_ifidx
) {
1225 CMD_SYSERROR("Failed to get netdev index\n");
1226 _exit(EXIT_FAILURE
);
1229 /* Write names of veth pairs and their ifindices to stout:
1230 * (e.g. eth0:731:veth9MT2L4:730)
1232 fprintf(stdout
, "%s:%d:%s:%d\n", newname
, container_veth_ifidx
, nicname
,
1236 _exit(EXIT_SUCCESS
);