27RCSID(
"$Id: 1a2041472da920f135e3a2f36ce8b655d1e2d768 $")
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/unlang/call_env.h>
32#include <freeradius-devel/unlang/xlat_func.h>
33#include <freeradius-devel/util/debug.h>
34#include <freeradius-devel/unlang/xlat.h>
35#include <freeradius-devel/util/dcursor.h>
36#include <freeradius-devel/util/skip.h>
37#include <freeradius-devel/util/value.h>
103 struct wbcContext *wb_ctx;
106 gid_t *wb_groups = NULL;
108 char const *domain = NULL;
109 size_t domain_len = 0;
111 char *username_buff = NULL;
112 size_t backslash = 0;
126 domain = env->
domain.vb_strvalue;
127 domain_len = env->
domain.vb_length;
134 RWDEBUG(
"Searching group with plain username, this will probably fail");
135 RWDEBUG(
"Ensure winbind domain is correctly set");
141 wbctx = winbind_slab_reserve(t->
slab);
143 RERROR(
"Unable to get winbind context");
150 err = wbcCtxGetGroups(wb_ctx,
username, &num_groups, &wb_groups);
152 case WBC_ERR_SUCCESS:
158 RDEBUG2(
"Successfully retrieved user's groups");
161 case WBC_ERR_WINBIND_NOT_AVAILABLE:
162 RERROR(
"Failed retrieving groups: Unable to contact winbindd");
165 case WBC_ERR_DOMAIN_NOT_FOUND:
167 REDEBUG(
"Failed retrieving groups: User or Domain not found");
170 case WBC_ERR_UNKNOWN_USER:
171 REDEBUG(
"Failed retrieving groups: User cannot be found");
175 REDEBUG(
"Failed retrieving groups: %s", wbcErrorString(
err));
192 if (domain_len > 0) backslash = domain_len - 1;
194 for (i = 0; i < num_groups; i++) {
199 err = wbcCtxGetgrgid(wb_ctx, wb_groups[i], &group);
200 if (
err != WBC_ERR_SUCCESS) {
201 REDEBUG(
"Failed resolving GID %i: %s", wb_groups[i], wbcErrorString(
err));
202 if (wb_groups[i] == UINT32_MAX) {
203 REDEBUG(
"GID appears to be winbind placeholder value, idmap likely failed");
208 RDEBUG3(
"Resolved GID %i to name \"%s\"", wb_groups[i], group->gr_name);
211 if ((backslash < strlen(group->gr_name)) && (group->gr_name[backslash] ==
'\\')) {
212 group_name = group->gr_name + backslash + 1;
213 }
else if ((group_name = strchr(group->gr_name,
'\\'))) {
215 backslash = group_name - (group->gr_name - 1);
217 group_name = group->gr_name;
221 RDEBUG3(
"Checking plain group name \"%s\"", group_name);
223 RDEBUG2(
"Found matching group: %s", group_name);
226 wbcFreeMemory(group);
232 if (!rcode)
RWDEBUG2(
"No groups found that match");
235 wbcFreeMemory(wb_groups);
236 winbind_slab_release(wbctx);
266 char const *p = arg->vb_strvalue;
299 struct wbcAuthErrorInfo *err_info = NULL;
304 wbctx = winbind_slab_reserve(t->
slab);
306 RERROR(
"Ping failed - Unable to get winbind context");
314 err = wbcCtxPingDc2(wbctx->
ctx, domain ? domain->vb_strvalue : NULL, &err_info, &dc);
318 if (WBC_ERROR_IS_OK(
err)) {
319 RDEBUG2(
"Ping succeeded to DC %s after %pVms", dc,
325 char const *err_str = wbcErrorString(
err);
327 RERROR(
"Ping failed (%s) to DC %s after %pVms%s%s", err_str, dc,
329 err_info->display_string ?
" - " :
"",
330 err_info->display_string ? err_info->display_string :
"");
335 if (dc) wbcFreeMemory(dc);
336 if (err_info) wbcFreeMemory(err_info);
337 winbind_slab_release(wbctx);
349 wbcCtxFree(wbctx->
ctx);
358 wbctx->
ctx = wbcCtxCreate();
380 if (!
inst->auth_type) {
381 WARN(
"Failed to find 'authenticate %s {...}' section. Winbind authentication will likely not work",
408 REDEBUG2(
"No %s found in the request; not doing winbind authentication.",
413 if (!
inst->auth_type) {
414 WARN(
"No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup Winbind authentication",
440 REDEBUG(
"User-Password must not be empty");
450 RDEBUG2(
"Login attempt with password");
459 RDEBUG2(
"User authenticated successfully using winbind");
470 .pair.dflt =
"User-Password", .pair.dflt_quote =
T_BARE_WORD },
479 tmpl_t *parsed_tmpl = NULL;
480 struct wbcInterfaceDetails *wb_info = NULL;
486 NULL, t_rules) < 0)
return -1;
493 struct wbcContext *wb_ctx;
495 cf_log_warn(ci,
"winbind domain unspecified; trying to get it from winbind");
497 wb_ctx = wbcCtxCreate();
500 cf_log_err(ci,
"Unable to get libwbclient context, cannot get domain");
504 err = wbcCtxInterfaceDetails(wb_ctx, &wb_info);
507 if (
err != WBC_ERR_SUCCESS) {
508 cf_log_err(ci,
"libwbclient returned wbcErr code %d; unable to get domain name.",
err);
509 cf_log_err(ci,
"Is winbind running and does the winbind_privileged socket have");
514 if (!wb_info->netbios_domain) {
515 cf_log_err(ci,
"winbind returned blank domain name");
520 &
FR_SBUFF_IN(wb_info->netbios_domain, strlen(wb_info->netbios_domain)),
524 wbcFreeMemory(wb_info);
528 cf_log_info(ci,
"Using winbind_domain '%s'", parsed_tmpl->name);
531 wbcFreeMemory(wb_info);
534 *(
void **)
out = parsed_tmpl;
535 return parsed_tmpl ? 0 : -1;
545 .pair.dflt =
"User-Password", .pair.dflt_quote =
T_BARE_WORD },
608 ERROR(
"Connection handle pool instantiation failed");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
int do_auth_wbclient_pap(request_t *request, winbind_auth_call_env_t *env, rlm_winbind_thread_t *t)
PAP authentication direct to winbind via Samba's libwbclient library.
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
#define FR_CALL_ENV_SUBSECTION(_name, _name2, _flags, _subcs)
Specify a call_env_parser_t which defines a nested subsection.
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
@ CALL_ENV_FLAG_SECRET
The value is a secret, and should not be logged.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_info(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
static xlat_action_t winbind_group_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Check if the user is a member of a particular winbind group.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RWDEBUG2(fmt,...)
#define REDEBUG2(fmt,...)
#define RINDENT()
Indent R* messages by one level.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
int strcasecmp(char *s1, char *s2)
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
fr_event_list_t * el
Event list to register any IO handlers and timers against.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
module_t common
Common fields presented by all modules.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
static const conf_parser_t config[]
#define RETURN_MODULE_REJECT
#define RETURN_MODULE_NOOP
#define RETURN_MODULE_INVALID
rlm_rcode_t
Return codes indicating the result of the module call.
static int instantiate(module_inst_ctx_t const *mctx)
static int domain_call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
static const call_env_method_t winbind_autz_method_env
static xlat_arg_parser_t const winbind_group_xlat_arg[]
static int winbind_ctx_alloc(winbind_ctx_t *wbctx, UNUSED void *uctx)
fr_dict_attr_autoload_t rlm_winbind_dict_attr[]
static const call_env_method_t winbind_auth_method_env
static const conf_parser_t group_config[]
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_expr_bool_enum
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Authenticate the user via libwbclient and winbind.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Bootstrap this module.
static xlat_action_t winbind_ping_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Ping a specific domain.
static fr_dict_attr_t const * attr_auth_type
static conf_parser_t reuse_winbind_config[]
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Authorize for libwbclient/winbind authentication.
static int _mod_ctx_free(winbind_ctx_t *wbctx)
static const call_env_method_t winbind_group_xlat_call_env
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static bool winbind_check_group(rlm_winbind_t const *inst, request_t *request, char const *name, winbind_group_xlat_call_env_t *env, rlm_winbind_thread_t *t)
Group comparison for Winbind-Group.
static const conf_parser_t module_config[]
fr_dict_autoload_t rlm_winbind_dict[]
static xlat_arg_parser_t const winbind_ping_xlat_arg[]
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
Instantiate this module.
rlm_winbind_t const * inst
Instance of rlm_winbind.
winbind_slab_list_t * slab
Slab list for winbind handles.
#define FR_SBUFF_IN(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name
Instance name e.g. user_database.
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
void * boot
Data allocated during the boostrap phase.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Optional arguments passed to vp_tmpl functions.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
#define FR_SLAB_CONFIG_CONF_PARSER
conf_parser_t entries to populate user configurable slab values
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Stores an attribute, a value and various bits of other data.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
#define fr_time_sub(_a, _b)
Subtract one time from another.
uint8_t required
Argument must be present, and non-empty.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition for a single argument consumend by an xlat function.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_box_time_delta_msec(_val)
static size_t char ** out
void * env_data
Expanded call env data.
module_ctx_t const * mctx
Synthesised module calling ctx.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
void xlat_func_call_env_set(xlat_t *x, call_env_method_t const *env_method)
Register call environment of an xlat.