Skip to content

Commit

Permalink
pam_exec_add_bareos_user: adapted for Bareos >= 19.2.4
Browse files Browse the repository at this point in the history
Previos versions of Bareos did require that a Bareos user configuration has set a password,
even if this password isn't used (because the user authenticates against PAM).

Bareos >= 19.2.4 had done cleanups to the configuration.
For the "console" resource, nothing have changed, except that they can no longer be used for PAM.
The "user" resources do no longer contain password and TLS directives.
A PAM user now has to be defined as Bareos "user". Previosly "user" and "console" have been possible.
Also the director now offers the ".users" command, to get the list of users.

This patch added the pam_exec_add_bareos_user.py script to this.
  • Loading branch information
joergsteffens committed Jan 15, 2020
1 parent 2405a3b commit f2c03e6
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 47 deletions.
20 changes: 11 additions & 9 deletions misc/bareos_pam_integration/README.rst
Expand Up @@ -6,9 +6,9 @@ provide dynamic authentication support for applications and services in a Linux

PAM authentication is included since Bareos >= 18.2, see https://docs.bareos.org/master/TasksAndConcepts/PAM.html#configuration

However, this support does only the include the authentication.
However, this support offers the authentication.
That means, the user must be known in the backend system used by PAM (:file:`/etc/passwd`, LDAP or ...)
**and** the user/console has to exist in the Bareos Director.
**and** the user has to exist in the Bareos Director.

The PAM implementation of Bareos is only used for authentication of console connections.
Console access is only provided by the Bareos Director.
Expand All @@ -23,16 +23,16 @@ The Bareos Director uses the service name **bareos**.
The corresponding configuration file is :file:`/etc/pam.d/bareos`.
If this file does not exist, PAM uses the fallback file :file:`/etc/pam.d/other`.

Often PAM is offered by system services, meaning the calling process has **root** priviliges.
The Bareos Director on Linux runs as user **bareos**,
Often PAM is offered by system services, meaning the calling process has *root* priviliges.
The Bareos Director on Linux runs as user *bareos*,
therefore by default it might not offer all required functionality.

Known Limitations of PAM Modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:pam_unix:
When authenticating with pam_unix, it tries to read system files,
also the file :file:`/etc/shadow`.
including the file :file:`/etc/shadow`.
By default, the user *bareos* do not have the permission to read this file.
If this functionality is required, adapt the priviliges accordingly
(e.g. add the user bareos to the group owning the file).
Expand Down Expand Up @@ -110,7 +110,7 @@ Reuse your existing PamConsole or create an additional one::
}

As PHP does not yet support TLS-PSK, the setting ``TLS Enable = no`` is required.
For security, use this only, if the Bareos Director and Bareos WebUI run on the same host.
Therefore it is advised to run the Bareos Director and Bareos WebUI on the same host.

You may want to add following section to your :file:`/etc/bareos-webui/directors.ini`::

Expand Down Expand Up @@ -138,6 +138,8 @@ The PAM script ``pam_exec_add_bareos_user.py`` can circumvent this.

It can be integrated into the Bareos PAM configuration by ``pam_exec`` .

This version of the script requires at least Bareos >= 19.2.4.

Installation
^^^^^^^^^^^^

Expand All @@ -152,7 +154,7 @@ Create a Bareos console for user pam-adduser:
Console {
Name = "pam-adduser"
Password = "secret"
CommandACL = ".api", ".consoles", ".profiles", "configure"
CommandACL = ".api", ".profiles", ".users", "configure", "version"
TlsEnable = no
}

Expand All @@ -163,9 +165,9 @@ This example uses pam_ldap to authenticate.
::

auth requisite pam_ldap.so
auth [default=ignore] pam_exec.so quiet /usr/local/bin/pam_exec_add_bareos_user.py --name pam-adduser --password secret --profile webui-admin
auth [default=ignore] pam_exec.so /usr/local/bin/pam_exec_add_bareos_user.py --name pam-adduser --password secret --profile webui-admin

Make sure, an unsuccessful authentication ends before pam_exec.so.
In this example, this is done by the *requisite* keyword (when not successful, stop executing the PAM stack).

Using this, a user that successfully authenticates against LDAP, will be created as Bareos console/user with ACLs as defined in profile *webui-admin*.
Using this, a user that successfully authenticates against LDAP, will be created as Bareos user with ACLs as defined in profile *webui-admin*.
89 changes: 51 additions & 38 deletions misc/bareos_pam_integration/pam_exec_add_bareos_user.py
@@ -1,8 +1,16 @@
#!/usr/bin/env python

"""
This script is intended to be integrated with pam_exec into the Linux authentication process.
It can be used to auto-create users that do already exists as PAM users as Bareos users.
Requires Bareos >= 19.2.4.
"""

from __future__ import print_function
import argparse
import bareos.bsock
import bareos.exceptions
import logging
import os
from pprint import pformat
Expand All @@ -11,12 +19,30 @@
import sys


def get_random_string(length=16, chars=string.ascii_letters + string.digits):
return ''.join(random.choice(chars) for x in range(length))
def check_requirements(director):
min_version = "19.2.4"
logger = logging.getLogger()
logger.debug("checking requirements: start")
try:
result = director.call('.users')
except (bareos.exceptions.Error) as e:
logger.error('The .users command is required, but not available: {}'.format(str(e)))
sys.exit(1)
try:
result = director.call('version')
except (bareos.exceptions.Error) as e:
logger.error('The version command is required, but not available: {}'.format(str(e)))
sys.exit(1)
version = result['version']['version']
if version < min_version:
logger.error('Bareos has version {}. However Bareos >= {} is required.'.format(version, min_version))
sys.exit(1)
logger.debug("checking requirements: finish")


def get_user_names(director):
result = director.call('.consoles')['consoles']
users = [job['name'] for job in result]
result = director.call('.users')['users']
users = [i['name'] for i in result]
return users


Expand All @@ -25,11 +51,13 @@ def does_user_exists(director, username):


def add_user(director, username, profile):
# The password should not be used,
# however is required to create a new console.
# Therefore we set a random password.
password = 'PAM_WORKAROUND_' + get_random_string()
result = director.call('configure add console="{username}" password="{password}" profile="{profile}"'.format(username = username, password = password, profile = profile))

result = director.call(
'configure add user="{username}" profile="{profile}"'.format(
username = username,
profile = profile
)
)

try:
if result['configure']['add']['name'] != username:
Expand All @@ -51,22 +79,13 @@ def add_user(director, username, profile):


def getArguments():
parser = argparse.ArgumentParser(description='Console to Bareos Director.')
parser.add_argument('-d', '--debug', action='store_true',
help="enable debugging output")
parser.add_argument('--name', default="*UserAgent*",
help="use this to access a specific Bareos director named console. Otherwise it connects to the default console (\"*UserAgent*\")")
parser.add_argument('--password', '-p', required=True,
help="password to authenticate to a Bareos Director console")
parser.add_argument('--port', default=9101,
help="Bareos Director network port")
parser.add_argument('--dirname', help="Bareos Director name")
parser.add_argument('--profile', default='webui-admin',
help="Bareos Profile for the newly generated user")
parser.add_argument('--address', default="localhost",
help="Bareos Director network address")
parser.add_argument('--username', help="Name of the user to add. Default: content of ENV(PAM_USER)")
args = parser.parse_args()
argparser = argparse.ArgumentParser(description='Add a PAM user to Bareos Director.')
argparser.add_argument('-d', '--debug', action='store_true', help="enable debugging output")
bareos.bsock.DirectorConsole.argparser_add_default_command_line_arguments(argparser)
argparser.add_argument('--username', help="Name of the user to add. Default: content of ENV(PAM_USER)")
argparser.add_argument('--profile', default='webui-admin',
help="Bareos Profile for the newly generated user")
args = argparser.parse_args()
return args


Expand All @@ -79,24 +98,18 @@ def getArguments():
if args.debug:
logger.setLevel(logging.DEBUG)

bareos_args = bareos.bsock.DirectorConsole.argparser_get_bareos_parameter(args)
logger.debug('options: %s' % (bareos_args))

try:
options = ['address', 'port', 'dirname', 'name']
parameter = {}
for i in options:
if hasattr(args, i) and getattr(args, i) != None:
logger.debug("%s: %s" % (i, getattr(args, i)))
parameter[i] = getattr(args, i)
else:
logger.debug('%s: ""' % (i))
logger.debug('options: %s' % (parameter))
password = bareos.bsock.Password(args.password)
parameter['password'] = password
director = bareos.bsock.DirectorConsoleJson(**parameter)
except RuntimeError as e:
director = bareos.bsock.DirectorConsoleJson(**bareos_args)
except (bareos.exceptions.Error) as e:
print(str(e))
sys.exit(1)
logger.debug("authentication successful")

check_requirements(director)

username = os.getenv('PAM_USER', args.username)
profile = getattr(args, 'profile', 'webui-admin')

Expand Down

0 comments on commit f2c03e6

Please sign in to comment.