Commit 07c5433f authored by Renzo Davoli's avatar Renzo Davoli

v.0.1

parents
This diff is collapsed.
AM_LIBTOOLFLAGS = --quiet
libsecurity_LTLIBRARIES = pam_newnet.la pam_usernet.la
pam_newnet_la_SOURCES = pam_newnet.c pam_net_checkgroup.c
pam_newnet_la_LDFLAGS = -module -avoid-version
pam_usernet_la_SOURCES = pam_usernet.c pam_net_checkgroup.c
pam_usernet_la_LDFLAGS = -module -avoid-version
man_MANS = pam_newnet.8 pam_usernet.8
install-data-hook:
@(cd $(DESTDIR)$(libsecuritydir) && $(RM) $(libsecurity_LTLIBRARIES))
## LIBPAM-NET: create/join network namespaces at login
**libpam-net** implements two pam modules:
- **pam_newnet.so**: users belonging to the *newnet* group get a new
network namespace at login.
- **pam_usernet.so** users belonging to the *usernet* group get their own
network name at login. If a network namespace having the same name as the
username exists, pam runs the user shell in that namespace. If such a
namespace does does not exist, it is created during the login process.
### INSTALL:
get the source code, from the root of the source tree run:
```
$ autoreconf -if
$ ./configure --with-libsecuritydir=/lib/x86_64-linux-gnu/security
$ make
$ sudo make install
```
Add the rules to the pam configuration files: e.g. */etc/pam.d/sshd* or
*/etc/pam.d/login*
```
session required pam_newnet.so
session required pam_usernet.so
```
Create the groups *newnet* and *usernet* including all the users that
must be subject to one or the other service:
e.g. in /etc/group:
```
newnet:x:148:renzononet
usernet:x:149:renzousernet
```
### Usage cases.
- **pam_newnet.so**. Users in the *newnet* group can log-in through a
network connection (e.g. by ssh) but their processes cannot communicate
(the only interface they can see is the localhost of the namespace created
at login time.
Networking can take place just between processes of the same
session).
- **pam_usernet.so**. The system administrator can create a network
namespace for each user in *usernet* group. Each namespace must be named
after each username.
Users will *land* in their own network namespace at
login. e.g. the sysadm can create *renzousernet*'s network namespace as
follows:
```
# ip netns add renzousernet
# ip netns exec renzousernet ip addr add 127.0.0.1/8 dev lo
# ip netns exec renzousernet tunctl -t eth0
# ...
```
- **pam_newnet.so** or **pam_usernet.so** with **cado** (see [cado on
GitHub](https://github.com/rd235/cado). Users in *newnet* or *usernet*
which are allowed to gain **CAP_NET_ADMIN** capability can manage their
networks by themselves. They can create tap interfaces (by **tunctl** or
**vde_tunctl**), assign IP addresses, define routing etc. Users can
configure only their own network namespaces, not the real network
interfaces and services.
- **pam_newnet.so** or **pam_usernet.so** with **cado** and **vde**
(virtual distributed ethernet). Users can connect their networks to vde
services (e.g. vde switches).
- **pam_newnet.so** and **netnsjoin** (a tool of nsutils, see [nsutils on
GitHub](https://github.com/rd235/nsutils)). Each user can create new
namespaces (just by starting a new session), he/she can keep namespaces
alive, assign meaningful tags for an easier management,
and later join any of their own namespaces.
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <security/pam_appl.h> header file. */
#define HAVE_SECURITY_PAM_APPL_H 1
/* Define to 1 if you have the <security/pam_modules.h> header file. */
#define HAVE_SECURITY_PAM_MODULES_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcmp' function. */
#define HAVE_STRCMP 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <syslog.h> header file. */
#define HAVE_SYSLOG_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "libpam-net"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "info@v2.cs.unibo.it"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libpam-net"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libpam-net 0.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libpam-net"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.1"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.1"
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([libpam-net], [0.1], [info@v2.cs.unibo.it])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AC_CONFIG_SRCDIR([pam_newnet.c])
AC_CONFIG_HEADERS([config.h])
CFLAGS="$CFLAGS -Wall"
AC_ENABLE_SHARED(yes)
AC_ENABLE_STATIC(no)
AC_ARG_WITH([libsecuritydir],
[AS_HELP_STRING([--with-libsecuritydir],
[Directory for PAM modules, pass /lib/security for live install])],
[], [with_libsecuritydir='$(libdir)/security'])
AC_SUBST([libsecuritydir], [$with_libsecuritydir])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
LT_INIT
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h syslog.h])
AC_CHECK_HEADERS([security/pam_modules.h security/pam_appl.h],
[],
[AC_MSG_ERROR([missing lbpam0g header])])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CHECK_FUNCS([strcmp])
AC_OUTPUT([Makefile])
/*
* pam_net_common.
* Copyright (C) 2016 Renzo Davoli, Eduard Caizer University of Bologna
*
* pam_net common code.
*
* Cado is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <grp.h>
#include <pwd.h>
/* check if "user" belongs to "group" */
int checkgroup(const char *user, const char *group) {
struct passwd *pw=getpwnam(user);
int ngroups=0;
if (pw == NULL) return -1;
if (getgrouplist(user, pw->pw_gid, NULL, &ngroups) < 0) {
gid_t gids[ngroups];
if (getgrouplist(user, pw->pw_gid, gids, &ngroups) == ngroups) {
struct group *grp;
int i;
while ((grp=getgrent()) != NULL) {
for (i=0; i<ngroups; i++) {
if (grp->gr_gid == gids[i] && strcmp(grp->gr_name,group) == 0) {
endgrent();
return 1;
}
}
}
endgrent();
return 0;
}
}
return -1;
}
#ifndef PAM_NET_COMMON_H
#define PAM_NET_COMMON_H
/* check if "user" belongs to "group" */
/* 0=NO 1=YES -1=error */
int checkgroup(const char *user, const char *group);
#endif //PAM_NET_COMMON_H
.TH PAM_NEWNET 8 "August 17, 2016" "VirtualSquare Labs"
.SH "NAME"
pam_newnet \- create a new network namespace at login
.SH "SYNOPSIS"
\fBpam_newnet\&.so\fR
.SH DESCRIPTION
The pam_newnet PAM module creates a new network namespace at login for users in the \fInewnet\fR group.
Users in the newnet group can log-in through a
network connection (e.g. by ssh) but their processes cannot communicate
(the only interface they can see is the localhost of the namespace created
at login time.
Networking can take place just between processes of the same
session).
When pam_newnet is used together with a specific \fBcado(1)\fR configuration
users can configure their own networking services. (see https://github.com/rd235/cado)
The nsutils tools, and more specfically \fBnetnsjoin(1)\fR, allow users to
assign placeholders to keep namespaces alive, assign meaningful tags for an easier management,
and later join any of their own namespaces (see https://github.com/rd235/nsutils)
.SH "RETURN VALUES"
.PP
PAM_IGNORE
.RS 4
User does not belong to the \fInewnet\fR group\&.
.RE
.PP
PAM_ABORT
.RS 4
Error in retrieving the user id or in the namespace creation\&.
.RE
.PP
PAM_SUCCESS
.RS 4
Success\&.
.RE
.SH "EXAMPLES"
.PP
Add the following line to
/etc/pam\&.d/sshd
or /etc/pam\&.d/login
.sp
.RS 8
session required pam_newnet.so
.RE
.sp
.SH "SEE ALSO"
.PP
\fBpam.conf\fR(5),
\fBpam.d\fR(5),
\fBpam\fR(7)
.SH "AUTHOR"
.PP
pam_newnet was written by Renzo Davoli and Eduard Caizer, University of Bologna
/*
* pam_newnet.
* Copyright (C) 2016 Renzo Davoli, Eduard Caizer University of Bologna
*
* pam_newnet module
* create a new network namespace at each login
* (for users belonging to the "newnet" group)
*
* Cado is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <sched.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <pam_net_checkgroup.h>
/**
* init_log: log initialization with the given name
*/
void init_log(const char * log_name)
{
setlogmask (LOG_UPTO (LOG_NOTICE));
openlog (log_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
}
/**
* end_log: closes the log previously initialized
*/
void end_log()
{
closelog ();
}
/*
* PAM entry point for session creation
*/
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
const char *user;
int rv;
int isnewnet;
init_log ("pam_newnet");
if ((rv=pam_get_user(pamh, &user, NULL) != PAM_SUCCESS)) {
syslog (LOG_ERR, "get user: %s", strerror(errno));
goto close_log_and_exit;
}
isnewnet = checkgroup(user, "newnet");
if (isnewnet > 0) {
if (unshare(CLONE_NEWNET) < 0) {
syslog (LOG_ERR, "Failed to create a new netns: %s", strerror(errno));
goto close_log_and_abort;
}
} else
rv=PAM_IGNORE;
close_log_and_exit:
end_log();
return rv;
close_log_and_abort:
rv = PAM_ABORT;
end_log();
return rv;
}
/*
* PAM entry point for session cleanup
*/
int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
return(PAM_IGNORE);
}
.TH PAM_USERNET 8 "August 17, 2016" "VirtualSquare Labs"
.SH "NAME"
pam_usernet \- join the user own network namespace at login
.SH "SYNOPSIS"
\fBpam_usernet\&.so\fR
.SH DESCRIPTION
The pam_usernet PAM module allow each user in \fIusernet\fR group to have their own
network namespace.
If a network namespace having the same name as the
username exists, pam runs the user shell in that namespace. If such a
namespace does does not exist, it is created during the login process.
The system administrator can create a network
namespace for each user in \fIusernet\fR group. Each namespace must be named
after each username.
Users will get their own network namespace at
login.
When pam_usernet is used together with a specific \fBcado(1)\fR configuration
users can configure their own networking services. (see https://github.com/rd235/cado)
.SH "RETURN VALUES"
.PP
PAM_IGNORE
.RS 4
User does not belong to the \fIusernet\fR group\&.
.RE
.PP
PAM_ABORT
.RS 4
Error in retrieving the user id or in the namespace creation/joining\&.
.RE
.PP
PAM_SUCCESS
.RS 4
Success\&.
.RE
.SH "EXAMPLES"
.PP
Add the following line to
/etc/pam\&.d/sshd
or /etc/pam\&.d/login
.sp
.RS 8
session required pam_usernet.so
.RE
.sp
.SH "SEE ALSO"
.PP
\fBpam.conf\fR(5),
\fBpam.d\fR(5),
\fBpam\fR(7)
.SH "AUTHOR"
.PP
pam_usernet was written by Renzo Davoli and Eduard Caizer, University of Bologna
/*
* pam_usernet.
* Copyright (C) 2016 Renzo Davoli, Eduard Caizer University of Bologna
*
* pam_usernet module
* provide each user with their own network
* (for users belonging to the "usernet" group)
*
* Cado is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <pam_net_checkgroup.h>
#define NSDIR "/var/run/netns/"
/**
* init_log: log initialization with the given name
*/
void init_log(const char * log_name)
{
setlogmask (LOG_UPTO (LOG_NOTICE));
openlog (log_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
}
/**
* end_log: closes the log previously initialized
*/
void end_log()
{
closelog ();
}
/*
* PAM entry point for session creation
*/
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
const char *user;
int rv;
int isusernet;
init_log ("pam_usernet");
if ((rv=pam_get_user(pamh, &user, NULL) != PAM_SUCCESS)) {
syslog (LOG_ERR, "get user: %s", strerror(errno));
goto close_log_and_exit;
}
isusernet = checkgroup(user, "usernet");
if (isusernet > 0) {
int nsfd;
size_t ns_pathlen=sizeof(NSDIR)+strlen(user)+1;
char ns_path[ns_pathlen];
if (mkdir(NSDIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
if (errno != EEXIST) {
syslog (LOG_ERR, "cannot create netns dir %s: %s",NSDIR, strerror(errno));
goto close_log_and_abort;
}
}
if (mount("", NSDIR, "none", MS_SHARED | MS_REC, NULL)) {
if (errno != EINVAL) {
syslog (LOG_ERR, "mount --make-shared %s: %s",NSDIR, strerror(errno));
goto close_log_and_abort;
}
if (mount(NSDIR, NSDIR, "none", MS_BIND, NULL)) {
syslog (LOG_ERR, "mount --bind %s: %s",NSDIR, strerror(errno));
goto close_log_and_abort;
}
if (mount("", NSDIR, "none", MS_SHARED | MS_REC, NULL)) {
syslog (LOG_ERR, "mount --make-shared after bind %s: %s",NSDIR, strerror(errno));
goto close_log_and_abort;
}
}
snprintf(ns_path,ns_pathlen,NSDIR "%s",user);
if ((nsfd = open(ns_path, O_RDONLY)) < 0) {
if (errno == ENOENT) {
if ((nsfd = open(ns_path, O_RDONLY|O_CREAT|O_EXCL, 0)) < 0) {
syslog (LOG_ERR, "cannot create netns %s: %s",ns_path, strerror(errno));
goto close_log_and_abort;
}
close(nsfd);
if (unshare(CLONE_NEWNET) < 0) {
syslog (LOG_ERR, "Failed to create a new netns %s: %s",ns_path, strerror(errno));
goto close_log_and_abort;
}
if (mount("/proc/self/ns/net", ns_path, "none", MS_BIND, NULL) < 0) {
syslog (LOG_ERR, "mount /proc/self/ns/net -> %s failed: %s",ns_path, strerror(errno));
goto close_log_and_abort;
}
} else {
syslog (LOG_ERR, "netns open failed %s",ns_path);
goto close_log_and_abort;
}
} else {
if (setns(nsfd, CLONE_NEWNET) != 0) {
syslog (LOG_ERR, "cannot join netns %s: %s",ns_path, strerror(errno));
close(nsfd);
goto close_log_and_abort;
}
close(nsfd);
if (unshare(CLONE_NEWNS) < 0) {
syslog (LOG_ERR, "unshare failed: %s", strerror(errno));
goto close_log_and_abort;
}
}
} else
rv=PAM_IGNORE;
close_log_and_exit:
end_log();
return rv;
close_log_and_abort:
rv = PAM_ABORT;
end_log();
return rv;
}
/*
* PAM entry point for session cleanup
*/
int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
return(PAM_IGNORE);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment