Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
2c7a5008
Commit
2c7a5008
authored
Jun 23, 2015
by
Serge Hallyn
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #517 from hkjolhede/master
Added support for groups in lxc-usernet
parents
16fc3582
680836fa
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
245 additions
and
24 deletions
+245
-24
lxc-usernet.sgml.in
doc/lxc-usernet.sgml.in
+27
-2
lxc_user_nic.c
src/lxc/lxc_user_nic.c
+218
-22
No files found.
doc/lxc-usernet.sgml.in
View file @
2c7a5008
...
@@ -63,6 +63,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
...
@@ -63,6 +63,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para>
<para>
<command>user</command> <command>type</command> <command>bridge</command> <command>number</command>
<command>user</command> <command>type</command> <command>bridge</command> <command>number</command>
</para>
</para>
<para>or</para>
<para>
<command>@group</command> <command>type</command> <command>bridge</command> <command>number</command>
</para>
<para>
<para>
Where
Where
</para>
</para>
...
@@ -82,6 +86,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
...
@@ -82,6 +86,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<varlistentry>
<varlistentry>
<term>
<term>
<option>@group</option>
</term>
<listitem>
<para>
is the groupname to which this entry applies.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>type</option>
<option>type</option>
</term>
</term>
<listitem>
<listitem>
...
@@ -110,12 +125,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
...
@@ -110,12 +125,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</term>
</term>
<listitem>
<listitem>
<para>
<para>
is the number of network interfaces of the given type which the
is the number o
r quota o
f network interfaces of the given type which the
given user may attach to the given bridge, for instance <filename>2</filename>.
given user
or group
may attach to the given bridge, for instance <filename>2</filename>.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
</variablelist>
</variablelist>
<para>
Since a user can be be specified both by username as well as one or
more usergroups, it is possible that several configuration lines
enable that user to create network interfaces. In such cases, any
interfaces create are counted towards the quotas of the user or group
in the order in which they appear in the file. If the quota of one
line is full, the rest will be parsed until one is found or the end of
the file.
</para>
</refsect2>
</refsect2>
</refsect1>
</refsect1>
...
...
src/lxc/lxc_user_nic.c
View file @
2c7a5008
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/types.h>
#include <pwd.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <unistd.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/file.h>
...
@@ -96,20 +97,173 @@ static char *get_username(void)
...
@@ -96,20 +97,173 @@ static char *get_username(void)
return
pwd
->
pw_name
;
return
pwd
->
pw_name
;
}
}
static
void
free_groupnames
(
char
**
groupnames
)
{
char
**
group
;
for
(
group
=
groupnames
;
group
!=
NULL
;
group
++
)
free
(
*
group
);
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:
/* The configuration file consists of lines of the form:
*
*
* user type bridge count
* user type bridge count
* or
* @group type bridge count
*
*
* Return the count entry for the calling user if there is one. Else
* Return the count entry for the calling user if there is one. Else
* return -1.
* 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
(
LXC_USERNIC_CONF
,
"r"
);
FILE
*
fin
=
fopen
(
LXC_USERNIC_CONF
,
"r"
);
char
*
line
=
NULL
;
char
*
line
=
NULL
;
char
user
[
100
],
type
[
100
],
br
[
100
];
char
name
[
100
],
type
[
100
],
br
[
100
];
size_t
len
=
0
;
size_t
len
=
0
;
int
n
=
-
1
,
ret
;
int
n
,
ret
,
count
=
0
;
char
**
groups
;
if
(
!
fin
)
{
if
(
!
fin
)
{
fprintf
(
stderr
,
"Failed to open %s: %s
\n
"
,
LXC_USERNIC_CONF
,
fprintf
(
stderr
,
"Failed to open %s: %s
\n
"
,
LXC_USERNIC_CONF
,
...
@@ -117,24 +271,48 @@ static int get_alloted(char *me, char *intype, char *link)
...
@@ -117,24 +271,48 @@ static int get_alloted(char *me, char *intype, char *link)
return
-
1
;
return
-
1
;
}
}
groups
=
get_groupnames
();
while
((
getline
(
&
line
,
&
len
,
fin
))
!=
-
1
)
{
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
)
if
(
ret
!=
4
)
continue
;
continue
;
if
(
strcmp
(
user
,
me
)
!=
0
)
if
(
strlen
(
name
)
==
0
)
continue
;
continue
;
if
(
strcmp
(
name
,
me
)
!=
0
)
{
if
(
name
[
0
]
!=
'@'
)
continue
;
if
(
!
name_is_in_groupnames
(
name
+
1
,
groups
))
continue
;
}
if
(
strcmp
(
type
,
intype
)
!=
0
)
if
(
strcmp
(
type
,
intype
)
!=
0
)
continue
;
continue
;
if
(
strcmp
(
link
,
br
)
!=
0
)
if
(
strcmp
(
link
,
br
)
!=
0
)
continue
;
continue
;
free
(
line
);
fclose
(
fin
);
/* found the user or group with the appropriate settings, therefore finish the search.
return
n
;
* 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
);
fclose
(
fin
);
free
(
line
);
free
(
line
);
return
-
1
;
// now return the total number of nics that this user can create
return
count
;
}
}
static
char
*
get_eol
(
char
*
s
,
char
*
e
)
static
char
*
get_eol
(
char
*
s
,
char
*
e
)
...
@@ -154,7 +332,7 @@ static char *get_eow(char *s, char *e)
...
@@ -154,7 +332,7 @@ static char *get_eow(char *s, char *e)
static
char
*
find_line
(
char
*
p
,
char
*
e
,
char
*
u
,
char
*
t
,
char
*
l
)
static
char
*
find_line
(
char
*
p
,
char
*
e
,
char
*
u
,
char
*
t
,
char
*
l
)
{
{
char
*
p1
,
*
p2
,
*
ret
;
char
*
p1
,
*
p2
,
*
ret
;
while
(
p
<
e
&&
(
p1
=
get_eol
(
p
,
e
))
<
e
)
{
while
(
p
<
e
&&
(
p1
=
get_eol
(
p
,
e
))
<
e
)
{
ret
=
p
;
ret
=
p
;
if
(
*
p
==
'#'
)
if
(
*
p
==
'#'
)
...
@@ -361,7 +539,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
...
@@ -361,7 +539,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
p
+=
entry_lines
[
n
-
1
].
len
+
1
;
p
+=
entry_lines
[
n
-
1
].
len
+
1
;
if
(
p
>=
e
)
if
(
p
>=
e
)
break
;
break
;
}
}
p
=
buf
;
p
=
buf
;
for
(
i
=
0
;
i
<
n
;
i
++
)
{
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
!
entry_lines
[
i
].
keep
)
if
(
!
entry_lines
[
i
].
keep
)
...
@@ -396,18 +574,23 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
...
@@ -396,18 +574,23 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
* The dbfile has lines of the format:
* The dbfile has lines of the format:
* user type bridge nicname
* 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
;
off_t
len
,
slen
;
struct
stat
sb
;
struct
stat
sb
;
char
*
buf
=
NULL
,
*
newline
;
char
*
buf
=
NULL
,
*
newline
;
int
ret
,
count
=
0
;
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
);
if
(
allowed
==
0
)
if
(
allowed
==
0
)
return
false
;
return
false
;
owner
=
names
->
name
;
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
fprintf
(
stderr
,
"Failed to fstat: %s
\n
"
,
strerror
(
errno
));
fprintf
(
stderr
,
"Failed to fstat: %s
\n
"
,
strerror
(
errno
));
return
false
;
return
false
;
...
@@ -420,17 +603,27 @@ static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br,
...
@@ -420,17 +603,27 @@ static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br,
return
false
;
return
false
;
}
}
count
=
count_entries
(
buf
,
len
,
me
,
intype
,
br
);
owner
=
NULL
;
if
(
count
>=
allowed
)
for
(
n
=
names
;
n
!=
NULL
;
n
=
n
->
next
)
{
return
false
;
count
=
count_entries
(
buf
,
len
,
n
->
name
,
intype
,
br
);
if
(
count
>=
n
->
allowed
)
continue
;
owner
=
n
->
name
;
break
;
}
}
}
if
(
owner
==
NULL
)
return
false
;
if
(
!
get_new_nicname
(
nicname
,
br
,
pid
,
cnic
))
if
(
!
get_new_nicname
(
nicname
,
br
,
pid
,
cnic
))
return
false
;
return
false
;
/*
me
' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
/*
owner
' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
slen
=
strlen
(
me
)
+
strlen
(
intype
)
+
strlen
(
br
)
+
strlen
(
*
nicname
)
+
5
;
slen
=
strlen
(
owner
)
+
strlen
(
intype
)
+
strlen
(
br
)
+
strlen
(
*
nicname
)
+
5
;
newline
=
alloca
(
slen
);
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
(
ret
<
0
||
ret
>=
slen
)
{
if
(
lxc_netdev_delete_by_name
(
*
nicname
)
!=
0
)
if
(
lxc_netdev_delete_by_name
(
*
nicname
)
!=
0
)
fprintf
(
stderr
,
"Error unlinking %s!
\n
"
,
*
nicname
);
fprintf
(
stderr
,
"Error unlinking %s!
\n
"
,
*
nicname
);
...
@@ -592,6 +785,7 @@ int main(int argc, char *argv[])
...
@@ -592,6 +785,7 @@ int main(int argc, char *argv[])
char
*
cnic
=
NULL
;
// created nic name in container is returned here.
char
*
cnic
=
NULL
;
// created nic name in container is returned here.
char
*
vethname
=
NULL
;
char
*
vethname
=
NULL
;
int
pid
;
int
pid
;
struct
alloted_s
*
alloted
=
NULL
;
/* set a sane env, because we are setuid-root */
/* set a sane env, because we are setuid-root */
if
(
clearenv
()
<
0
)
{
if
(
clearenv
()
<
0
)
{
...
@@ -631,14 +825,16 @@ int main(int argc, char *argv[])
...
@@ -631,14 +825,16 @@ int main(int argc, char *argv[])
if
(
!
may_access_netns
(
pid
))
{
if
(
!
may_access_netns
(
pid
))
{
fprintf
(
stderr
,
"User %s may not modify netns for pid %d
\n
"
,
fprintf
(
stderr
,
"User %s may not modify netns for pid %d
\n
"
,
me
,
pid
);
me
,
pid
);
exit
(
1
);
exit
(
1
);
}
}
n
=
get_alloted
(
me
,
argv
[
2
],
argv
[
3
]);
n
=
get_alloted
(
me
,
argv
[
2
],
argv
[
3
]
,
&
alloted
);
if
(
n
>
0
)
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
);
close
(
fd
);
free_alloted
(
&
alloted
);
if
(
!
gotone
)
{
if
(
!
gotone
)
{
fprintf
(
stderr
,
"Quota reached
\n
"
);
fprintf
(
stderr
,
"Quota reached
\n
"
);
exit
(
1
);
exit
(
1
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment