diff options
Diffstat (limited to 'doc/configuration')
-rw-r--r-- | doc/configuration/acct_type.rst | 71 | ||||
-rw-r--r-- | doc/configuration/autz_type.rst | 88 | ||||
-rw-r--r-- | doc/configuration/configurable_failover.rst | 476 | ||||
-rw-r--r-- | doc/configuration/dynamic_home_servers.md | 238 | ||||
-rw-r--r-- | doc/configuration/load_balance.rst | 172 | ||||
-rw-r--r-- | doc/configuration/post_auth_type | 44 | ||||
-rw-r--r-- | doc/configuration/session_type | 10 | ||||
-rw-r--r-- | doc/configuration/simultaneous_use | 173 | ||||
-rw-r--r-- | doc/configuration/snmp | 58 | ||||
-rw-r--r-- | doc/configuration/variables.rst | 151 |
10 files changed, 1481 insertions, 0 deletions
diff --git a/doc/configuration/acct_type.rst b/doc/configuration/acct_type.rst new file mode 100644 index 0000000..e8abff4 --- /dev/null +++ b/doc/configuration/acct_type.rst @@ -0,0 +1,71 @@ +Acct-Type +========= + +FreeRADIUS supports the Acct-Type attribute to select between +accounting methods based on arbitrary attribute/value pairs contained +in an accounting packet. Its use follows the same general configuration +syntax as Auth-Type and Autz-Type. The main difference in configuration +between Acct-Type and Auth/Autz-Type lies in where the Acct-Type +method is assigned. With Auth/Autz-Type, the method is typically +assigned in the 'users' file. The 'users' file, naturally, is not +processed during the handling of the accounting {} section. However, +part of the default files {} module is the 'acct_users' file, which +serves the same purpose as the 'users' file, but applies to accounting +packets. + +For example, a server administrator is responsible for handling the +accounting data for two different realms, foo.com and bar.com, and +wishes to use different instances of the SQL module for each. In +addition, there is one RADIUS client sending accounting data that is +to be logged only to a specific detail file. Everything else should +use a third SQL instance. + +The acct_users file would look something like this:: + + DEFAULT Realm == "foo.com", Acct-Type := "SQLFOO" + + DEFAULT Realm == "bar.com", Acct-Type := "SQLBAR" + + DEFAULT Client-IP-Address == "10.0.0.1", Acct-Type := "OTHERNAS" + +And in radiusd.conf:: + + $INCLUDE ${confdir}/sql0.conf # Instance named 'sql0'. + $INCLUDE ${confdir}/sql1.conf # Instance named 'sql1'. + $INCLUDE ${confdir}/sql2.conf # Instance named 'sql2'. + + detail othernas { + filename = ${radacctdir}/10.0.0.1/detail-%Y%m%d + } + + preacct { + suffix # Add the Realm A/V pair. + files # Add the Acct-Type A/V pair based on the Realm A/V pair. + } + + accounting { + + # If Acct-Type is SQLFOO use the 'sql1' instance of the SQL module. + + Acct-Type SQLFOO { + sql1 + } + + # If Acct-Type is SQLBAR, use the 'sql2' instance of the SQL module. + + Acct-Type SQLBAR { + sql2 + } + + # If Acct-Type is OTHERNAS, use the 'othernas' instance of the detail + # module + + Acct-Type OTHERNAS { + othernas + } + + # If we've made it this far, we haven't matched an Acct-Type, so use + # the sql0 instance. + + sql0 + } diff --git a/doc/configuration/autz_type.rst b/doc/configuration/autz_type.rst new file mode 100644 index 0000000..a91e4e5 --- /dev/null +++ b/doc/configuration/autz_type.rst @@ -0,0 +1,88 @@ +Autz-Type +========= + +Like Auth-Type for authentication method selection freeradius also +supports the Autz-Type to select between authorization methods. The only +problem is that authorization is the first thing to be called when an +authentication request is handled. As a result we first have to call the +authorize section without checking for Autz-Type. After that we check for +Autz-Type and if it exists we call the corresponding subsection in the +authorize section. In other words the authorize section in radiusd.conf +should look like this:: + + authorize{ + suffix + preprocess + # whatever other authorize modules here + Autz-Type Ldap{ + ldap + } + Autz-Type SQL{ + sql + } + files + } + +What happens is that the first time the authorize section is examined the +suffix, preprocess and files modules are executed. If Autz-Type is set +after that the server core checks for any matching Autz-Type subsection. +If one is found it is called. The users file should look something +like this:: + + DEFAULT Called-Station-Id == "123456789", Autz-Type := Ldap + + DEFAULT Realm == "other.example.com", Autz-Type := SQL + +Autz-Type could also be used to select between multiple instances of +a module (ie sql or ldap) which have been configured differently. For +example based on the user realm different ldap servers (belonging to +different companies) could be queried. If Auth-Type was also set then we +could do both Authentication and Authorization with the user databases +belonging to other companies. In detail: + +radiusd.conf:: + + authenticate{ + Auth-Type customer1{ + ldap1 + } + Auth-Type customer2{ + ldap2 + } + } + + authorize{ + preprocess + suffix + Autz-Type customer1{ + ldap1 + } + Autz-Type customer2{ + ldap2 + } + files + } + +The users file:: + + DEFAULT Realm == "customer1", Autz-Type := customer1, Auth-Type := customer1 + + DEFAULT Realm == "customer2", Autz-Type := customer2, Auth-Type := customer2 + + +Apart from Autz-Type the server also supports the use of +Acct-Type, Session-Type and Post-Auth-Type for the corresponding sections. +The corresponding section names in the radiusd.conf file are the same. So for example: + +users file:: + + DEFAULT Called-Station-Id == "236473", Session-Type := SQL + +radiusd.conf:: + + session { + radutmp + Session-Type SQL { + sql + } + } diff --git a/doc/configuration/configurable_failover.rst b/doc/configuration/configurable_failover.rst new file mode 100644 index 0000000..4e21335 --- /dev/null +++ b/doc/configuration/configurable_failover.rst @@ -0,0 +1,476 @@ +Configurable Module Fail Over +============================= + +Before configurable module failover, we had this kind of entry in +``radiusd.conf``: + +:: + + #--- + authorize { + preprocess + files + } + #--- + +This entry instructed the ``authorize`` section to first process the +request through the ``preprocess`` module, and if that returned success, +to process it through ``files`` module. If that sequence returned +success, then the ``authorize`` stage itself would then return success. +Processing was strictly linear and if one module failed, the whole +section would fail immediately. + +Configurable failover provides more flexibility. It takes advantage +of the tree structure of radiusd.conf to support a configuration +language that allows you to ``group`` modules that should work together +in ways other than simple lists. You can control the flow of any +stage (e.g. ``authorize``) to fit your needs, without touching C code, +just by altering radiusd.conf. + +This configurable fail-over has a convenient short-hand, too. +Administrators commonly want to say things like "try SQL1, if it's +down, try SQL2, otherwise drop the request." + +For example: + +:: + + #--- + modules { + sql sql1 { + # configuration to connect to SQL database one + } + sql sql2 { + # configuration to connect to SQL database two + } + always handled { + rcode = handled + } + } + + # Handle accounting packets + accounting { + detail # always log to detail, stopping if it fails + redundant { + sql1 # try module sql1 + sql2 # if that's down, try module sql2 + handled # otherwise drop the request as + # it's been ``handled`` by the ``always`` + # module (see doc/rlm_always) + } + } + #--- + +The ``redundant`` section is a configuration directive which tells the +server to process the second module if the first one fails. Any +number of modules can be listed in a ``redundant`` section. The server +will process each in turn, until one of the modules succeeds. It will then stop processing the ``redundant`` list. + +Rewriting results for single modules +------------------------------------ + +Normally, when a module fails, the entire section (``authorize``, +``accounting``, etc.) stops being processed. In some cases, we may want +to permit "soft failures". That is, we may want to tell the server +that it is "ok" for a module to fail, and that the failure should not +be treated as a fatal error. + +In this case, the module is treated as a "section", rather than just +as a single lne in ``radiusd.conf``. The configuration entries for +that section are taken from the ``configurable fail-over`` code, and not +from the configuration information for that module. + +For example, the ``detail`` module normally returns ``fail`` if it is +unable to write its information to the ``detail`` file. As a test, we +can configure the server so that it continues processing the request, +even if the ``detail`` module fails. The following example shows how: + +:: + + #-- + # Handle accounting packets + accounting { + detail { + fail = 1 + } + redundant { + sql1 + sql2 + handled + } + } + #-- + +The ``fail = 1`` entry tells the server to remember the ``fail`` code, +with priority ``1``. The normal configuration is ``fail = return``, which +means ``if the detail module fails, stop processing the accounting +section``. + +Fail-over configuration entries +------------------------------- + +Modules normally return on of the following codes as their result: + ++-----------+-----------------------------------------------------+ +|Code | Meaning | ++===========+=====================================================+ +|notfound | the user was not found | ++-----------+-----------------------------------------------------+ +|noop | the module did nothing | ++-----------+-----------------------------------------------------+ +|ok | the module succeeded | ++-----------+-----------------------------------------------------+ +|updated | the module updated information in the request | ++-----------+-----------------------------------------------------+ +|fail | the module failed | ++-----------+-----------------------------------------------------+ +|reject | the module rejected the user | ++-----------+-----------------------------------------------------+ +|userlock | the user was locked out | ++-----------+-----------------------------------------------------+ +|invalid | the user's configuration entry was invalid | ++-----------+-----------------------------------------------------+ +|handled | the module has done everything to handle the request| ++-----------+-----------------------------------------------------+ + +In a configurable fail-over section, each of these codes may be +listed, with a value. If the code is not listed, or a configurable +fail-over section is not defined, then values that make sense for the +requested ``group`` (group, redundant, load-balance, etc) are used. + +The special code ``default`` can be used to set all return codes to +the specified value. This value will be used with a lower priority +than ones that are explicitly set. + +The values for each code may be one of two things: + ++---------+---------------------------------------------------------------+ +|Value | Meaning | ++=========+===============================================================+ +|<number> | Priority for this return code. | ++---------+---------------------------------------------------------------+ +|return | Stop processing this configurable fail-over list. | ++---------+---------------------------------------------------------------+ +|reject | Stop processing this configurable fail-over list and | +| | immediately return a reject. | ++---------+---------------------------------------------------------------+ + +The ``<number>`` used for a value may be any decimal number between 1 +and 99999. The number is used when processing a list of modules, to +determine which code is returned from the list. For example, if +``module1`` returns ``fail`` with priority ``1``, and a later ``module2`` +returns ``ok`` with priority ``3``, the return code from the list of +modules will be ``ok``, because it has higher priority than ``fail``. + +This configurability allows the administrator to permit some modules +to fail, so long as a later module succeeds. + + +More Complex Configurations +--------------------------- + +The ``authorize`` section is normally a list of module names. We can +create sub-lists by using the section name ``group``. The ``redundant`` +section above is just a short-hand for ``group``, with a set of default +return codes, which are different than the normal ``stop processing the +list on failure``. + +For example, we can configure two detail modules, and allow either +to fail, so long as one of them succeeds. + +:: + + #-- + # Handle accounting packets + accounting { + group { + detail1 { + fail = 1 # remember ``fail`` with priority 1 + ok = return # if we succeed, don't do ``detail2`` + } + detail2 { + fail = 1 # remember ``fail`` with priority 1 + ok = return # if we succeed, return ``ok`` + # if ``detail1`` returned ``fail`` + } + } # returns ``fail`` only if BOTH modules returned ``fail`` + redundant { + sql1 + sql2 + handled + } + } + #-- + +This configuration says: + + - log to ``detail1``, and stop processing the ``group`` list if ``detail1`` returned OK. + + - If ``detail1`` returned ``fail``, then continue, but remember the ``fail`` code, with priority 1. + + - If ``detail2`` fails, then remember ``fail`` with priority 1. + + - If ``detail2`` returned ``ok``, return ``ok`` from the ``group``. + +The return code from the ``group`` is the return code which was either +forced to return (e.g. ``ok`` for ``detail1``), or the highest priority +return code found by processing the list. + +This process can be extended to any number of modules listed in a +``group`` section. + + +Virtual Modules +--------------- + +Some configurations may require using the same list of modules, in +the same order, in multiple sections. For those systems, the +configuration can be simplified through the use of ``virtual`` modules. +These modules are configured as named sub-sections of the +``instantiate`` section, as follows: + +:: + + instantiate { + ... + + redundant sql1_or_2 { + sql1 + sql2 + } + } + +The name ``sql1_or_2`` can then be used in any other section, such as +``authorize`` or ``accounting``. The result will be *exactly* as if that +section was placed at the location of the ``sql1_or_2`` reference. + +These virtual modules are full-fledged objects in and of themselves. +One virtual module can refer to another virtual module, and they can +contain ``if`` conditions, or any other configuration permitted in a +section. + + +Redundancy and Load-Balancing +----------------------------- + +See ``man unlang`` or ``doc/load-balance`` for information on simple +redundancy (fail-over) and load balancing. + + +The Gory Details +----------------- + +The fundamental object is called a MODCALLABLE, because it is something that +can be passed a specific radius request and returns one of the RLM_MODULE_* +results. It is a function - if you can accept the fact that pieces of +radiusd.conf are functions. There are two kinds of MODCALLABLEs: GROUPs and +SINGLEs. + +A SINGLE is a reference to a module instance that was set up in the modules{} +section of radiusd.conf, like ``preprocess`` or ``sql1``. When a SINGLE is +called, the corresponding function in the rlm is invoked, and whichever +RLM_MODULE_* it returns becomes the RESULT of the SINGLE. + +A GROUP is a section of radiusd.conf that includes some MODCALLABLEs. +Examples of GROUPs above include ``authorize{...}``, which implements the C +function module_authorize, and ``redundant{...}``, which contains two SINGLEs +that refer to a couple of redundant databases. Note that a GROUP can contain +other GROUPs - ``Auth-Type SQL{...}`` is also a GROUP, which implements the C +function module_authenticate when Auth-Type is set to SQL. + +Now here's the fun part - what happens when a GROUP is called? It simply runs +through all of its children in order, and calls each one, whether it is +another GROUP or a SINGLE. It then looks at the RESULT of that child, and +takes some ACTION, which is basically either ``return that RESULT immediately`` +or ``Keep going``. In the first example, any ``bad`` RESULT from the preprocess +module causes an immediate return, and any ``good`` RESULT causes the +authorize{...} GROUP to proceed to the files module. + +We can see the exact rules by writing them out the long way: + +:: + + authorize { + preprocess { + notfound = 1 + noop = 2 + ok = 3 + updated = 4 + fail = return + reject = return + userlock = return + invalid = return + handled = return + } + files { + notfound = 1 + noop = 2 + ok = 3 + updated = 4 + fail = return + reject = return + userlock = return + invalid = return + handled = return + } + } + +This is the same as the first example, with the behavior explicitly +spelled out. Each SINGLE becomes its own section, containing a list of +RESULTs that it may return and what ACTION should follow from them. So +preprocess is called, and if it returns for example RLM_MODULE_REJECT, +then the reject=return rule is applied, and the authorize{...} GROUP +itself immediately returns RLM_MODULE_REJECT. + +If preprocess returns RLM_MODULE_NOOP, the corresponding ACTION is ``2``. An +integer ACTION serves two purposes - first, it tells the parent GROUP to go +on to the next module. Second, it is a hint as to how desirable this RESULT +is as a candidate for the GROUP's own RESULT. So files is called... suppose +it returns RLM_MODULE_NOTFOUND. The ACTION for notfound inside the files{...} +block is ``1``. We have now reached the end of the authorize{...} GROUP and we +look at the RESULTs we accumulated along the way - there is a noop with +preference level 2, and a notfound with preference level 1, so the +authorize{...} GROUP as a whole returns RLM_MODULE_NOOP, which makes sense +because to say the user was not found at all would be a lie, since preprocess +apparently found him, or else it would have returned RLM_MODULE_NOTFOUND too. + +We could use the ``default`` code to simplify the above example a +little. The following two configurations are identical: + +:: + + files { + notfound = 1 + noop = 2 + ok = 3 + updated = 4 + default = return + } + + +When putting the ``default`` first, later definitions over-ride it's +return code: + +:: + + files { + default = return + notfound = 1 + noop = 2 + ok = 3 + updated = 4 + } + +[Take a deep breath - the worst is over] + +That RESULT preference/desirability stuff is pretty complex, but my hope is +that it will be complex enough to handle the needs of everyone's real-world +imperfect systems, while staying out of sight most of the time since the +defaults will be right for the most common configurations. + +So where does redundant{...} fit in with all that? Well, redundant{...} is +simply a group that changes the default ACTIONs to something like + +:: + + fail = 1 + everythingelse = return + +so that when one module fails, we keep trying until we find one that doesn't +fail, then return whatever it returned. And at the end, if they all failed, +the redundant GROUP as a whole returns RLM_MODULE_FAIL, just as you'd want it +to (I hope). + +There are two other kinds of grouping: ``group{...}`` which does not have any +specialized default ACTIONs, and ``append{...}``, which should be used when you +have separate but similarly structured databases that are guaranteed not to +overlap. + +That's all that really needs to be said. But now a few random notes: + +GROUPs may have RESULT=ACTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It would look like this: + +:: + + authorize { + preprocess + redundant { + sql1 + sql2 + notfound = return + } + files + } + +which would prevent ``files`` from being called if neither of the SQL +instances could find the user. + +redundant{...} and append{...} are just shortcuts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You could write: + +:: + + group { + sql1 { + fail = 1 + notfound = 2 + noop = return + ok = return + updated = return + reject = return + userlock = return + invalid = return + handled = return + } + sql2 { + fail = 1 + notfound = 2 + noop = return + ok = return + updated = return + reject = return + userlock = return + invalid = return + handled = return + } + } + instead of + redundant { + sql1 + sql2 + } + +but the latter is just a whole lot easier to read. + +``authenticate{...}`` is not a GROUP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +even though it contains a list of ``Auth-Type`` GROUPs, because its +semantics are totally different - it uses ``Auth-Type`` to decide which of +its members to call, and their order is irrelevant. + +The default rules are context-sensitive +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For ``authorize``, the defaults are +what you saw above - notfound, noop, ok, and updated are considered +success, and anything else has an ACTION of ``return``. For authenticate, the +default is to return on success *or* reject, and only try the second and +following items if the first one fails. You can read all the default ACTIONs +in modcall.c (int defaultactions[][][]), or just trust me. They do the right +thing. + +There are some rules that can't be implemented in this language +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +things like ``notfound = 1-reject``, ``noop = 2-ok``, ``ok = 3-ok``, etc. But I don't feel +justified adding that complexity in the first draft. +There are already enough things here that may never see real-world usage. +Like append{...} + +-- Pac. 9/18/2000 diff --git a/doc/configuration/dynamic_home_servers.md b/doc/configuration/dynamic_home_servers.md new file mode 100644 index 0000000..7518f0a --- /dev/null +++ b/doc/configuration/dynamic_home_servers.md @@ -0,0 +1,238 @@ +# Dynamic Home Servers in v3 + +FreeRADIUS has some support for dynamic home servers, with certain +limitations. + + +## Configuration + +The configuration needs to have dynamic home servers enabled, by +editing `proxy.conf`. + +``` +proxy server { + ... + dynamic = true + ... +} +``` + +This configuration item causes the internal data structures to become +thread-safe for updates. This change means that there will be more +lock contention on the data structures holding home servers. As a +result, high-load proxy may see slowdowns. + +Once dynamic home servers are enabled, they should be placed into +a subdirectory. FreeRADIUS should be told which subdirectory the +home servers are located in: + +``` +proxy server { + ... + dynamic = true + ... + directory = ${raddb}/home_servers/ +} +``` + +This directory should contain nothing other than definitions for +dynamic home servers. These definitions are simply normal +`home_server` definitions: + +``` +home_server example.com { + ... +} +``` + +Each file in the directory should be named for the home server domain +name. In the above example, the filename should be +`${raddb}/home_servers/example.com`. The name of the home server in +the file should be the same as the filename which contains the home +server definition. + +Each file in the directory should have one, and only one, +`home_server` definition. + +Home servers which use RadSec can `$INCLUDE tls.conf` in this +directory to use a common site-local TLS configuration. The script +`freeradius-naptr-to-home-server.sh` referenced below assumes that +this file exists. If you are not using that file, it is safe to just +replace it with an empty file. + +### The Control Socket + +The virtual server `sites-enabled/control` *must* be enabled for +dynamic home servers to work. The `radmin` program *must* have +read/write permission in order for dynamic home servers to work. + +Please see that `sites-enabled/control` file for information on +configuring that virtual server. + + +## Starting FreeRADIUS + +When FreeRADIUS starts, it will read each file in the +`${raddb}/home_servers/` directory. The file will parsed in order to +define a dynamic `home_server`. + + +## Adding a new Home Server + +In order to add a new home server while FreeRADIUS is running, simply +add a new `home_server` definition file to the +`${raddb}/home_servers/` directory. + +Then, tell FreeRADIUS that the home server is available in a new file: + +``` +$ radmin -e "add home_server file /path/to/raddb/home_servers/example/com" +``` + +If all goes well, the home server will be added. If there are issues, +`radmin` will print a descriptive error. + +Once a dynamic home server has been added, it can be used just like +any other home server. + + +## Deleting a Home Server + +Dynamically created home servers can be deleted via `radmin`. Note +also that dynamic home servers which are loaded when FreeRADIUS starts +can be deleted. + +``` +$ radmin -e "del home_server file <name> <type>" +``` + +Note that this command deletes the home server by name and type, not +by filename. This difference from the `add home_server` command is +due to internal limitations in the server core. + +``` +home_server <name> { + type = <type> +} +``` + + +## Listing a Home Server + +It is possible to list all home servers and know which is dynamic or no. + +``` +$ radmin -e "show home_server list all" +``` + + +## Limitations + +Note that due to internal limitations, dynamic home servers are _not_ +freed. So repeatedly adding and deleted home servers _will_ cause +FreeRADIUS to gradually use more memory. + +Other internal limitations means that it is impossible to add dynamic +home servers to a `home_server_pool`. In short, dynamic home servers +exist by themselves, with no associated realm, pool, or failover +capability. + + +## Proxying to a Home Server + +The new attribute `Home-Server-Name` controls proxying to a particular +home server. The home server just has to exist, it does not need to +be a dynamic home server. + +``` +authorize { + ... + + update control { + Home-Server-Name := "example.com" + } + ... +} +``` + + +## Checking if a Dynamic Home Server exists + +You can see if a dynamic home server exists through the following +dynamic string expansion: + +``` +%{home_server_dynamic:name} +``` + +This expansion looks up the home server by name, and returns whether +or not the home server exists, and is dynamic. + +The return values are: + +* empty string - the home server does not exist. +* `0` - the home server exists, and is statically defined. +* `1` - the home server exists, and is dynamically defined + +``` +authorize { + ... + if (User-Name =~ /@(.*)$/) { + switch "%{home_server_dynamic:%{1}}" { + case "1" { + # Proxy to this one particular home server + update control { + &Home-Server-Name := "%{1}" + } + } + + case "0" { + # Proxy with home server pool, failover, etc. + update control { + &Proxy-To-Realm := "%{1}" + } + } + + case { + # no home server exists, ask DNS + update control { + # you can add a parameter for the NAPTR tag to look up, e.g. "aaa+auth:radius.tls.tcp" (RFC7585, OpenRoaming) + # if the third parameter is omitted, it defaults to "x-eduroam:radius.tls" + &Temp-Home-Server-String := `%{config:confdir}/mods-config/realm/freeradius-naptr-to-home-server.sh -d %{config:confdir} %{1}` + } + if ("%{control:Temp-Home-Server-String}" == "" ) { + reject + } else { + update control { + &Home-Server-Name := "%{1}" + } + } + } + } + } + ... +} +``` + +## Maintenance of Dynamic Home Servers + +Dynamic home servers are discovered from DNS, and DNS has TTLs. These +TTLs are not tracked by FreeRADIUS, as they are not available when +using the standard DNS APIs. + +Dynamic realms should be regularly deleted, so that they can be +recreated with updated information. The server should be restarted +with an empty home_server directory regularly, for two reasons: + +* Entries in DNS may change over time, or be removed, and the server should learn this. + If the entries are not removed, the server will not discover any changes. +* dynamic home servers are often RADIUS/TLS based with client and server certificates, + and the server should refresh CRL information regularly + +As a result, we recommend emptying the home_servers directory (except +for the `tls.conf` file), refreshing CRLs and then restarting the server +once per day. e.g. + +``` +rm -f $(ls -1 raddb/home_servers | egrep -v tls.conf) +``` diff --git a/doc/configuration/load_balance.rst b/doc/configuration/load_balance.rst new file mode 100644 index 0000000..7926444 --- /dev/null +++ b/doc/configuration/load_balance.rst @@ -0,0 +1,172 @@ +Load Balancing +============== + +As of version 2.0.0, the load balance documentation is in the +available in the "unlang" man page. The text below may not be up to +date, and is here only for historical purposes. + +As of version 1.1.0, FreeRADIUS supports load balancing in module +sections. Please see the "configurable_failover" file in this +directory for a more complete description of module sections. + +The short summary is that you can use a "load-balance" section in +any place where a module name may be used. The semantics of the +"load-balance" section are that one of the modules in the section will +be chosen at random, evenly spread over the modules in the list. + +An example is below:: + + accounting { + load-balance { + sql1 + sql2 + sql2 + } + } + +In this case, 1/3 of the RADIUS requests will be processed by +"sql1", one third by "sql2", and 1/3 by "sql3". + +The "load-balance" section can be nested in a "redundant" section, +or vice-versa:: + + accounting { + load-balance { # between two redundant sections below + redundant { + sql1 + sql2 + } + redundant { + sql2 + sql1 + } + } + } + +This says "load balance between sql1 and sql2, but if sql1 is down, +use sql2, and if sql2 is down, use sql1". That way, you can guarantee +both that load balancing occurs, and that the requests are *always* +logged to one of the databases:: + + accounting { + redundant { + load-balance { + sql1 + sql2 + } + detail + } + } + +This says "load balance between sql1 and sql2, but if the one being +used is down, then log to detail". + +And finally:: + + accounting { + redundant { # between load-balance & detail + load-balance { # between two redundant sections + redundant { + sql1 + sql2 + } + redundant { + sql2 + sql1 + } + } + detail + } + } + +This says "try to load balance between sql1 and sql2; if sql1 is down, +use sql2; if sql2 is down use sql1; if both sql1 and sql2 are down, +then log to the detail file" + + +More complicated scenarios +-------------------------- + +If you want to do redundancy and load-balancing among three +modules, the configuration is quite complex:: + + load-balance { + redundant { + sql1 + load-balance { + redundant { + sql2 + sql3 + } + redundant { + sql3 + sql2 + } + } + } # sql1, etc. + redundant { + sql2 + load-balance { + redundant { + sql3 + sql1 + } + redundant { + sql1 + sql3 + } + } + } # sql2, etc. + redundant { + sql3 + load-balance { + redundant { + sql1 + sql2 + } + redundant { + sql2 + sql1 + } + } + } # sql3, etc. + } + +For four or more modules, it quickly becomes unmanageable. + +The solution is to use the "redundant-load-balance" section, which +combines the features of "load-balance", with "redundant" fail-over +between members. The above complex configuration for three modules +then becomes:: + + redundant-load-balance { + sql1 + sql2 + sql3 + } + + +Which means "load-balance evenly among all three servers. If the +one picked for load-balancing is down, load-balance among the +remaining two. If that one is down, pick the one remaining 'live' +server". + +The "redundant-load-balance" section can contain any number of +modules. + + +Interaction with "if" and "else" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's best to have "if" and "else" blocks contain "load-balance" or +"redundant-load-balance" sections, rather than the other way around. +The "else" and "elsif" sections cannot appear inside of a +"load-balance" or "redundant-load-balance" section, because the "else" +condition would be chose as one of the modules for load-balancing, +which is not what you want. + +It's OK to have a plain "if" block inside of a "load-balance" or +"redundant-load-balance" section. In that case, the "if" condition +checks the return code of the module or group that executed just +before the "load-balance" section. It does *not* check the return +code of the previous module in the section. diff --git a/doc/configuration/post_auth_type b/doc/configuration/post_auth_type new file mode 100644 index 0000000..7492324 --- /dev/null +++ b/doc/configuration/post_auth_type @@ -0,0 +1,44 @@ +This is now called Post-Auth-Type, for consistency. + +O.INTRODUCTION + + Post-Auth-Type is used to select between groupings of + modules in the post-auth stanza using arbitrary attributes. + It is functionally identical to Acct-Type, apart from + the name of the attribute and its dealing with rejected + requests.. This means that (unlike Autz-Type) the attribute + must be set before the stanza is run. Changes to + Post-Auth-Type during post-auth will have no effect. + +1.HOW IT WORKS + + If a request has been rejected, the value of Post-Auth-Type + is overwritten with REJECT automatically, so anonymous + modules outside the REJECT substanza will not be run, only + modules within the appropriate substanza will be run. + +2.EXAMPLES + + In the example below, when a request has been rejected, the + module my_ippool will not be run, only the module my_detail + will be run. + If the request is not rejected, the my_ippool module will be + run, but not the my_detail module + + post-auth { + my_ippool + Post-Auth-Type REJECT { + my_detail + } + } + + In the following example, 2 different sql modules are used + to store accepted requests and rejected requests. + + post-auth { + my_sql_accept + Post-Auth-Type REJECT { + my_sql_reject + } + } + diff --git a/doc/configuration/session_type b/doc/configuration/session_type new file mode 100644 index 0000000..9efcd7c --- /dev/null +++ b/doc/configuration/session_type @@ -0,0 +1,10 @@ +Session-Type is used to select between groupings of +modules in the session stanza using arbitrary attributes. +It is functionally identical to Acct-Type, apart from +the name of the attribute. This means that (unlike +Autz-Type) the attribute must be set before the stanza +is run. Changes to Session-Type during session will +have no effect. + +This allows Simultaneous-Use checking behaviour to be very flexible. + diff --git a/doc/configuration/simultaneous_use b/doc/configuration/simultaneous_use new file mode 100644 index 0000000..5639738 --- /dev/null +++ b/doc/configuration/simultaneous_use @@ -0,0 +1,173 @@ + + FreeRADIUS server and the Simultaneous-Use parameter. + + +0. INTRODUCTION + + Lots of people want to limit the number of times one user account can + login, usually to one. This is hard to do with the radius protocol; + the nature of the accounting stuff is such that the idea the radius server + has about the list of logged-in users might be different from the idea + the terminal server has about it. + + However, most terminal servers have an alternative way to get a list + of logged-in users. Most support some way through telnet, some have + a finger-daemon builtin and a lot of them support SNMP. So if the + radius server thinks that someone is trying to login a second time, + it is possible to check on the terminal server itself if the first + login is indeed still active. Only then access is denied for the + second login. + + +1. PREREQUISITES + + You need to have perl installed. + + For SNMP checks, you have 2 options. You can use the `snmpget' program + from the cmu-snmp tools. You can probably get precompiled ones, + maybe even packaged for your system (Debian/Linux, Redhat/Linux, FreeBSD + ports collection etc). The source code is at + http://www.net.cmu.edu/projects/snmp/snmpapps/. The Linux-specific + version of this is at http://www.gaertner.de/snmp/ + + The other option is to install the SNMP_Session and BER modules that + for example the well known `mrtg' package uses. This is recommended. + In that case you need no external snmpget program, checkrad will + speak SNMP directly. See http://www.switch.ch/misc/leinen/snmp/perl/ + + The checkroutine for USR/3Com Total Control racks uses the Net::Telnet + module from CPAN, at least version 3.00. If you need that, obtain it from + your local CPAN mirror (or see http://www.perl.com/CPAN/). The checkrad.pl + perl script will autodetect if that module is installed. + +2. USAGE. + + It works by adding the `check' parameter "Simultaneous-Use" to the entry + for a users or DEFAULT in /etc/raddb/users. It should be at least one; + it defines the maximum number of users logged in with the same account name. + For example: + + # + # Simultaneous use restrictions. + # + DEFAULT Group == "staff", Simultaneous-Use := 4 + Fall-Through = 1 + DEFAULT Group == "business", Simultaneous-Use := 2 + Fall-Through = 1 + DEFAULT Simultaneous-Use := 1 + Fall-Through = 1 + + + NOTE!!! The "Simultaneous-Use" parameter is in the "check" A/V pairs, + and not in the Reply A/V pairs (it _is_ a check). + + For SQL, after creating and populating your schema, you should + execute the following statement (for MySQL, others may vary): + + INSERT INTO radgroupcheck (GroupName, Attribute, op, Value) values("dialup", "Simultaneous-Use", ":=", "1"); + + Once that is done, your users should be limited to only one login at a time. + +3. IMPLEMENTATION + + The server keeps a list of logged-in users in the /var/log/radutmp file. + This is also called "the session database". When you execute "radwho", + all that radwho really does is list the entries in this file in a pretty + format. Only when someone tries to login who _already_ has an active + session according to the radutmp file, the server executes the perl + script /usr/local/sbin/checkrad (or /usr/sbin/checkrad, it checks for + the presence of both and in that order). This script queries the terminal + server to see if the user indeed already has an active session. + + The script uses SNMP for Livingston Portmasters and Ciscos, finger for + Portslave, Computone and Ascend, and Net::Telnet for USR/3Com TC. + + Since the script has been witten in perl, it's easy to adjust for + any type of terminal server. There are implementations in the script for + checks using SNMP, finger, and telnet, so it should be easy to add + your own check routine if your terminal server is not supported yet. + + You can find the script in the file src/checkrad.pl. + + You need to set the correct type in the file /etc/raddb/naslist so that + checkrad KNOWS how it should interrogate the terminal server. At this + time you can define the following types: + + type Vendor Uses method needs Need naspasswd + ==== ====== =========== ===== ============== + ascend Lucent SNMP SNMP No + bay Nortel finger finger command No + cisco Cisco SNMP SNMP Optional [1] + computone Computone finger finger command No + cvx Nortel SNMP SNMP No + digitro Digitro rusers rusers command No + livingston Livingston SNMP SNMP No [2] + max40xx Lucent finger finger command No + netserver USR/3com telnet CPAN Net::Telnet Yes + pathras Cyclades telnet CPAN Net::Telnet Yes + patton Patton SNMP SNMP No + portslave ? finger finger command No + pr3000 Cyclades SNMP snmpwalk command No + pr4000 Cyclades SNMP snmpwalk command No + tc USR/3com telnet CPAN Net::Telnet Yes + usrhyper USR/3com SNMP SNMP No [3] + versanet VersaNet SNMP SNMP No + + other none N/A - No + + [1] In naspasswd file: set username to SNMP, password is community. + [2] Needs at least ComOS 3.5, SNMP enabled. + [3] Set "Reported Port Density" to 256 (default) + + "other" means "don't bother checking, I believe what radutmp says". + This really is not recommended, if a user has a "stuck" entry in the + session database she will not be able to login again - hence the + extra check that "checkrad" does. + +4. IF IT DOESN'T WORK + + Note that you need to add the Simultaneous-Use parameter to the + check item (first line), not the reply item, using the ':=' operator. + + You can edit the `checkrad' perl script and turn on debugging. Then + watch the debug file. The `radius.log' file also gives some hints. + + You can also run the "checkrad" script manually, use the "-d" + switch to get debug output on standard output instead of in the log. + + See also: + + http://wrath.geoweb.ge/simult.html + + which has a good discussion of the use of Simultaneous-Use. + + +5. CAVEATS + + This solution checks the radutmp file. This file is kept up-to-date from + the Accounting records the NAS sends. Since some NASes delay these records + for quite some time, it is possible to get a double login by logging in + twice at _exactly_ the same time (plus or minus the mentioned delay time), + since neither of the logins are registered yet. + + The solution would be to create a small 1-minute cache of Authentication + records, that is also checked for double login attempts. Perhaps in the + next version. + + When implementing this one thing was considered the most important: when + trying to detect double logins, we always try to err on the safe side. So + in rare cases, a double login is possible but we try never to limit access + for a legitimate login. + +6. PROBLEMS WITH DROPPED CONNECTIONS + + Our PM3, with 2 ISDN-30 lines coming into it, had the habit of sometimes + dropping connections. In a few cases, the portmaster thought the session was + still alive so if the user tried to login again, he or she was denied access. + In our case, this problem was caused by a bad PRI line from the phone + company. + + We tried to compensate this by setting the Idle-Timeout to 15 minutes. That + way, even if a user did get locked out the portmaster would clear the rogue + session within 15 minutes and the user could login again. + diff --git a/doc/configuration/snmp b/doc/configuration/snmp new file mode 100644 index 0000000..713cb83 --- /dev/null +++ b/doc/configuration/snmp @@ -0,0 +1,58 @@ +INSTALL +------- + +Installing the SNMP patch is straightforward: + +$ tar -zxf freeradius-server-2.1.11.tar.gz +$ cd freeradius-server-2.1.11 +$ patch -p1 < ../snmp.patch +$ ./configure --args.... +$ make +$ make install + +MIB Installation +---------------- + +The traps *REQUIRE* that the files in the "mibs" directory be copied +to the global mibs directory, usually /usr/share/snmp/mibs/. +If this is not done, the "snmptrap" program has no idea what information +to send, and will not work. The MIB installation is *NOT* done as +part of the default installation, so that step *MUST* be done manually. + +The global MIB directory can be found by running the following command: + + $ snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR | sed "s/' .*//;s/.* '//;s/.*://" + +Or maybe just: + + $ snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR + +If you have copied the MIBs to that directory, you can test the +FreeRADIUS MIBs by running the following command: + + $ snmptranslate -m +FREERADIUS-NOTIFICATION-MIB -IR -On serverStart + +It should print out: + + .1.3.6.1.4.1.11344.4.1.1 + +As always, run the server in debugging mode after enabling the +traps. You will see the "snmptrap" command being run, and it will +print out any errors or issues that it encounters. Those need to +be fixed before running the server in daemon mode. + +We also suggest running in debugging mode as the "radiusd" user, if +you have "user/group" set in radiusd.conf. The "snmptrap" program +may behave differently when run as "root" or as the "radiusd" user. + +You will also need to edit "radiusd.conf", and uncomment the line saying + + # $INCLUDE trigger.conf + +That will enable the triggers. + + +More Documentation +------------------ + +See raddb/trigger.conf for complete documentation. diff --git a/doc/configuration/variables.rst b/doc/configuration/variables.rst new file mode 100644 index 0000000..4a2f28c --- /dev/null +++ b/doc/configuration/variables.rst @@ -0,0 +1,151 @@ +Run-time variables +================== + +See "man unlang" for more complete documentation on the run-time +variables. This file is here only for historical purposes. + +The above variable expansions also support the following +meta-attributes. These are not normal RADIUS attributes, but are +created by the server to be used like them, for ease of use. They can +only be queried, and cannot be assigned. + ++-----------------------+-------------------------------------------------+ +| Packet-Type | RADIUS packet type (Access-Request, etc.) | ++-----------------------+-------------------------------------------------+ +| Packet-Src-IP-Address | IP address from which the packet was sent | ++-----------------------+-------------------------------------------------+ +| Packet-Dst-IP-Address | IP address to which the packet was sent. | +| | This may be "0.0.0.0", if the server | +| | was configured with ``bind_address = *``. | ++-----------------------+-------------------------------------------------+ +| Packet-Src-Port | UDP port from which the packet was sent | ++-----------------------+-------------------------------------------------+ +| Packet-Dst-Port | UDP port to which the packet was sent. | ++-----------------------+-------------------------------------------------+ + +``%{config:section.subsection.item}`` + Corresponding value in ``radiusd.conf`` for the string value of that item. + +The ``%{config:...}`` variables should be used VERY carefully, as they +may leak secret information from your RADIUS server, if you use them +in reply attributes to the NAS! + +:: + + DEFAULT User-Name =~ "^([^@]+)@(.*)" + All-That-Matched = `%{0}` + Just-The-User-Name = `%{1}` + Just-The-Realm-Name = `%{2}` + + +The variables are used in dynamically translated strings. Most of the +configuration entries in ``radiusd.conf`` (and related files) will do +dynamic string translation. To do the same dynamic translation in a +RADIUS attribute (when pulling it from a database, or "users" file), +you must put the string into an back-quoted string: + +:: + + Session-Timeout = `%{expr: 2 + 3}` + +To do the dynamic translation in the ``radiusd.conf`` (or some other +configuration files), just use the variable as-is. See +``radiusd.conf`` for examples. + + +Attributes as environment variables in executed programs +-------------------------------------------------------- + +When calling an external program (e.g. from ``rlm_exec`` module), these +variables can be passed on the command line to the program. In +addition, the server places all of the attributes in the RADIUS +request into environment variables for the external program. The +variables are renamed under the following rules: + + #. All letters are made upper-case. + #. All hyphens '-' are turned into underscores '_' + +so the attribute ``User-Name`` can be passed on the command line to the +program as ``%{User-Name}``, or used inside the program as the environment +variable ``USER_NAME`` (or ``$USER_NAME`` for shell scripts). + +If you want to see the list of all of the variables, try adding a line +``printenv > /tmp/exec-program-wait`` to the script. Then look in the +file for a complete list of variables. + +One-character variables +----------------------- + +The following one-character variables were defined. They were duplicates of the +previous general cases, and were only provided for backwards compatibility. +They are in the process of being removed, this table documents the old variables +and their new equivalents. +(i.e. ``:-``, as described above. + ++-----------+---------------------------+-----------------------+ +| Variable | Description | Proper Equivalent | ++===========+===========================+=======================+ +|%a |Protocol (SLIP/PPP) |%{Framed-Protocol} | ++-----------+---------------------------+-----------------------+ +|%c |Callback-Number |%{Callback-Number} | ++-----------+---------------------------+-----------------------+ +|%d |request day (DD) | | ++-----------+---------------------------+-----------------------+ +|%f |Framed IP address |%{Framed-IP-Address} | ++-----------+---------------------------+-----------------------+ +|%i |Calling Station ID |%{Calling-Station-Id} | ++-----------+---------------------------+-----------------------+ +|%l |request timestamp | | ++-----------+---------------------------+-----------------------+ +|%m |request month (MM) | | ++-----------+---------------------------+-----------------------+ +|%n |NAS IP address |%{NAS-IP-Address} | ++-----------+---------------------------+-----------------------+ +|%p |Port number |%{NAS-Port} | ++-----------+---------------------------+-----------------------+ +|%s |Speed (PW_CONNECT_INFO) |%{Connect-Info} | ++-----------+---------------------------+-----------------------+ +|%t |request in ctime format | | ++-----------+---------------------------+-----------------------+ +|%u |User name |%{User-Name} | ++-----------+---------------------------+-----------------------+ +|%A |radacct_dir |%{config:radacctdir} | ++-----------+---------------------------+-----------------------+ +|%C |clientname | | ++-----------+---------------------------+-----------------------+ +|%D |request date (YYYYMMDD) | | ++-----------+---------------------------+-----------------------+ +|%G |request minute | | ++-----------+---------------------------+-----------------------+ +|%H |request hour | | ++-----------+---------------------------+-----------------------+ +|%I |request ID | | ++-----------+---------------------------+-----------------------+ +|%L |radlog_dir |%{config:logdir} | ++-----------+---------------------------+-----------------------+ +|%M |MTU |%{Framed-MTU} | ++-----------+---------------------------+-----------------------+ +|%R |radius_dir |%{config:raddbdir} | ++-----------+---------------------------+-----------------------+ +|%S |request timestamp | | +| |in SQL format | | ++-----------+---------------------------+-----------------------+ +|%T |request timestamp | | +| |in database format | | ++-----------+---------------------------+-----------------------+ +|%U |Stripped User name |%{Stripped-User-Name} | ++-----------+---------------------------+-----------------------+ +|%V |Request-Authenticator | | +| |(Verified/None) | | ++-----------+---------------------------+-----------------------+ +|%v |Server Version | | ++-----------+---------------------------+-----------------------+ +|%Y |request year (YYYY) | | ++-----------+---------------------------+-----------------------+ +|%Z |All request attributes | | +| |except password | | +| |(must have a big buffer) | | ++-----------+---------------------------+-----------------------+ + + + $Id$ |