\section{Bacula Auth Plugin Documentation}

\subsection{Overview}

Large companies are using central systems to handle authentication and
authorization data. It is very often based on LDAP databases. With one click,
the access to all software in the company can be granted or revoked. Today,
once a user can access the \texttt{bconsole.conf} file, Bacula doesn't require any
other form of authentication, basically, any user that have access to
\texttt{bconsole.conf} can interact with Bacula. It is mandatory to change the Console
resource and reload the Director to disable a user. The idea would be to let
the administrator the possibility to authenticate users with a central
database. For that, this document propose to design an
Authorization/Authentication mechanism based on a Director plugin. Once the
Console is properly connected, the plugin would be able to authenticate a given
user (password/user), and in a second time, would be also able to manage ACLs.

\subsection{Dictionary}

\begin{itemize}
\item [Authentication] is the act of proving an assertion, such as the identity
  of a computer system user.  In contrast with identification, the act of
  indicating a person or thing's identity, authentication is the process of
  verifying that identity. It might involve validating with personal password.
\item [Authorization] is the function of specifying access rights/privileges to
  resources, which is related to information security and computer security in
  general and to access control in particular.  More formally, "to authorize"
  is to define an access policy.
\item [Multi-factor authentication] (or MFA) is an authentication method in
  which a computer user is granted access only after successfully presenting
  two or more pieces of evidence (or factors) to an authentication mechanism:
  knowledge (something the user and only the user knows), possession (something
  the user and only the user has), and inherence (something the user and only
  the user is).
\item [Two-Factor Authentication] (or 2FA) is a subset of MFA described above
  with only two different factors, i.e. something they know, something they
  have, or something they are.
\end{itemize}

\subsection{Bacula DIR Plugin API}

To write a Bacula plugin, you create a dynamic shared object program (or dll on
Win32) with a particular name and two exported entry points, place it in the
Plugins Directory, which is defined in the \texttt{bacula-dir.conf} file in the
\textbf{Director} resource, and when the Director starts, it will load all the
plugins that end with \texttt{-dir.so} (or \texttt{-dir.dll} on Win32) found
in that directory.

\subsubsection{Loading Plugins}

Once the Director loads the plugins, it asks the dynamic loader for the two
entry points (\texttt{loadPlugin} and \texttt{unloadPlugin}) then calls the
\texttt{loadPlugin} entry point (see below). Bacula passes information to the
plugin through this call and it gets back information that it needs to use the
plugin. Later, Bacula will call particular functions that are defined by the
loadPlugin interface. When Bacula is finished with the plugin (when Bacula is
going to exit), it will call the unloadPlugin entry point.

\smallskip{}

The two entry points are:

\begin{verbatim}
bRC loadPlugin(bDirInfo *lbinfo, bDirFuncs *lbfuncs, pDirInfo **pinfo, pDirFuncs **pfuncs)
\end{verbatim}

and

\begin{verbatim}
bRC unloadPlugin()
\end{verbatim}

both these external entry points to the shared object are defined as C entry
points to avoid name mangling complications with C++. However, the shared
object can actually be written in any language (preferably C or C++) providing
that it follows C language calling conventions.

The definitions for \texttt{bRC} and the arguments are \texttt{src/dird/dir\_plugins.h}
and so this header file needs to be included in your plugin. It along with
\texttt{src/lib/plugins.h} define basically the whole plugin interface.  Within
this header file, it includes the following files:

\begin{verbatim}
#include <sys/types.h>
#include "config.h"
#include "bc_types.h"
#include "lib/plugins.h"
\end{verbatim}

\subsubsection*{loadPlugin}

As previously mentioned, the \texttt{loadPlugin} entry point in the plugin is
called immediately after Bacula loads the plugin when the Director itself is
first starting. This entry point is only called once during the execution of
the Director. In calling the plugin, the first two arguments are information
from Bacula that is passed to the plugin, and the last two arguments are
information about the plugin that the plugin must return to Bacula. The call
is:

\begin{verbatim}
bRC loadPlugin(bDirInfo *lbinfo, bDirFuncs *lbfuncs, pDirInfo **pinfo, pDirFuncs **pfuncs)
\end{verbatim}

and the arguments are:

\begin{itemize}
\item [lbinfo] This is information about Bacula in general. Currently, the only
  value defined in the \texttt{bInfo} structure is the version, which is the
  Bacula plugin interface version, currently defined as 1.  The size is set to
  the byte size of the structure. The exact definition of the \texttt{bInfo} structure
  as of this writing is:

\begin{verbatim}
  typedef struct s_dirbaculaInfo {
    uint32_t size;
    uint32_t version;
  } bDirInfo;
\end{verbatim}

\item [lbfuncs] The \texttt{bFuncs} structure defines the callback entry points
  within Bacula that the plugin can use register events, get Bacula values, set
  Bacula values, and send messages to the Job output or debug output.  The
  exact definition as of this writing is:

\begin{verbatim}
  typedef struct s_dirbaculaFuncs {
    uint32_t size;
    uint32_t version;
    bRC (*registerBaculaEvents)(bpContext *ctx, ...);
    bRC (*getBaculaValue)(bpContext *ctx, brDirVariable var, void *value);
    bRC (*setBaculaValue)(bpContext *ctx, bwDirVariable var, void *value);
    bRC (*JobMessage)(bpContext *ctx, const char *file, int line,
                      int type, utime_t mtime, const char *fmt, ...);
    bRC (*DebugMessage)(bpContext *ctx, const char *file, int line,
                      int level, const char *fmt, ...);
   } bDirFuncs;
\end{verbatim}

  We will discuss these entry points and how to use them a bit later when
  describing the plugin code.

\item [pInfo] When the \texttt{loadPlugin} entry point is called, the plugin
  must initialize an information structure about the plugin and return a
  pointer to this structure to Bacula.  The exact definition as of this writing
  is:

\begin{verbatim}
  typedef struct s_dirpluginInfo {
    uint32_t size;
    uint32_t version;
    const char *plugin_magic;
    const char *plugin_license;
    const char *plugin_author;
    const char *plugin_date;
    const char *plugin_version;
    const char *plugin_description;
  } pDirInfo;
\end{verbatim}

  Where:
  \begin{itemize}
  \item [version] is the current Bacula defined plugin interface version, currently set to 1. If the interface
    version differs from the current version of Bacula, the plugin will not be run (not yet implemented).

    
  \item [plugin\_magic] is a pointer to the text string \texttt{DirPluginData} defined in \texttt{DIR\_PLUGIN\_MAGIC},
    a sort of sanity check. If this value is not specified, the plugin will not be run (not yet implemented).
  \item [plugin\_license] is a pointer to a text string that describes the plugin license. Bacula will only accept
    compatible licenses. The accepted licenses as of this writing are: "Bacula AGPLv3", "AGPLv3",
    "Bacula Systems(R) SA" and defined in \texttt{BPLUGIN\_LICENSE} compile time definition.
  \item [plugin\_author] is a pointer to the text name of the author of the plugin. This string can be anything
    but is generally the author’s name.
  \item [plugin\_date] is the pointer to a text string containing the date of the plugin. This string can be
    anything but is generally some human readable form of the date.
    
  \item [plugin\_version] is a pointer to a text string containing the version of the plugin. The contents are
    determined by the plugin writer.
  \item [plugin\_description] is a pointer to a text string describing what the plugin does. The contents are
    determined by the plugin writer.
  \end{itemize}

  The pInfo structure must be defined in static memory because Bacula does not copy it and may refer to the
  values at any time while the plugin is loaded. All values must be supplied or the plugin will not
  run (not yet implemented). All text strings must be either ASCII or UTF-8 strings that are terminated
  with a zero (\texttt{nul}) byte.

  
\item [pFuncs] When the \texttt{loadPlugin} entry point is called, the plugin must initialize an entry point structure
  about the plugin and return a pointer to this structure to Bacula. This structure contains pointer to each
  of the entry points that the plugin must (or will) provide for Bacula. When Bacula is actually running the
  plugin, it will call the defined entry points at particular times.
  The \texttt{pFuncs} structure must be defined in static memory because Bacula does not copy it and may refer to the
  values at any time while the plugin is loaded.

  \smallskip{}

  The exact definition as of this writing is:

\begin{verbatim}
  typedef struct s_dirpluginFuncs
  {
    uint32_t size;
    uint32_t version;
    bRC (*newPlugin)(bpContext *ctx);
    bRC (*freePlugin)(bpContext *ctx);
    bRC (*getPluginValue)(bpContext *ctx, pDirVariable var, void *value);
    bRC (*setPluginValue)(bpContext *ctx, pDirVariable var, void *value);
    bRC (*handlePluginEvent)(bpContext *ctx, bDirEvent *event, void *value);
    bRC (*getPluginAuthenticationData)(bpContext *ctx, const char *param, void **data);
    bRC (*getPluginAuthorizationData)(bpContext *ctx, const char *param, void **data);
  } pDirFuncs;
\end{verbatim}

  The details of the entry points will be presented in separate sections below. Where:
  \begin{itemize}
  \item [size] is the byte size of the structure.
  \item [version] is the plugin interface version currently set to 1 (defined in \texttt{DIR\_PLUGIN\_INTERFACE\_VERSION}).
  \end{itemize}
\end{itemize}

\subsubsection**{unloadPlugin}

As previously mentioned, the \texttt{unloadPlugin} entry point in the plugin is called just before a Director finish
execution. This entry point is responsible for releasing any resources allocated by plugin during \texttt{loadPlugin}.

\subsubsection{Plugin Entry Points}

This section will describe each of the entry points (subroutines) within the plugin that the plugin must
provide for Bacula, when they are called and their arguments. As noted above, pointers to these subroutines
are passed back to Bacula in the \texttt{pFuncs} structure when Bacula calls the \texttt{loadPlugin()} externally defined
entry point.

\subsubsection*{newPlugin}

This is the entry point that Bacula will call when a new \texttt{instance} of
the plugin is created. This typically happens at the beginning of any Job or Console
connection. If 10 Jobs are running simultaneously, there will be at least
10 instances of the plugin.

\smallskip{}

The \texttt{bpContext} structure will be passed to the plugin, and during this
call, if the plugin needs to have its private working storage that is
associated with the particular instance of the plugin, it should create it from
the heap (malloc the memory) and store a pointer to its private working storage
in the pContext variable.

\smallskip{}

\textbf{Note:} since Bacula is a multi-threaded program, you must not keep any
variable data in your plugin unless it is truly meant to apply globally to the
whole plugin. In addition, you must be aware that except the first and last
call to the plugin (\texttt{loadPlugin} and \texttt{unloadPlugin}) all the other calls will
be made by threads that correspond to a Bacula job. The \texttt{bpContext} that will
be passed for each thread will remain the same throughout the Job thus you can
keep your private Job specific data in it (\texttt{bContext}).

\begin{verbatim}
typedef struct s_bpContext {
  void *pContext; /* Plugin private context */
  void *bContext; /* Bacula private context */
} bpContext;
\end{verbatim}

This context pointer will be passed as the first argument to all the entry
points that Bacula calls within the plugin. Needless to say, the plugin should
not change the bContext variable, which is Bacula’s private context pointer for
this instance (Job) of this plugin.

\subsubsection*{freePlugin}

This entry point is called when the this instance of the plugin is no longer
needed (the Job/Console is ending), and the plugin should release all memory it may
have allocated for this particular instance i.e. the \texttt{pContext}.  This is
not the final termination of the plugin signaled by a call to
\texttt{unloadPlugin}. Any other instances (Job) will continue to run, and the entry
point newPlugin may be called again if other jobs start.

\subsubsection*{getPluginValue}

Bacula will call this entry point to get a value from the plugin. This entry
point is currently not called.

\subsubsection*{setPluginValue}

Bacula will call this entry point to set a value in the plugin. This entry
point is currently not called.

\subsubsection*{handlePluginEvent}

This entry point is called when Bacula encounters certain events. This is, in
fact, the main way that most plugins get control when a Job/Console runs and how they
know what is happening in the job. It can be likened to the RunScript feature
that calls external programs and scripts. When the plugin is called, Bacula
passes it the pointer to an event structure (\texttt{bDirEvent}), which currently has
one item, the \texttt{eventType}:

\begin{verbatim}
typedef struct s_bDirEvent {
  uint32_t eventType;
} bDirEvent;
\end{verbatim}

which defines what event has been triggered, and for each event, Bacula will
pass a pointer to a value associated with that event. If no value is associated
with a particular event, Bacula will pass a NULL pointer, so the plugin must be
careful to always check value pointer prior to dereferencing it.

\smallskip{}

The current list of events are:

\begin{verbatim}
typedef enum {
  bDirEventJobStart                    = 1,
  bDirEventJobEnd                      = 2,
  bDirEventJobInit                     = 3,
  bDirEventJobRun                      = 4,
  bDirEventVolumePurged                = 5,
  bDirEventNewVolume                   = 6,
  bDirEventNeedVolume                  = 7,
  bDirEventVolumeFull                  = 8,
  bDirEventRecyle                      = 9,
  bDirEventGetScratch                  = 10,
  bDirEventAuthenticationQuestion      = 1000,  // *value is a bDirAuthValue struct allocated by Dir
                                                // to get return value from
  bDirEventAuthenticationResponse      = 1001,  // *value is a char* to user response
  bDirEventAuthenticate                = 1002,  // return bRC_OK when authenticate is successful
} bDirEventsType;
\end{verbatim}

Most of the above are self-explanatory.

\begin{itemize}
\item [bEventJobStart] is called whenever a Job starts.
\item [bEventJobEnd] is called whenever a Job ends. No value is passed.
\item [bDirEventJobInit] is called when ... .
\item [bDirEventJobRun] is called when ... .
\item [bDirEventVolumePurged] is called when ... .
\item [bDirEventAuthenticationQuestion] is called for authentication plugin (see description below - BPAM)
  whenever Director wants to get the next question in user (bconsole) authentication session.
  A \textbf{value} is a pointer to \texttt{bDirAuthValue}. Plugin should return a single \texttt{bDirAuthData} structure
  (described below) in this value.
\item [bDirEventAuthenticationResponse] is called for authentication plugin to forward user response for
  the last handled authentication question.
  A value is a pointer to \texttt{bDirAuthValue}. Plugin will get a response in \texttt{value->response}
  (as a \texttt{char*}, a \texttt{nul} terminated string) and \texttt{value->seqdata} copied from authentication question.
  Plugin should return \texttt{bRC\_OK} if Director can proceed to the next step.
\item [bDirEventAuthenticate] is called for authentication plugin whenever Director asks a plugin to
  final authenticate result where \texttt{bRC\_OK} when successful and \texttt{bRC\_Error} when error.
\end{itemize}

During each of the above calls, the plugin receives either no specific value or
only one value, which in some cases may not be sufficient. However, knowing the
context of the event, the plugin can call back to the Bacula entry points it
was passed during the loadPlugin call and get to a number of Bacula
variables. (at the current time few Bacula variables are implemented, but it
easily extended at a future time and as needs require).

\subsection{Bacula Pluggable Authentication Modules API Framework \textbf{BPAM}]}

Starting from Bacula Enterprise 12.6 new user authentication API framework is
introduced which allows to configure a different authentication mechanisms
(user credentials verification) using a dedicated Director plugins and Console
resource configuration. This is called \textbf{BPAM} - \textbf{Bacula Pluggable
Authentication Modules}.

\smallskip{}

The new framework support standard \textbf{user/password} and \textbf{MFA}
authentication schemes which are fully driven by external plugins. On the
client side \texttt{bconsole} when noticed will perform user interaction to collect
required credentials. Bacula will still support all previous authentication
schemas including \texttt{CRAM-MD5} and \texttt{TLS}. You can even configure \textbf{TLS
Authentication} together with new BPAM authentication raising required security
level. BPAM authentication is available for named Console resources only.

The BPAM framework extend a standard Director Plugin API architecture with the following plugin
entry points:

\begin{verbatim}
bRC getPluginAuthenticationData(bpContext *ctx, const char *param, void **data);
bRC getPluginAuthorizationData(bpContext *ctx, const char *param, void **data);
\end{verbatim}

and plugin events mentioned above:

\begin{verbatim}
...
  bDirEventAuthenticationQuestion      = 1000,     // *value is a bDirAuthValue struct allocated by Dir
                                                   // to get return value from
  bDirEventAuthenticationResponse      = 1001,     // *value is a char* to user response
  bDirEventAuthenticate                = 1002,     // return bRC_OK when authenticate is successful
...
\end{verbatim}

\subsubsection{BPAM Plugin registration}

BPAM assumes that any authentication or authorization workflows manages a very
sensitive information (user credentials or permissions) which must be handled
with extreme care, i.e. it should not be visible outside the selected
plugin. This makes a clear break in general Bacula's plugin workflow design
where every event is forwarded to every plugin until one of them raise event
handling is done.  This kind of event workflow handling can leads to unexpected
user credentials data breach which is unacceptable.

Before a plugin will get authentication or authorization requests it has to
register its services with \texttt{getPluginAuthenticationData()} or
\texttt{getPluginAuthorizationData()} plugin entry points.  Director will call this
plugin's functions (if defined in \texttt{pDirFuncs} structure) on every new bconsole
connection for selected plugin only when appropriate \texttt{Console} resource is
configured (see below for more info).

\begin{verbatim}
Console {
  Name = "bpamauthconsole"
  Password = "xxx"

  # New directives
  Authentication Plugin = "<plugin>:<optional parameters>"
  Authorization Plugin = "<plugin>:<optional parameters>"       # not implemented yet!
  ...
}
\end{verbatim}

\subsubsection*{bacula-dir.conf - Console resource configuration}

The entry point \texttt{getPluginAuthenticationData()} is called when Director
needs to forward authentication to selected \texttt{<plugin>} which is defined with
\texttt{Authentication Plugin = ...} parameter. The name \texttt{<plugin>} has to match the
filename of the Director plugin (without a \texttt{-dir.*} suffix). No other plugin
will be bothered. The function takes the following parameters:

\begin{itemize}
\item [param] is a \texttt{nul} terminated string defined on the right side of the parameter, including plugin
  name and optional plugin parameters.
\item [data] is a pointer to \texttt{bDirAuthenticationRegister} struct pointer (\texttt{bDirAuthenticationRegister**})
  which should be filled as a return value for plugin data registration.
\end{itemize}

The \texttt{bDirAuthenticationRegister} structure is defined as:

\begin{verbatim}
typedef struct s_bDirAuthenticationRegister {
  const char * name;
  const char * welcome;
  const uint32_t num;
  const bDirAuthenticationData *data;
  const int32_t nsTTL;
} bDirAuthenticationRegister;
\end{verbatim}

which together with \texttt{bDirAuthenticationData} structure will define a full authentication workflow managed
by this plugin. Where parameters are:

\begin{itemize}
  
\item [name] is a name of the authentication plugin and should match the \texttt{<plugin>} string in Console
  resource configuration.
\item [welcome] is an optional authentication welcome string which will be displayed before first
  authentication question.
\item [num] is a number of elements in authentication operation data table pointed by \texttt{data} below.
\item [data] the pointer to the authentication operation data (\texttt{bDirAuthenticationData}) table, the
  first element, with a number of elements defined in \texttt{num} above.
\item [nsTTL] currently unimplemented, for future usage.
\end{itemize}

The structure \texttt{bDirAuthenticationData} is defines as:

\begin{verbatim}
typedef struct s_bDirAuthenticationData {
  const bDirAuthenticationOperation operation;
  const char * question;
  const uint32_t seqdata;
} bDirAuthenticationData;
\end{verbatim}

where:

\begin{itemize}
\item [operation] a single authentication step (operation) which should be performed by Director + bconsole
  application. The list of possible operations include: display user the message, get login from user, get
  password from user, etc.
\item [question] the \texttt{nul} terminated string to display to the user during credentials collection.
\item [seqdata] 32 bit integer for full plugin use; this value will be added to
  the user response send to the plugin.
\end{itemize}

Both \texttt{bDirAuthenticationRegister} and \texttt{bDirAuthenticationData}
structures could be a statically compiled data or assembled in
runtime. Director will read data from it and never change. BPAM defines the
following authentication operations:

\begin{verbatim}
typedef enum {
  bDirAuthenticationOperationPlugin,
  bDirAuthenticationOperationPluginAll,
  bDirAuthenticationOperationMessage,
  bDirAuthenticationOperationPlain,
  bDirAuthenticationOperationLogin = bDirAuthenticationOperationPlain,
  bDirAuthenticationOperationHidden,
  bDirAuthenticationOperationPassword = bDirAuthenticationOperationHidden,
  bDirAuthenticationOperationAuthenticate,
} bDirAuthenticationOperation;
\end{verbatim}

\begin{itemize}
\item [bDirAuthenticationOperationPlugin] Director will get the current operation from the plugin using
  \texttt{bDirEventAuthenticationQuestion} plugin event, then it should execute the operation returned.
\item [bDirAuthenticationOperationPluginAll] Director will get all authentication operations from the plugin with
  \texttt{bDirEventAuthenticationQuestion} plugin events loop.
\item [bDirAuthenticationOperationMessage] Director will ask bconsole to display a message pointed by
  \texttt{bDirAuthenticationData.question} and will proceed to the next operation in the list.
\item [bDirAuthenticationOperationPlain] (alias \texttt{bDirAuthenticationOperationLogin}) Director will ask bconsole
  to display a message pointed by \texttt{bDirAuthenticationData.question}, then get plain input visible to the user
  and proceed to the next operation in the list.
\item [bDirAuthenticationOperationHidden] (alias \texttt{bDirAuthenticationOperationPassword}) Director will ask bconsole
  to display a message pointed by \texttt{bDirAuthenticationData.question}, then get hidden (*) input invisible to the
  user, i.e. a password, and proceed to the next operation in the list.
\item [bDirAuthenticationOperationAuthenticate] tells Director to finish all user interaction and asks plugin for
  authentication using \texttt{bDirEventAuthenticate} plugin event.
\end{itemize}

Every authentication operation of \texttt{bDirAuthenticationOperationPlain} and
\texttt{bDirAuthenticationOperationHidden} will return with an user response
data which will be forwarded directly to plugin using
\texttt{bDirEventAuthenticationResponse} plugin event. No other operations will
do that. During this event a plugin is responsible to save user response as it
won't be saved by Director and lost forever. These collected responses should
be used for final user authenticate. The response is passed to plugin with
\texttt{bDirAuthValue.response} variable and filled with \texttt{seqdata} value from current
question operation.

\smallskip{}

As soon as the number of questions (\textbf{authenticate operations}) defined during registration (the
\texttt{bDirAuthenticationRegister.num} value) comes to the end or one of the operation executed is
\texttt{bDirAuthenticationOperationAuthenticate} then Director will stop asking a user more questions
and will generate the \texttt{bDirEventAuthenticate} plugin event. During this event handling a plugin
is responsible to verify all responses and perform user authentication.

\smallskip{}

There is a special operation in BPAM:
\texttt{bDirAuthenticationOperationPluginAll} which tells Director to asks in
runtime the plugin for every single operation to execute. This allow to build a
dynamic authentication procedure with a variable number of questions and
challenges. In this case a plugin is responsible to explicitly finish a
workflow with \texttt{bDirAuthenticationOperationAuthenticate}.

\bimageH[0.9\linewidth]
    {bpamflow2}{BPAM General Workflow}{fig:bpamworkflow}

You can find below some examples for above structures.

\begin{verbatim}
static bDirAuthenticationData testquestions0[] =
{
  // operation; question; data;
  {bDirAuthenticationOperationLogin, "Username:", 0},
  {bDirAuthenticationOperationPassword, "Password:", 1},
};

static bDirAuthenticationRegister testregister0 =
{
  .name = "PLUGIN_NAME",
  .welcome = "This is a test authplugin API Plugin. Use root/root to login.",
  .num = 2,
  .data = testquestions0,
  .nsTTL = 0,
};
\end{verbatim}

Above you can find a simplest user/password authentication scheme with plain (visible) user input
and hidden (invisible) password input.

\begin{verbatim}
static bDirAuthenticationData testquestions1[] =
{
  // operation; question; data;
  {bDirAuthenticationOperationLogin, "Username:", 0},
  {bDirAuthenticationOperationPlugin, NULL, 1},
  {bDirAuthenticationOperationPlain, "Response:", 2},
};

static bDirAuthenticationData testquestions1_msg =
{
  // operation; question; data;
  bDirAuthenticationOperationMessage, NULL, 0
};

static bDirAuthenticationRegister testregister1 =
{
  .name = "PLUGIN_NAME",
  .welcome = "This is a test authplugin API Plugin. Use bacula username to login.",
  .num = 3,
  .data = testquestions1,
  .nsTTL = 0,
};
\end{verbatim}

Above you can find a simplest MFA (\textbf{challenge-response}) authentication
scheme with out of band authentication verification. In this example a plugin
will display a message prepared in runtime by plugin.
