27 RCSID(
"$Id: 95d0fc72d8239a9a221c94699b25fb9503152dc2 $")
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>
92 struct wbcContext *wb_ctx;
95 gid_t *wb_groups = NULL;
97 char const *domain = NULL;
98 size_t domain_len = 0;
100 char *username_buff = NULL;
101 size_t backslash = 0;
115 domain = env->
domain.vb_strvalue;
116 domain_len = env->
domain.vb_length;
123 RWDEBUG(
"Searching group with plain username, this will probably fail");
124 RWDEBUG(
"Ensure winbind domain is correctly set");
131 if (wb_ctx == NULL) {
132 RERROR(
"Unable to get winbind connection from the pool");
138 err = wbcCtxGetGroups(wb_ctx,
username, &num_groups, &wb_groups);
140 case WBC_ERR_SUCCESS:
146 RDEBUG2(
"Successfully retrieved user's groups");
149 case WBC_ERR_WINBIND_NOT_AVAILABLE:
150 RERROR(
"Failed retrieving groups: Unable to contact winbindd");
153 case WBC_ERR_DOMAIN_NOT_FOUND:
155 REDEBUG(
"Failed retrieving groups: User or Domain not found");
158 case WBC_ERR_UNKNOWN_USER:
159 REDEBUG(
"Failed retrieving groups: User cannot be found");
163 REDEBUG(
"Failed retrieving groups: %s", wbcErrorString(
err));
180 if (domain_len > 0) backslash = domain_len - 1;
182 for (i = 0; i < num_groups; i++) {
187 err = wbcCtxGetgrgid(wb_ctx, wb_groups[i], &group);
188 if (
err != WBC_ERR_SUCCESS) {
189 REDEBUG(
"Failed resolving GID %i: %s", wb_groups[i], wbcErrorString(
err));
190 if (wb_groups[i] == UINT32_MAX) {
191 REDEBUG(
"GID appears to be winbind placeholder value, idmap likely failed");
196 RDEBUG3(
"Resolved GID %i to name \"%s\"", wb_groups[i], group->gr_name);
199 if ((backslash < strlen(group->gr_name)) && (group->gr_name[backslash] ==
'\\')) {
200 group_name = group->gr_name + backslash + 1;
201 }
else if ((group_name = strchr(group->gr_name,
'\\'))) {
203 backslash = group_name - (group->gr_name - 1);
205 group_name = group->gr_name;
209 RDEBUG3(
"Checking plain group name \"%s\"", group_name);
211 RDEBUG2(
"Found matching group: %s", group_name);
214 wbcFreeMemory(group);
220 if (!rcode)
RWDEBUG2(
"No groups found that match");
223 wbcFreeMemory(wb_groups);
249 char const *p = arg->vb_strvalue;
285 struct wbcContext **wb_ctx;
287 wb_ctx = talloc_zero(ctx,
struct wbcContext *);
288 *wb_ctx = wbcCtxCreate();
290 if (*wb_ctx == NULL) {
291 PERROR(
"failed to create winbind context");
322 if (!
inst->wb_pool) {
328 if (!
inst->auth_type) {
329 WARN(
"Failed to find 'authenticate %s {...}' section. Winbind authentication will likely not work",
373 REDEBUG2(
"No %s found in the request; not doing winbind authentication.",
378 if (!
inst->auth_type) {
379 WARN(
"No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup Winbind authentication",
405 REDEBUG(
"User-Password must not be empty");
415 RDEBUG2(
"Login attempt with password");
424 RDEBUG2(
"User authenticated successfully using winbind");
435 .pair.dflt =
"&User-Password", .pair.dflt_quote =
T_BARE_WORD },
444 tmpl_t *parsed_tmpl = NULL;
445 struct wbcInterfaceDetails *wb_info = NULL;
451 NULL, t_rules) < 0)
return -1;
458 struct wbcContext *wb_ctx;
460 cf_log_warn(ci,
"winbind domain unspecified; trying to get it from winbind");
462 wb_ctx = wbcCtxCreate();
465 cf_log_err(ci,
"Unable to get libwbclient context, cannot get domain");
469 err = wbcCtxInterfaceDetails(wb_ctx, &wb_info);
472 if (
err != WBC_ERR_SUCCESS) {
473 cf_log_err(ci,
"libwbclient returned wbcErr code %d; unable to get domain name.",
err);
474 cf_log_err(ci,
"Is winbind running and does the winbind_privileged socket have");
479 if (!wb_info->netbios_domain) {
480 cf_log_err(ci,
"winbind returned blank domain name");
485 &
FR_SBUFF_IN(wb_info->netbios_domain, strlen(wb_info->netbios_domain)),
489 wbcFreeMemory(wb_info);
493 cf_log_info(ci,
"Using winbind_domain '%s'", parsed_tmpl->name);
496 wbcFreeMemory(wb_info);
499 *(
void **)
out = parsed_tmpl;
500 return parsed_tmpl ? 0 : -1;
510 .pair.dflt =
"&User-Password", .pair.dflt_quote =
T_BARE_WORD },
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
int do_auth_wbclient_pap(rlm_winbind_t const *inst, request_t *request, winbind_auth_call_env_t *env)
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...
#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.
#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
@ 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.
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.
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a 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.
static fr_time_delta_t timeout
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 * 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.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
int strcasecmp(char *s1, char *s2)
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Module instance to detach.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
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.
fr_pool_t * module_rlm_connection_pool_init(CONF_SECTION *module, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific connection pool.
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)
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.
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
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 int mod_detach(module_detach_ctx_t const *mctx)
Tidy up module instance.
static const call_env_method_t winbind_autz_method_env
static xlat_arg_parser_t const winbind_group_xlat_arg[]
static void * mod_conn_create(TALLOC_CTX *ctx, UNUSED void *instance, UNUSED fr_time_delta_t timeout)
Create connection pool winbind context.
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 fr_dict_attr_t const * attr_auth_type
static bool winbind_check_group(rlm_winbind_t const *inst, request_t *request, char const *name, winbind_group_xlat_call_env_t *env)
Group comparison for Winbind-Group.
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 const call_env_method_t winbind_group_xlat_call_env
static int _mod_conn_free(struct wbcContext **wb_ctx)
Free connection pool winbind context.
static const conf_parser_t module_config[]
fr_dict_autoload_t rlm_winbind_dict[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
Instantiate this module.
#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.
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.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
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.
Optional arguments passed to vp_tmpl functions.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
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
A time delta, a difference in time measured in nanoseconds.
bool required
Argument must be present, and non-empty.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition for a single argument consumend by an xlat function.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
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.