/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_example_t *inst = instance;
	ATTR_FLAGS flags;

	memset(&flags, 0, sizeof(flags));
	/*
	 *	Do more work here
	 */
	if (!inst->boolean) {
		cf_log_err_cs(conf, "Boolean is false: forcing error!");
		return -1;
	}

	if (dict_addattr("Example-Paircmp", -1, 0, PW_TYPE_STRING, flags) < 0) {
		ERROR("Failed creating paircmp attribute: %s", fr_strerror());

		return -1;
	}

	paircompare_register(dict_attrbyname("Example-Paircmp"), dict_attrbyvalue(PW_USER_NAME, 0), false,
			     rlm_example_cmp, inst);

	return 0;
}
Beispiel #2
0
/** Convert module specific attribute id to value_pair_tmpl_t.
 *
 * @param[in] ctx for talloc
 * @param[in] name string to convert.
 * @param[in] type Type of quoting around value.
 * @return pointer to new VPT.
 */
value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type)
{
	value_pair_tmpl_t *vpt;

	vpt = talloc_zero(ctx, value_pair_tmpl_t);
	vpt->name = talloc_strdup(vpt, name);

	switch (type)
	{
		case T_BARE_WORD:
			if (!isdigit((int) *name)) {
				request_refs_t ref;
				pair_lists_t list;
				const char *p = name;

				ref = radius_request_name(&p, REQUEST_CURRENT);
				list = radius_list_name(&p, PAIR_LIST_REQUEST);

				if ((p != name) && !*p) {
					vpt->type = VPT_TYPE_LIST;

				} else {
					const DICT_ATTR *da;
					da = dict_attrbyname(p);
					if (!da) {
						vpt->type = VPT_TYPE_LITERAL;
						break;
					}
					vpt->da = da;
					vpt->type = VPT_TYPE_ATTR;
				}

				vpt->request = ref;
				vpt->list = list;
				break;
			}
			/* FALL-THROUGH */

		case T_SINGLE_QUOTED_STRING:
			vpt->type = VPT_TYPE_LITERAL;
			break;
		case T_DOUBLE_QUOTED_STRING:
			vpt->type = VPT_TYPE_XLAT;
			break;
		case T_BACK_QUOTED_STRING:
			vpt->type = VPT_TYPE_EXEC;
			break;
		case T_OP_REG_EQ: /* hack */
			vpt->type = VPT_TYPE_REGEX;
			break;
		default:
			rad_assert(0);
			return NULL;
	}

	return vpt;
}
/*
 *	This hack strips out Cisco's VSA duplicities in lines
 *	(Cisco not implemented VSA's in standard way.
 *
 *	Cisco sends it's VSA attributes with the attribute name *again*
 *	in the string, like:  H323-Attribute = "h323-attribute=value".
 *	This sort of behaviour is nonsense.
 */
static void cisco_vsa_hack(REQUEST *request)
{
	int		vendorcode;
	char		*ptr;
	char		newattr[MAX_STRING_LEN];
	VALUE_PAIR	*vp;
	vp_cursor_t	cursor;
	for (vp = fr_cursor_init(&cursor, &request->packet->vps);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
		vendorcode = vp->da->vendor;
		if (!((vendorcode == 9) || (vendorcode == 6618))) {
			continue; /* not a Cisco or Quintum VSA, continue */
		}

		if (vp->da->type != PW_TYPE_STRING) {
			continue;
		}

		/*
		 *  No weird packing.  Ignore it.
		 */
		ptr = strchr(vp->vp_strvalue, '='); /* find an '=' */
		if (!ptr) {
			continue;
		}

		/*
		 *	Cisco-AVPair's get packed as:
		 *
		 *	Cisco-AVPair = "h323-foo-bar = baz"
		 *	Cisco-AVPair = "h323-foo-bar=baz"
		 *
		 *	which makes sense only if you're a lunatic.
		 *	This code looks for the attribute named inside
		 *	of the string, and if it exists, adds it as a new
		 *	attribute.
		 */
		if (vp->da->attr == 1) {
			char const *p;

			p = vp->vp_strvalue;
			gettoken(&p, newattr, sizeof(newattr), false);

			if (dict_attrbyname(newattr) != NULL) {
				pairmake_packet(newattr, ptr + 1, T_OP_EQ);
			}
		} else {	/* h322-foo-bar = "h323-foo-bar = baz" */
			/*
			 *	We strip out the duplicity from the
			 *	value field, we use only the value on
			 *	the right side of the '=' character.
			 */
			pairstrcpy(vp, ptr + 1);
		}
	}
}
Beispiel #4
0
/*
 *	Parse a named policy "policy foo {...}"
 */
static int parse_named_policy(policy_lex_file_t *lexer)
{
    int rcode;
    policy_lex_t token;
    char mystring[256];
    policy_named_t *this;
    DICT_ATTR *dattr;

    debug_tokens("[POLICY] ");

    this = rad_malloc(sizeof(*this));
    memset(this, 0, sizeof(*this));

    this->item.type = POLICY_TYPE_NAMED_POLICY;
    this->item.lineno = lexer->lineno;

    token = policy_lex_file(lexer, 0, mystring, sizeof(mystring));
    if (token != POLICY_LEX_BARE_WORD) {
        fprintf(stderr, "%s[%d]: Expected policy name, got \"%s\"\n",
                lexer->filename, lexer->lineno,
                fr_int2str(rlm_policy_tokens, token, "?"));
        rlm_policy_free_item((policy_item_t *) this);
        return 0;
    }

    dattr = dict_attrbyname(mystring);
    if (dattr) {
        fprintf(stderr, "%s[%d]: Invalid policy name \"%s\": it is already defined as a dictionary attribute\n",
                lexer->filename, lexer->lineno, mystring);
        rlm_policy_free_item((policy_item_t *) this);
        return 0;
    }

    this->name = strdup(mystring);
    rcode = parse_block(lexer, &(this->policy));
    if (!rcode) {
        rlm_policy_free_item((policy_item_t *) this);
        return rcode;
    }

    /*
     *	And insert it into the tree of policies.
     *
     *	For now, policy names aren't scoped, they're global.
     */
    if (!rlm_policy_insert(lexer->policies, this)) {
        radlog(L_ERR, "Failed to insert policy \"%s\"", this->name);
        rlm_policy_free_item((policy_item_t *) this);
        return 0;
    }

    if ((lexer->debug & POLICY_DEBUG_PRINT_POLICY) != 0) {
        rlm_policy_print(this);
    }

    return 1;
}
/*
 *	Convert field X to a VP.
 */
static int csv_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
{
	char const *str = uctx;
	VALUE_PAIR *head = NULL, *vp;
	vp_cursor_t cursor;
	DICT_ATTR const *da;

	rad_assert(ctx != NULL);
	fr_cursor_init(&cursor, &head);

	/*
	 *	FIXME: allow multiple entries.
	 */
	if (map->lhs->type == TMPL_TYPE_ATTR) {
		da = map->lhs->tmpl_da;

	} else {
		char *attr;

		if (tmpl_aexpand(ctx, &attr, request, map->lhs, NULL, NULL) <= 0) {
			RWDEBUG("Failed expanding string");
			return -1;
		}

		da = dict_attrbyname(attr);
		if (!da) {
			RWDEBUG("No such attribute '%s'", attr);
			return -1;
		}

		talloc_free(attr);
	}

	vp = pairalloc(ctx, da);
	rad_assert(vp);

	if (pairparsevalue(vp, str, talloc_array_length(str) - 1) < 0) {
		char *escaped;

		escaped = fr_aprints(vp, str, talloc_array_length(str) - 1, '\'');
		RWDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped,
			map->lhs->tmpl_da->name, fr_strerror());

		talloc_free(vp); /* also frees escaped */
		return -1;
	}

	vp->op = map->op;
	fr_cursor_merge(&cursor, vp);

	*out = head;
	return 0;
}
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
 *
 * VPTs are used in various places where we need to pre-parse configuration 
 * sections into attribute mappings.
 *
 * Note: name field is just a copy of the input pointer, if you know that
 * string might be freed before you're done with the vpt use radius_attr2tmpl
 * instead.
 * 
 * @param[in] name attribute name including qualifiers.
 * @param[out] vpt to modify.
 * @param[in] request_def The default request to insert unqualified 
 *	attributes into.
 * @param[in] list_def The default list to insert unqualified attributes into.
 * @return -1 on error or 0 on success.
 */
int radius_parse_attr(const char *name, value_pair_tmpl_t *vpt,
		      request_refs_t request_def,
		      pair_lists_t list_def)
{
	char buffer[128];
	const char *p;
	size_t len;

	vpt->name = name;
	p = name;
	
	vpt->request = radius_request_name(&p, request_def);
	len = p - name;
	if (vpt->request == REQUEST_UNKNOWN) {
		strlcpy(buffer, name, len < sizeof(buffer) ?
			len + 1 : sizeof(buffer));
		
		radlog(L_ERR, "Invalid request qualifier \"%s\"", buffer);
		
		return -1;
	}
	name += len;
	
	vpt->list = radius_list_name(&p, list_def);
	if (vpt->list == PAIR_LIST_UNKNOWN) {
		len = p - name;
		strlcpy(buffer, name, len < sizeof(buffer) ?
			len + 1 : sizeof(buffer));
				
		radlog(L_ERR, "Invalid list qualifier \"%s\"", buffer);
		
		return -1;
	}
	
	if (*p == '\0') {
		vpt->type = VPT_TYPE_LIST;
		
		return 0;
	}
	
	vpt->da = dict_attrbyname(p);
	if (!vpt->da) {
		radlog(L_ERR, "Attribute \"%s\" unknown", p);
	
		return -1;
	}
	
	vpt->type = VPT_TYPE_ATTR;
	
	return 0;
}
Beispiel #7
0
/*
 *	Return a VALUE_PAIR, given an attribute name.
 *
 *	FIXME: Have it return the N'th one, too, like
 *	doc/variables.txt?
 *
 *	The amount of duplicated code is getting annoying...
 */
static VALUE_PAIR *find_vp(REQUEST *request, const char *name)
{
	const char *p;
	const DICT_ATTR *dattr;
	VALUE_PAIR *vps;

	p = name;
	vps = request->packet->vps;;

	/*
	 *	FIXME: use names from reserved word list?
	 */
	if (strncasecmp(name, "request:", 8) == 0) {
		p += 8;
	} else if (strncasecmp(name, "reply:", 6) == 0) {
		p += 6;
		vps = request->reply->vps;
#ifdef WITH_PROXY
	} else if (strncasecmp(name, "proxy-request:", 14) == 0) {
		p += 14;
		if (request->proxy) {
			vps = request->proxy->vps;
		}
	} else if (strncasecmp(name, "proxy-reply:", 12) == 0) {
		p += 12;
		if (request->proxy_reply) {
			vps = request->proxy_reply->vps;
		}
#endif
	} else if (strncasecmp(name, "control:", 8) == 0) {
		p += 8;
		vps = request->config_items;
	} /* else it must be a bare attribute name */

	if (!vps) {
		return NULL;
	}

	dattr = dict_attrbyname(p);
	if (!dattr) {
		fprintf(stderr, "No such attribute %s\n", p);
		return NULL;	/* no such attribute */
	}

	return pairfind(vps, dattr->attr, dattr->vendor);
}
Beispiel #8
0
/* Initialize the pwattr array for supported password encodings. */
void
otp_pwe_init(void)
{
  DICT_ATTR *da;

  /*
   * Setup known password types.  These are pairs.
   * NB: Increase pwattr array size when adding a type.
   *     It should be sized as (number of password types * 2)
   * NB: Array indices must match otp_pwe_t! (see otp.h)
   */
  (void) memset(pwattr, 0, sizeof(pwattr));

  /* PAP */
  if ((da = dict_attrbyname("User-Password")) != NULL) {
    pwattr[0] = da->attr;
    pwattr[1] = da->attr;
  }

  /* CHAP */
  if ((da = dict_attrbyname("CHAP-Challenge")) != NULL) {
    pwattr[2] = da->attr;
    if ((da = dict_attrbyname("CHAP-Password")) != NULL)
      pwattr[3] = da->attr;
    else
      pwattr[2] = 0;
  }

#if 0
  /* MS-CHAP (recommended not to use) */
  if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {
    pwattr[4] = da->attr;
    if ((da = dict_attrbyname("MS-CHAP-Response")) != NULL)
      pwattr[5] = da->attr;
    else
      pwattr[4] = 0;
  }
#endif /* 0 */

  /* MS-CHAPv2 */
  if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {
    pwattr[6] = da->attr;
    if ((da = dict_attrbyname("MS-CHAP2-Response")) != NULL)
      pwattr[7] = da->attr;
    else
      pwattr[6] = 0;
  }
}
Beispiel #9
0
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
 *
 * VPTs are used in various places where we need to pre-parse configuration
 * sections into attribute mappings.
 *
 * Note: name field is just a copy of the input pointer, if you know that
 * string might be freed before you're done with the vpt use radius_attr2tmpl
 * instead.
 *
 * @param[in] name attribute name including qualifiers.
 * @param[out] vpt to modify.
 * @param[in] request_def The default request to insert unqualified
 *	attributes into.
 * @param[in] list_def The default list to insert unqualified attributes into.
 * @return -1 on error or 0 on success.
 */
int radius_parse_attr(char const *name, value_pair_tmpl_t *vpt,
		      request_refs_t request_def,
		      pair_lists_t list_def)
{
	DICT_ATTR const *da;
	char const *p;
	size_t len;

	memset(vpt, 0, sizeof(*vpt));
	vpt->name = name;
	p = name;

	vpt->request = radius_request_name(&p, request_def);
	len = p - name;
	if (vpt->request == REQUEST_UNKNOWN) {
		ERROR("Invalid request qualifier \"%.*s\"", (int) len, name);
		return -1;
	}
	name += len;

	vpt->list = radius_list_name(&p, list_def);
	if (vpt->list == PAIR_LIST_UNKNOWN) {
		len = p - name;
		ERROR("Invalid list qualifier \"%.*s\"", (int) len, name);
		return -1;
	}

	if (*p == '\0') {
		vpt->type = VPT_TYPE_LIST;
		return 0;
	}

	da = dict_attrbyname(p);
	if (!da) {
		da = dict_attrunknownbyname(p, false);
		if (!da) {
			ERROR("Unknown attribute \"%s\"", p);
			return -1;
		}
	}
	vpt->da = da;

	vpt->type = VPT_TYPE_ATTR;
	return 0;
}
Beispiel #10
0
/*
 *	find the appropriate registered xlat function.
 */
static xlat_t *xlat_find(const char *module)
{
	xlat_t my_xlat;

	/*
	 *	Look for dictionary attributes first.
	 */
	if ((dict_attrbyname(module) != NULL) ||
	    (strchr(module, '[') != NULL) ||
	    (strchr(module, '#') != NULL)) {
		module = "request";
	}

	strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
	my_xlat.length = strlen(my_xlat.module);

	return rbtree_finddata(xlat_root, &my_xlat);
}
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sometimes_t *inst = instance;

	/*
	 *	Convert the rcode string to an int, and get rid of it
	 */
	inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
	if (inst->rcode == RLM_MODULE_UNKNOWN) {
		cf_log_err_cs(conf, "Unknown module return code '%s'", inst->rcode_str);
		return -1;
	}

	inst->da = dict_attrbyname(inst->key);
	rad_assert(inst->da);

	return 0;
}
static int sometimes_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_sometimes_t *inst;

	/*
	 *	Set up a storage area for instance data
	 */
	inst = rad_malloc(sizeof(*inst));
	if (!inst) {
		return -1;
	}
	memset(inst, 0, sizeof(*inst));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, inst, module_config) < 0) {
		sometimes_detach(inst);
		return -1;
	}

	/*
	 *	Convert the rcode string to an int, and get rid of it
	 */
	inst->rcode = str2rcode(inst->rcode_str);
	if (inst->rcode == -1) {
		sometimes_detach(inst);
		return -1;
	}

	inst->da = dict_attrbyname(inst->key);
	if (!inst->da) {
		radlog(L_ERR, "rlm_sometimes; Unknown attributes %s", inst->key);
		return -1;
		return -1;
	}

	*instance = inst;

	return 0;
}
Beispiel #13
0
/*
 *	Evaluate an assignment
 *
 *	Not really used much...
 */
static int evaluate_assignment(UNUSED policy_state_t *state, const policy_item_t *item)
{
	const policy_assignment_t *this;
#if 0
	const DICT_ATTR *dattr;
#endif

	this = (const policy_assignment_t *) item;

	rad_assert(this->lhs != NULL);
	rad_assert(this->rhs != NULL);

#if 0
	dattr = dict_attrbyname(this->lhs);
	if (!dattr) {
		fprintf(stderr, "HUH?\n");
		return 0;
	}
#endif

	return 1;
}
Beispiel #14
0
static int arp_socket_decode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
{
	int i;
	arp_over_ether_t const *arp;
	uint8_t const *p;

	arp = (arp_over_ether_t const *) request->packet->data;
	/*
	 *	arp_socket_recv() takes care of validating it's really
	 *	our kind of ARP.
	 */
	for (i = 0, p = (uint8_t const *) arp;
	     header_names[i].name != NULL;
	     p += header_names[i].len, i++) {
		ssize_t len;
		DICT_ATTR const *da;
		VALUE_PAIR *vp;

		da = dict_attrbyname(header_names[i].name);
		if (!da) return 0;

		vp = NULL;
		len = data2vp(request->packet, NULL, NULL, da, p,
			      header_names[i].len, header_names[i].len,
			      &vp);
		if (len <= 0) {
			RDEBUG("Failed decoding %s: %s",
			       header_names[i].name, fr_strerror());
			return 0;
		}

		debug_pair(vp);
		pairadd(&request->packet->vps, vp);
	}

	return 0;
}
Beispiel #15
0
/** Return a VP from the specified request.
 *
 * @param request current request.
 * @param name attribute name including qualifiers.
 * @param vp_p where to write the pointer to the resolved VP. 
 *	Will be NULL if the attribute couldn't be resolved.
 * @return False if either the attribute or qualifier were invalid, else true
 */
int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p)
{
	VALUE_PAIR **vps;
	pair_lists_t list;
	
	const DICT_ATTR *da;
	
	*vp_p = NULL;
	
	if (!radius_ref_request(&request, &name)) {
		RDEBUG("WARNING: Attribute name refers to outer request"
		       " but not in a tunnel.");
		return TRUE;	/* Discuss, we don't actually know if
				   the attrname was valid... */
	}
	
	list = radius_list_name(&name, PAIR_LIST_REQUEST);
	if (list == PAIR_LIST_UNKNOWN) {
		RDEBUG("ERROR: Invalid list qualifier");
		return FALSE;
	}
	
	da = dict_attrbyname(name);
	if (!da) {
		RDEBUG("ERROR: Attribute \"%s\" unknown", name);
		return FALSE;
	}

	vps = radius_list(request, list);
	rad_assert(vps);
	
	/*
	 *	May not may not be found, but it *is* a known name.
	 */
	*vp_p = pairfind(*vps, da->attr, da->vendor);
	return TRUE;
}
Beispiel #16
0
/*
 *	*presult is "did comparison match or not"
 */
static int radius_do_cmp(REQUEST *request, int *presult,
			 FR_TOKEN lt, const char *pleft, FR_TOKEN token,
			 FR_TOKEN rt, const char *pright,
			 int cflags, int modreturn)
{
	int result;
	uint32_t lint, rint;
	VALUE_PAIR *vp = NULL;
#ifdef HAVE_REGEX_H
	char buffer[8192];
#else
	cflags = cflags;	/* -Wunused */
#endif

	rt = rt;		/* -Wunused */

	if (lt == T_BARE_WORD) {
		/*
		 *	Maybe check the last return code.
		 */
		if (token == T_OP_CMP_TRUE) {
			int isreturn;

			/*
			 *	Looks like a return code, treat is as such.
			 */
			isreturn = fr_str2int(modreturn_table, pleft, -1);
			if (isreturn != -1) {
				*presult = (modreturn == isreturn);
				return TRUE;
			}
		}

		/*
		 *	Bare words on the left can be attribute names.
		 */
		if (radius_get_vp(request, pleft, &vp)) {
			VALUE_PAIR myvp;

			/*
			 *	VP exists, and that's all we're looking for.
			 */
			if (token == T_OP_CMP_TRUE) {
				*presult = (vp != NULL);
				return TRUE;
			}

			if (!vp) {
				DICT_ATTR *da;
				
				/*
				 *	The attribute on the LHS may
				 *	have been a dynamically
				 *	registered callback.  i.e. it
				 *	doesn't exist as a VALUE_PAIR.
				 *	If so, try looking for it.
				 */
				da = dict_attrbyname(pleft);
				if (da && (da->vendor == 0) && radius_find_compare(da->attr)) {
					VALUE_PAIR *check = pairmake(pleft, pright, token);
					*presult = (radius_callback_compare(request, NULL, check, NULL, NULL) == 0);
					RDEBUG3("  Callback returns %d",
						*presult);
					pairfree(&check);
					return TRUE;
				}
				
				RDEBUG2("    (Attribute %s was not found)",
				       pleft);
				*presult = 0;
				return TRUE;
			}

#ifdef HAVE_REGEX_H
			/*
			 * 	Regex comparisons treat everything as
			 *	strings.
			 */
			if ((token == T_OP_REG_EQ) ||
			    (token == T_OP_REG_NE)) {
				vp_prints_value(buffer, sizeof(buffer), vp, 0);
				pleft = buffer;
				goto do_checks;
			}
#endif

			memcpy(&myvp, vp, sizeof(myvp));
			if (!pairparsevalue(&myvp, pright)) {
				RDEBUG2("Failed parsing \"%s\": %s",
				       pright, fr_strerror());
				return FALSE;
			}

			myvp.operator = token;
			*presult = paircmp(&myvp, vp);
			RDEBUG3("  paircmp -> %d", *presult);
			return TRUE;
		} /* else it's not a VP in a list */
	}

#ifdef HAVE_REGEX_H
	do_checks:
#endif
	switch (token) {
	case T_OP_GE:
	case T_OP_GT:
	case T_OP_LE:
	case T_OP_LT:
		if (!all_digits(pright)) {
			RDEBUG2("    (Right field is not a number at: %s)", pright);
			return FALSE;
		}
		rint = strtoul(pright, NULL, 0);
		if (!all_digits(pleft)) {
			RDEBUG2("    (Left field is not a number at: %s)", pleft);
			return FALSE;
		}
		lint = strtoul(pleft, NULL, 0);
		break;
		
	default:
		lint = rint = 0;  /* quiet the compiler */
		break;
	}
	
	switch (token) {
	case T_OP_CMP_TRUE:
		/*
		 *	Check for truth or falsehood.
		 */
		if (all_digits(pleft)) {
			lint = strtoul(pleft, NULL, 0);
			result = (lint != 0);
			
		} else {
			result = (*pleft != '\0');
		}
		break;
		

	case T_OP_CMP_EQ:
		result = (strcmp(pleft, pright) == 0);
		break;
		
	case T_OP_NE:
		result = (strcmp(pleft, pright) != 0);
		break;
		
	case T_OP_GE:
		result = (lint >= rint);
		break;
		
	case T_OP_GT:
		result = (lint > rint);
		break;
		
	case T_OP_LE:
		result = (lint <= rint);
		break;
		
	case T_OP_LT:
		result = (lint < rint);
		break;

#ifdef HAVE_REGEX_H
	case T_OP_REG_EQ: {
		int i, compare;
		regex_t reg;
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
		
		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, pright, cflags);
		if (compare != 0) {
			if (debug_flag) {
				char errbuf[128];

				regerror(compare, &reg, errbuf, sizeof(errbuf));
				DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
			}
			return FALSE;
		}

		compare = regexec(&reg, pleft,
				  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);
		
		/*
		 *	Add new %{0}, %{1}, etc.
		 */
		if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
			char *r;

			free(request_data_get(request, request,
					      REQUEST_DATA_REGEX | i));

			/*
			 *	No %{i}, skip it.
			 *	We MAY have %{2} without %{1}.
			 */
			if (rxmatch[i].rm_so == -1) continue;
			
			/*
			 *	Copy substring into allocated buffer
			 */
			r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1);
			memcpy(r, pleft + rxmatch[i].rm_so,
			       rxmatch[i].rm_eo - rxmatch[i].rm_so);
			r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';

			request_data_add(request, request,
					 REQUEST_DATA_REGEX | i,
					 r, free);
		}
		result = (compare == 0);
	}
		break;
		
	case T_OP_REG_NE: {
		int compare;
		regex_t reg;
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
		
		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, pright, cflags);
		if (compare != 0) {
			if (debug_flag) {
				char errbuf[128];

				regerror(compare, &reg, errbuf, sizeof(errbuf));
				DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
			}
			return FALSE;
		}

		compare = regexec(&reg, pleft,
				  REQUEST_MAX_REGEX + 1,
				  rxmatch, 0);
		regfree(&reg);
		
		result = (compare != 0);
	}
		break;
#endif
		
	default:
		DEBUG("ERROR: Comparison operator %s is not supported",
		      fr_token_name(token));
		result = FALSE;
		break;
	}
	
	*presult = result;
	return TRUE;
}
Beispiel #17
0
int main(int argc, char **argv)
{
	char *p;
	int c;
	char const *radius_dir = RADDBDIR;
	char const *dict_dir = DICTDIR;
	char const *filename = NULL;
	DICT_ATTR const *da;

	fr_debug_lvl = 0;

	while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:"
	)) != EOF) switch(c) {
		case 'D':
			dict_dir = optarg;
			break;

		case 'd':
			radius_dir = optarg;
			break;
		case 'f':
			filename = optarg;
			break;
		case 'i':
			iface = optarg;
			break;
		case 'r':
			if (!isdigit((int) *optarg))
				usage();
			retries = atoi(optarg);
			if ((retries == 0) || (retries > 1000)) usage();
			break;
		case 't':
			if (!isdigit((int) *optarg))
				usage();
			timeout = atof(optarg);
			break;
		case 'v':
			printf("%s\n", dhcpclient_version);
			exit(0);

		case 'x':
			fr_debug_lvl++;
			fr_log_fp = stdout;
			break;
		case 'h':
		default:
			usage();
	}
	argc -= (optind - 1);
	argv += (optind - 1);

	if (argc < 2) usage();

	/*	convert timeout to a struct timeval */
#define USEC 1000000
	tv_timeout.tv_sec = timeout;
	tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC);

	if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
		fr_perror("radclient");
		return 1;
	}

	if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
		fr_perror("radclient");
		return 1;
	}
	fr_strerror();	/* Clear the error buffer */

	/*
	 *	Ensure that dictionary.dhcp is loaded.
	 */
	da = dict_attrbyname("DHCP-Message-Type");
	if (!da) {
		if (dict_read(dict_dir, "dictionary.dhcp") < 0) {
			fprintf(stderr, "Failed reading dictionary.dhcp: %s\n",
				fr_strerror());
			return -1;
		}
	}

	/*
	 *	Resolve hostname.
	 */
	server_ipaddr.af = AF_INET;
	if (strcmp(argv[1], "-") != 0) {
		char const *hostname = argv[1];
		char const *portname = argv[1];
		char buffer[256];

		if (*argv[1] == '[') { /* IPv6 URL encoded */
			p = strchr(argv[1], ']');
			if ((size_t) (p - argv[1]) >= sizeof(buffer)) {
				usage();
			}

			memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
			buffer[p - argv[1] - 1] = '\0';

			hostname = buffer;
			portname = p + 1;

		}
		p = strchr(portname, ':');
		if (p && (strchr(p + 1, ':') == NULL)) {
			*p = '\0';
			portname = p + 1;
		} else {
			portname = NULL;
		}

		if (ip_hton(&server_ipaddr, AF_INET, hostname, false) < 0) {
			fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno));
			fr_exit_now(1);
		}

		/*
		 *	Strip port from hostname if needed.
		 */
		if (portname) server_port = atoi(portname);
	}

	/*
	 *	See what kind of request we want to send.
	 */
	if (argc >= 3) {
		if (!isdigit((int) argv[2][0])) {
			packet_code = fr_str2int(request_types, argv[2], -2);
			if (packet_code == -2) {
				fprintf(stderr, "Unknown packet type: %s\n", argv[2]);
				usage();
			}
		} else {
			packet_code = atoi(argv[2]);
		}
	}
	if (server_port == 0) server_port = 67;

	request_init(filename);

	/*
	 *	No data read.  Die.
	 */
	if (!request || !request->vps) {
		fprintf(stderr, "dhcpclient: Nothing to send.\n");
		fr_exit_now(1);
	}

	/*
	 *	Sanity check.
	 */
	if (!request->code) {
		fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n",
			(argc >= 3) ? "'auto'" : "unspecified");
		exit(1);
	}

	if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) {
		/*	These kind of packets do not get a reply, so don't wait for one. */
		reply_expected = false;
	}

	/*
	 *	Bind to the first specified IP address and port.
	 *	This means we ignore later ones.
	 */
	if (request->src_ipaddr.af == AF_UNSPEC) {
		memset(&client_ipaddr, 0, sizeof(client_ipaddr));
		client_ipaddr.af = server_ipaddr.af;
		client_port = 0;
	} else {
		client_ipaddr = request->src_ipaddr;
		client_port = request->src_port;
	}

	/* set "raw mode" if an interface is specified and if destination IP address is the broadcast address. */
	if (iface) {
		iface_ind = if_nametoindex(iface);
		if (iface_ind <= 0) {
			fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface);
			fr_exit_now(1);
		}

		if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) {
			fprintf(stderr, "dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind);
			raw_mode = true;
		}
	}

	if (request->src_ipaddr.af == AF_UNSPEC) {
		request->src_ipaddr = client_ipaddr;
		request->src_port = client_port;
	}
	if (request->dst_ipaddr.af == AF_UNSPEC) {
		request->dst_ipaddr = server_ipaddr;
		request->dst_port = server_port;
	}

	/*
	 *	Encode the packet
	 */
	if (fr_dhcp_encode(request) < 0) {
		fprintf(stderr, "dhcpclient: failed encoding: %s\n",
			fr_strerror());
		fr_exit_now(1);
	}
	if (fr_debug_lvl) print_hex(request);

#ifdef HAVE_LIBPCAP
	if (raw_mode) {
		send_with_pcap();
	} else
#endif
	{
		send_with_socket();
	}

	if (reply && fr_debug_lvl) print_hex(reply);

	if (reply && fr_dhcp_decode(reply) < 0) {
		fprintf(stderr, "dhcpclient: failed decoding\n");
		return 1;
	}

	dict_free();

	if (success) return 0;

	return 1;
}
Beispiel #18
0
/*
 *	Find the named user in this modules database.  Create the set
 *	of attribute-value pairs to check and reply with for this user
 *	from the database. The authentication code only needs to check
 *	the password, the rest is done here.
 */
static int sqlcounter_authorize(void *instance, REQUEST *request)
{
	rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance;
	int ret=RLM_MODULE_NOOP;
	int counter=0;
	int res=0;
	DICT_ATTR *dattr;
	VALUE_PAIR *key_vp, *check_vp;
	VALUE_PAIR *reply_item;
	char msg[128];
	char querystr[MAX_QUERY_LEN];
	char responsestr[MAX_QUERY_LEN];

	/* quiet the compiler */
	instance = instance;
	request = request;

	/*
	 *	Before doing anything else, see if we have to reset
	 *	the counters.
	 */
	if (data->reset_time && (data->reset_time <= request->timestamp)) {

		/*
		 *	Re-set the next time and prev_time for this counters range
		 */
		data->last_reset = data->reset_time;
		find_next_reset(data,request->timestamp);
	}


	/*
	 *      Look for the key.  User-Name is special.  It means
	 *      The REAL username, after stripping.
	 */
	DEBUG2("rlm_sqlcounter: Entering module authorize code");
	key_vp = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr);
	if (key_vp == NULL) {
		DEBUG2("rlm_sqlcounter: Could not find Key value pair");
		return ret;
	}

	/*
	 *      Look for the check item
	 */
	if ((dattr = dict_attrbyname(data->check_name)) == NULL) {
		return ret;
	}
	/* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", dattr->attr); */
	if ((check_vp= pairfind(request->config_items, dattr->attr)) == NULL) {
		DEBUG2("rlm_sqlcounter: Could not find Check item value pair");
		return ret;
	}

	/* first, expand %k, %b and %e in query */
	sqlcounter_expand(querystr, MAX_QUERY_LEN, data->query, instance);

	/* second, xlat any request attribs in query */
	radius_xlat(responsestr, MAX_QUERY_LEN, querystr, request, sql_escape_func);

	/* third, wrap query with sql module & expand */
	snprintf(querystr, sizeof(querystr), "%%{%%S:%s}", responsestr);
	sqlcounter_expand(responsestr, MAX_QUERY_LEN, querystr, instance);

	/* Finally, xlat resulting SQL query */
	radius_xlat(querystr, MAX_QUERY_LEN, responsestr, request, sql_escape_func);

	counter = atoi(querystr);


	/*
	 * Check if check item > counter
	 */
	res=check_vp->lvalue - counter;
	if (res > 0) {
		DEBUG2("rlm_sqlcounter: (Check item - counter) is greater than zero");
		/*
		 *	We are assuming that simultaneous-use=1. But
		 *	even if that does not happen then our user
		 *	could login at max for 2*max-usage-time Is
		 *	that acceptable?
		 */

		/*
		 *	User is allowed, but set Session-Timeout.
		 *	Stolen from main/auth.c
		 */

		/*
		 *	If we are near a reset then add the next
		 *	limit, so that the user will not need to
		 *	login again
		 */
		if (data->reset_time && (
			res >= (data->reset_time - request->timestamp))) {
			res = data->reset_time - request->timestamp;
			res += check_vp->lvalue;
		}

		if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) {
			if (reply_item->lvalue > res)
				reply_item->lvalue = res;
		} else {
			if ((reply_item = paircreate(PW_SESSION_TIMEOUT, PW_TYPE_INTEGER)) == NULL) {
				radlog(L_ERR|L_CONS, "no memory");
				return RLM_MODULE_NOOP;
			}
			reply_item->lvalue = res;
			pairadd(&request->reply->vps, reply_item);
		}

		ret=RLM_MODULE_OK;

		DEBUG2("rlm_sqlcounter: Authorized user %s, check_item=%d, counter=%d",
				key_vp->strvalue,check_vp->lvalue,counter);
		DEBUG2("rlm_sqlcounter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d",
				key_vp->strvalue,reply_item->lvalue);
	}
	else{
		char module_fmsg[MAX_STRING_LEN];
		VALUE_PAIR *module_fmsg_vp;

		DEBUG2("rlm_sqlcounter: (Check item - counter) is less than zero");

		/*
		 * User is denied access, send back a reply message
		 */
		snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", data->reset);
		reply_item=pairmake("Reply-Message", msg, T_OP_EQ);
		pairadd(&request->reply->vps, reply_item);

		snprintf(module_fmsg, sizeof(module_fmsg), "rlm_sqlcounter: Maximum %s usage time reached", data->reset);
		module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
		pairadd(&request->packet->vps, module_fmsg_vp);

		ret=RLM_MODULE_REJECT;

		DEBUG2("rlm_sqlcounter: Rejected user %s, check_item=%d, counter=%d",
				key_vp->strvalue,check_vp->lvalue,counter);
	}

	return ret;
}
Beispiel #19
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_sql_t *inst = instance;

	/*
	 *	Hack...
	 */
	inst->config = &inst->myconfig;
	inst->cs = conf;

	inst->config->xlat_name = cf_section_name2(conf);
	if (!inst->config->xlat_name) {
		inst->config->xlat_name = cf_section_name1(conf);
	} else {
		char *group_name;
		DICT_ATTR const *da;
		ATTR_FLAGS flags;

		/*
		 *	Allocate room for <instance>-SQL-Group
		 */
		group_name = talloc_typed_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name);
		DEBUG("rlm_sql (%s): Creating new attribute %s",
		      inst->config->xlat_name, group_name);

		memset(&flags, 0, sizeof(flags));
		if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s: %s", inst->config->xlat_name, group_name,
			       fr_strerror());
			return -1;
		}

		da = dict_attrbyname(group_name);
		if (!da) {
			ERROR("rlm_sql (%s): Failed to create "
			       "attribute %s", inst->config->xlat_name, group_name);
			return -1;
		}

		if (inst->config->groupmemb_query &&
		    inst->config->groupmemb_query[0]) {
			DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
			      inst->config->xlat_name, group_name);
			paircompare_register(da, dict_attrbyvalue(PW_USER_NAME, 0),
					     false, sql_groupcmp, inst);
		}
	}

	rad_assert(inst->config->xlat_name);

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(conf, inst, &inst->config->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(conf, inst, &inst->config->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		cf_log_err_cs(conf, "Invalid configuration");
		return -1;
	}

	/*
	 *	Cache the SQL-User-Name DICT_ATTR, so we can be slightly
	 *	more efficient about creating SQL-User-Name attributes.
	 */
	inst->sql_user = dict_attrbyname("SQL-User-Name");
	if (!inst->sql_user) {
		return -1;
	}

	/*
	 *	Export these methods, too.  This avoids RTDL_GLOBAL.
	 */
	inst->sql_set_user		= sql_set_user;
	inst->sql_get_socket		= sql_get_socket;
	inst->sql_release_socket	= sql_release_socket;
	inst->sql_escape_func		= sql_escape_func;
	inst->sql_query			= rlm_sql_query;
	inst->sql_select_query		= rlm_sql_select_query;
	inst->sql_fetch_row		= rlm_sql_fetch_row;

	/*
	 *	Register the SQL xlat function
	 */
	xlat_register(inst->config->xlat_name, sql_xlat, sql_escape_func, inst);

	/*
	 *	Sanity check for crazy people.
	 */
	if (strncmp(inst->config->sql_driver_name, "rlm_sql_", 8) != 0) {
		ERROR("rlm_sql (%s): \"%s\" is NOT an SQL driver!",
		       inst->config->xlat_name, inst->config->sql_driver_name);
		return -1;
	}

	/*
	 *	Load the appropriate driver for our database
	 */
	inst->handle = lt_dlopenext(inst->config->sql_driver_name);
	if (!inst->handle) {
		ERROR("Could not link driver %s: %s",
		       inst->config->sql_driver_name,
		       dlerror());
		ERROR("Make sure it (and all its dependent libraries!)"
		       "are in the search path of your system's ld");
		return -1;
	}

	inst->module = (rlm_sql_module_t *) dlsym(inst->handle,
						  inst->config->sql_driver_name);
	if (!inst->module) {
		ERROR("Could not link symbol %s: %s",
		       inst->config->sql_driver_name,
		       dlerror());
		return -1;
	}

	if (inst->module->mod_instantiate) {
		CONF_SECTION *cs;
		char const *name;

		name = strrchr(inst->config->sql_driver_name, '_');
		if (!name) {
			name = inst->config->sql_driver_name;
		} else {
			name++;
		}

		cs = cf_section_sub_find(conf, name);
		if (!cs) {
			cs = cf_section_alloc(conf, name, NULL);
			if (!cs) {
				return -1;
			}
		}

		/*
		 *	It's up to the driver to register a destructor
		 */
		if (inst->module->mod_instantiate(cs, inst->config) < 0) {
			return -1;
		}
	}

	inst->lf = fr_logfile_init(inst);
	if (!inst->lf) {
		cf_log_err_cs(conf, "Failed creating log file context");
		return -1;
	}

	INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked",
	       inst->config->xlat_name, inst->config->sql_driver_name,
	       inst->module->name);

	/*
	 *	Initialise the connection pool for this instance
	 */
	INFO("rlm_sql (%s): Attempting to connect to database \"%s\"",
	       inst->config->xlat_name, inst->config->sql_db);

	if (sql_socket_pool_init(inst) < 0) return -1;

	if (inst->config->groupmemb_query &&
	    inst->config->groupmemb_query[0]) {
		paircompare_register(dict_attrbyvalue(PW_SQL_GROUP, 0),
				dict_attrbyvalue(PW_USER_NAME, 0), false, sql_groupcmp, inst);
	}

	if (inst->config->do_clients) {
		if (generate_sql_clients(inst) == -1){
			ERROR("Failed to load clients from SQL");
			return -1;
		}
	}

	return RLM_MODULE_OK;
}
Beispiel #20
0
/*
 *	Create a VALUE_PAIR from an ASCII attribute and value.
 */
VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
{
	DICT_ATTR	*da;
	VALUE_PAIR	*vp;
	char            *tc, *ts;
	signed char     tag;
	int             found_tag;
	char		buffer[64];
	const char	*attrname = attribute;

	/*
	 *    Check for tags in 'Attribute:Tag' format.
	 */
	found_tag = 0;
	tag = 0;

	ts = strrchr(attribute, ':');
	if (ts && !ts[1]) {
		fr_strerror_printf("Invalid tag for attribute %s", attribute);
		return NULL;
	}

	if (ts && ts[1]) {
		strlcpy(buffer, attribute, sizeof(buffer));
		attrname = buffer;
		ts = strrchr(attrname, ':');

	         /* Colon found with something behind it */
	         if (ts[1] == '*' && ts[2] == 0) {
		         /* Wildcard tag for check items */
		         tag = TAG_ANY;
			 *ts = 0;
		 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
		         /* It's not a wild card tag */
		         tag = strtol(ts + 1, &tc, 0);
			 if (tc && !*tc && TAG_VALID_ZERO(tag))
				 *ts = 0;
			 else tag = 0;
		 } else {
			 fr_strerror_printf("Invalid tag for attribute %s", attribute);
			 return NULL;
		 }
		 found_tag = 1;
	}

	/*
	 *	It's not found in the dictionary, so we use
	 *	another method to create the attribute.
	 */
	if ((da = dict_attrbyname(attrname)) == NULL) {
		return pairmake_any(attrname, value, operator);
	}

	if ((vp = pairalloc(da)) == NULL) {
		fr_strerror_printf("out of memory");
		return NULL;
	}
	vp->operator = (operator == 0) ? T_OP_EQ : operator;

	/*      Check for a tag in the 'Merit' format of:
	 *      :Tag:Value.  Print an error if we already found
	 *      a tag in the Attribute.
	 */

	if (value && (*value == ':' && da->flags.has_tag)) {
	        /* If we already found a tag, this is invalid */
	        if(found_tag) {
			fr_strerror_printf("Duplicate tag %s for attribute %s",
				   value, vp->name);
			DEBUG("Duplicate tag %s for attribute %s\n",
				   value, vp->name);
		        pairbasicfree(vp);
			return NULL;
		}
	        /* Colon found and attribute allows a tag */
	        if (value[1] == '*' && value[2] == ':') {
		       /* Wildcard tag for check items */
		       tag = TAG_ANY;
		       value += 3;
		} else {
	               /* Real tag */
		       tag = strtol(value + 1, &tc, 0);
		       if (tc && *tc==':' && TAG_VALID_ZERO(tag))
			    value = tc + 1;
		       else tag = 0;
		}
		found_tag = 1;
	}

	if (found_tag) {
	  vp->flags.tag = tag;
	}

	switch (vp->operator) {
	default:
		break;

		/*
		 *      For =* and !* operators, the value is irrelevant
		 *      so we return now.
		 */
	case T_OP_CMP_TRUE:
	case T_OP_CMP_FALSE:
		vp->vp_strvalue[0] = '\0';
		vp->length = 0;
	        return vp;
		break;

		/*
		 *	Regular expression comparison of integer attributes
		 *	does a STRING comparison of the names of their
		 *	integer attributes.
		 */
	case T_OP_REG_EQ:	/* =~ */
	case T_OP_REG_NE:	/* !~ */
		if (!value) {
			fr_strerror_printf("No regular expression found in %s",
					   vp->name);
		        pairbasicfree(vp);
			return NULL;
		}
	  
		strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
		vp->length = strlen(vp->vp_strvalue);
		/*
		 *	If anything goes wrong, this is a run-time error,
		 *	not a compile-time error.
		 */
		return vp;

	}

	/*
	 *	FIXME: if (strcasecmp(attribute, vp->name) != 0)
	 *	then the user MAY have typed in the attribute name
	 *	as Vendor-%d-Attr-%d, and the value MAY be octets.
	 *
	 *	We probably want to fix pairparsevalue to accept
	 *	octets as values for any attribute.
	 */
	if (value && (pairparsevalue(vp, value) == NULL)) {
		pairbasicfree(vp);
		return NULL;
	}

	return vp;
}
Beispiel #21
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int sqlcounter_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_sqlcounter_t *data;
	DICT_ATTR *dattr;
	ATTR_FLAGS flags;
	time_t now;
	char buffer[MAX_STRING_LEN];

	/*
	 *	Set up a storage area for instance data
	 */
	data = rad_malloc(sizeof(*data));
	if (!data) {
		return -1;
	}
	memset(data, 0, sizeof(*data));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, data, module_config) < 0) {
		free(data);
		return -1;
	}

	/*
	 *	No query, die.
	 */
	if (data->query == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'query' must be set.");
		return -1;
	}

	/*
	 *	Safe characters list for sql queries. Everything else is
	 *	replaced rwith their mime-encoded equivalents.
	 */
	allowed_chars = data->allowed_chars;

	/*
	 *	Discover the attribute number of the key.
	 */
	if (data->key_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'key' must be set.");
		return -1;
	}
	sql_escape_func(buffer, sizeof(buffer), data->key_name);
	if (strcmp(buffer, data->key_name) != 0) {
		radlog(L_ERR, "rlm_sqlcounter: The value for option 'key' is too long or contains unsafe characters.");
		return -1;
	}
	dattr = dict_attrbyname(data->key_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: No such attribute %s",
				data->key_name);
		return -1;
	}
	data->key_attr = dattr->attr;

	/*
	 *	Check the "sqlmod-inst" option.
	 */
	if (data->sqlmod_inst == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'sqlmod-inst' must be set.");
		return -1;
	}
	sql_escape_func(buffer, sizeof(buffer), data->sqlmod_inst);
	if (strcmp(buffer, data->sqlmod_inst) != 0) {
		radlog(L_ERR, "rlm_sqlcounter: The value for option 'sqlmod-inst' is too long or contains unsafe characters.");
		return -1;
	}

	/*
	 *  Create a new attribute for the counter.
	 */
	if (data->counter_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'counter-name' must be set.");
		return -1;
	}

	memset(&flags, 0, sizeof(flags));
	dict_addattr(data->counter_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(data->counter_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create counter attribute %s",
				data->counter_name);
		return -1;
	}
	data->dict_attr = dattr->attr;
	DEBUG2("rlm_sqlcounter: Counter attribute %s is number %d",
			data->counter_name, data->dict_attr);

	/*
	 * Create a new attribute for the check item.
	 */
	if (data->check_name == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'check-name' must be set.");
		return -1;
	}
	dict_addattr(data->check_name, 0, PW_TYPE_INTEGER, -1, flags);
	dattr = dict_attrbyname(data->check_name);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: Failed to create check attribute %s",
				data->counter_name);
		return -1;
	}
	DEBUG2("rlm_sqlcounter: Check attribute %s is number %d",
			data->check_name, dattr->attr);

	/*
	 *  Discover the end of the current time period.
	 */
	if (data->reset == NULL) {
		radlog(L_ERR, "rlm_sqlcounter: 'reset' must be set.");
		return -1;
	}
	now = time(NULL);
	data->reset_time = 0;

	if (find_next_reset(data,now) == -1)
		return -1;

	/*
	 *  Discover the beginning of the current time period.
	 */
	data->last_reset = 0;

	if (find_prev_reset(data,now) == -1)
		return -1;


	/*
	 *	Register the counter comparison operation.
	 */
	paircompare_register(data->dict_attr, 0, sqlcounter_cmp, data);

	*instance = data;

	return 0;
}
Beispiel #22
0
static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
				       char const **error)
{
	ssize_t slen;
	char *p, *q, *brace;
	char const *attrname;
	xlat_exp_t *node;

	rad_assert(fmt[0] == '%');
	rad_assert(fmt[1] == '{');

	/*
	 *	%{%{...}:-bar}
	 */
	if ((fmt[2] == '%') && (fmt[3] == '{')) {
		return xlat_tokenize_alternation(ctx, fmt, head, error);
	}

	XLAT_DEBUG("EXPANSION: %s", fmt);
	node = talloc_zero(ctx, xlat_exp_t);
	attrname = node->fmt = fmt + 2;
	node->len = 0;

#ifdef HAVE_REGEX_H
	/*
	 *	Handle regex's specially.
	 */
	if (isdigit((int) fmt[2]) && (fmt[3] == '}')) {
		if (fmt[2] == '9') {
			talloc_free(node);
			*error = "Invalid regex reference";
			return -2;
		}

		XLAT_DEBUG("REGEX: %s", fmt);
		fmt[3] = '\0';
		node->num = fmt[2] - '0'; /* ASCII */

		node->type = XLAT_REGEX;
		*head = node;
		return 4;
	}
#endif /* HAVE_REGEX_H */

	/*
	 *	%{Attr-Name}
	 *	%{Attr-Name[#]}
	 *	%{Tunnel-Password:1}
	 *	%{Tunnel-Password:1[#]}
	 *	%{request:Attr-Name}
	 *	%{request:Tunnel-Password:1}
	 *	%{request:Tunnel-Password:1[#]}
	 *	%{mod:foo}
	 */
	q = brace = NULL;
	for (p = fmt + 2; *p != '\0'; p++) {
		if (*p == ':') break;

		if (isspace((int) *p)) break;

		if (*p == '[') break;

		if (*p == '}') break;
	}

	if (*p != ':') p = NULL;

	/*
	 *	Might be a module name reference.
	 */
	if (p) {
		*p = '\0';

		/*
		 *	%{mod:foo}
		 */
		node->xlat = xlat_find(node->fmt);
		if (node->xlat) {
			node->type = XLAT_MODULE;

			XLAT_DEBUG("MOD: %s --> %s", node->fmt, p);
			slen = xlat_tokenize_literal(node, p + 1, &node->child, true, error);
			if (slen <= 0) {
				talloc_free(node);
				return slen - (p - fmt);
			}
			p += slen + 1;

			*head = node;
			rad_assert(node->next == NULL);
			return p - fmt;
		}

		/*
		 *	Modules can have '}' in their RHS, so we
		 *	didn't check for that until now.
		 *
		 *	As of now, node->fmt MUST be a reference to an
		 *	attribute, however complicated.  So it MUST have a closing brace.
		 */
		brace = strchr(p + 1, '}');
		if (!brace) goto no_brace;
		*brace = '\0';

		/*
		 *	%{User-Name}
		 *	%{User-Name[1]}
		 *	%{Tunnel-Password:1}
		 *	%{request:Tunnel-Password:1}
		 *
		 *	<sigh>  The syntax is fairly poor.
		 */
		XLAT_DEBUG("Looking for list in '%s'", attrname);

		/*
		 *	Not a module.  Has to be an attribute
		 *	reference.
		 *
		 *	As of v3, we've removed %{request: ..>} as
		 *	internally registered xlats.
		 */
		*p = ':';
		node->ref = radius_request_name(&attrname, REQUEST_CURRENT);
		rad_assert(node->ref != REQUEST_UNKNOWN);

		node->list = radius_list_name(&attrname, PAIR_LIST_REQUEST);
		if (node->list == PAIR_LIST_UNKNOWN) {
			talloc_free(node);
			*error = "Unknown module";
			return -2;
		}

		/*
		 *	Check for a trailing tag.
		 */
		p = strchr(attrname, ':');
		if (p) *p = '\0';

	} else {
		brace = strchr(attrname, '}');
		if (!brace) {
		no_brace:
			talloc_free(node);
			*error = "No matching closing brace";
			return -1;	/* second character of format string */
		}
		*brace = '\0';

		node->ref = REQUEST_CURRENT;
		node->list = PAIR_LIST_REQUEST;
	}

	*brace = '\0';

	XLAT_DEBUG("Looking for attribute name in %s", attrname);

	/*
	 *	Allow for an array reference.  They come AFTER the
	 *	tag, if the tag exists.  Otherwise, they come after
	 *	the attribute name.
	 */
	if (p) {
		q = strchr(p + 1, '[');
	} else {
		q = strchr(attrname, '[');
	}
	if (q) *(q++) = '\0';

	if (!*attrname) {
		talloc_free(node);
		*error = "Empty expression is invalid";
		return -(attrname - fmt);
	}

	/*
	 *	It's either an attribute name, or a Tunnel-Password:TAG
	 *	with the ':' already set to NULL.
	 */
	node->da = dict_attrbyname(attrname);
	if (!node->da) {
		/*
		 *	Foreach.  Maybe other stuff, too.
		 */
		node->xlat = xlat_find(attrname);
		if (node->xlat) {
			node->type = XLAT_VIRTUAL;
			node->fmt = attrname;

			XLAT_DEBUG("VIRTUAL: %s", node->fmt);
			*head = node;
			rad_assert(node->next == NULL);
			brace++;
			return brace - fmt;
		}

		talloc_free(node);
		*error = "Unknown attribute";
		return -(attrname - fmt);
	}

	/*
	 *	Parse the tag.
	 */
	if (p) {
		unsigned long tag;
		char *end;

		if (!node->da->flags.has_tag) {
			talloc_free(node);
			*error = "Attribute cannot have a tag";
			return - (p - fmt);
		}

		tag = strtoul(p + 1, &end, 10);
		p++;

		if (tag == ULONG_MAX) {
			talloc_free(node);
			*error = "Invalid tag value";
			return - (p - fmt);
		}

		node->tag = tag;
		p = end;

		if (*p) {
			talloc_free(node);
			*error = "Unexpected text after tag";
			return - (p - fmt);
		}

	} else {
		node->tag = TAG_ANY;
		/* leave p alone */
	}

	/*
	 *	Check for array reference
	 */
	if (q) {
		unsigned long num;
		char *end;

		p = q;
		if (*p== '#') {
			node->num = 65536;
			p++;

		} else if (*p == '*') {
			node->num = 65537;
			p++;

		} else if (isdigit((int) *p)) {
			num = strtoul(p, &end, 10);
			if ((num == ULONG_MAX) || (num > 65535)) {
				talloc_free(node);
				*error = "Invalid number";
				return - (p - fmt);
			}
			p = end;
			DEBUG("END %s", p);
			node->num = num;

		} else {
			talloc_free(node);
			*error = "Invalid array reference";
			return - (p - fmt);
		}

		if (*p != ']') {
			talloc_free(node);
			*error = "Expected ']'";
			return - (p - fmt);
		}

		p++;
		if (*p) {
			talloc_free(node);
			*error = "Unexpected text after array reference";
			return - (p - fmt);
		}
	}

	rad_assert(!p || (p == brace));

	node->type = XLAT_ATTRIBUTE;
	p = brace + 1;

	*head = node;
	rad_assert(node->next == NULL);
	return p - fmt;
}
Beispiel #23
0
/** Instantiate the module
 *
 * Creates a new instance of the module reading parameters from a configuration section.
 *
 * @param conf to parse.
 * @param instance Where to write pointer to configuration data.
 * @return 0 on success < 0 on failure.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	CONF_SECTION *options;
	ldap_instance_t *inst = instance;

	inst->cs = conf;

	options = cf_section_sub_find(conf, "options");
	if (!options || !cf_pair_find(options, "chase_referrals")) {
		inst->chase_referrals_unset = true;	 /* use OpenLDAP defaults */
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
	}

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		LDAP_ERR("Failed parsing configuration");

		goto error;
	}

	/*
	 *	Sanity checks for cacheable groups code.
	 */
	if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
		if (!inst->groupobj_name_attr) {
			LDAP_ERR("Directive 'group.name_attribute' must be set if cacheable group names are enabled");

			goto error;
		}
	}

	/*
	 *	Check for URLs.  If they're used and the library doesn't support them, then complain.
	 */
	inst->is_url = 0;
	if (ldap_is_ldap_url(inst->server)) {
#ifdef HAVE_LDAP_INITIALIZE
		inst->is_url = 1;
		inst->port = 0;
#else
		LDAP_ERR("Directive 'server' is in URL form but ldap_initialize() is not available");
		goto error;
#endif
	}

	/*
	 *	Workaround for servers which support LDAPS but not START TLS
	 */
	if (inst->port == LDAPS_PORT || inst->tls_mode) {
		inst->tls_mode = LDAP_OPT_X_TLS_HARD;
	} else {
		inst->tls_mode = 0;
	}

#if LDAP_SET_REBIND_PROC_ARGS != 3
	/*
	 *	The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
	 *	variable for the username, password, etc.
	 */
	if (inst->rebind == true) {
		LDAP_ERR("Cannot use 'rebind' directive as this version of libldap does not support the API "
			 "that we need");

		goto error;
	}
#endif

	/*
	 *	Convert scope strings to enumerated constants
	 */
	inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
	if (inst->userobj_scope < 0) {
		LDAP_ERR("Invalid 'user.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->userobj_scope_str);
		goto error;
	}

	inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
	if (inst->groupobj_scope < 0) {
		LDAP_ERR("Invalid 'group.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->groupobj_scope_str);
		goto error;
	}

	inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
	if (inst->clientobj_scope < 0) {
		LDAP_ERR("Invalid 'client.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
			 inst->clientobj_scope_str);
		goto error;
	}

	if (inst->tls_require_cert_str) {
#ifdef LDAP_OPT_X_TLS_NEVER
		/*
		 *	Convert cert strictness to enumerated constants
		 */
		inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
		if (inst->tls_require_cert < 0) {
			LDAP_ERR("Invalid 'tls.require_cert' value \"%s\", expected 'never', 'demand', 'allow', "
				 "'try' or 'hard'", inst->tls_require_cert_str);
			goto error;
		}
#else
		LDAP_ERR("Modifying 'tls.require_cert' is not supported by current version of libldap. "
			 "Please upgrade libldap and rebuild this module");

		goto error;
#endif
	}
	/*
	 *	Build the attribute map
	 */
	if (rlm_ldap_map_verify(inst, &(inst->user_map)) < 0) {
		goto error;
	}

	/*
	 *	Group comparison checks.
	 */
	if (cf_section_name2(conf)) {
		ATTR_FLAGS flags;
		char buffer[256];

		snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
			 inst->xlat_name);
		memset(&flags, 0, sizeof(flags));

		if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating group attribute: %s", fr_strerror());

			return -1;
		}
		inst->group_da = dict_attrbyname(buffer);
		if (!inst->group_da) {
			LDAP_ERR("Failed creating attribute %s", buffer);

			goto error;
		}

		paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
	/*
	 *	Were the default instance
	 */
	} else {
		inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
		paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
				false, rlm_ldap_groupcmp, inst);
	}

	xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);

	/*
	 *	Setup the cache attribute
	 */
	if (inst->cache_attribute) {
		ATTR_FLAGS flags;
		memset(&flags, 0, sizeof(flags));

		if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating cache attribute: %s", fr_strerror());

			return -1;
		}
		inst->cache_da = dict_attrbyname(inst->cache_attribute);
	} else {
		inst->cache_da = inst->group_da;	/* Default to the group_da */
	}

	/*
	 *	Initialize the socket pool.
	 */
	inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL);
	if (!inst->pool) {
		return -1;
	}

	/*
	 *	Bulk load dynamic clients.
	 */
	if (inst->do_clients) {
		if (rlm_ldap_load_clients(inst) < 0) {
			LDAP_ERR("Error loading clients");

			return -1;
		}
	}

	return 0;

error:
	return -1;
}
Beispiel #24
0
/*
 *	Add a value for an attribute to the dictionary.
 */
int dict_addvalue(const char *namestr, const char *attrstr, int value)
{
	size_t		length;
	DICT_ATTR	*dattr;
	DICT_VALUE	*dval;

	static DICT_ATTR *last_attr = NULL;

	if (!*namestr) {
		fr_strerror_printf("dict_addvalue: empty names are not permitted");
		return -1;
	}

	if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
		fr_strerror_printf("dict_addvalue: value name too long");
		return -1;
	}

	if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
		fr_strerror_printf("dict_addvalue: out of memory");
		return -1;
	}
	memset(dval, 0, sizeof(*dval));

	strcpy(dval->name, namestr);
	dval->value = value;

	/*
	 *	Most VALUEs are bunched together by ATTRIBUTE.  We can
	 *	save a lot of lookups on dictionary initialization by
	 *	caching the last attribute.
	 */
	if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
		dattr = last_attr;
	} else {
		dattr = dict_attrbyname(attrstr);
		last_attr = dattr;
	}

	/*
	 *	Remember which attribute is associated with this
	 *	value, if possible.
	 */
	if (dattr) {
		if (dattr->flags.has_value_alias) {
			fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
			return -1;
		}

		dval->attr = dattr->attr;

		/*
		 *	Enforce valid values
		 *
		 *	Don't worry about fixups...
		 */
		switch (dattr->type) {
			case PW_TYPE_BYTE:
				if (value > 255) {
					fr_pool_free(dval);
					fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
					return -1;
				}
				break;
			case PW_TYPE_SHORT:
				if (value > 65535) {
					fr_pool_free(dval);
					fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
					return -1;
				}
				break;

				/*
				 *	Allow octets for now, because
				 *	of dictionary.cablelabs
				 */
			case PW_TYPE_OCTETS:

			case PW_TYPE_INTEGER:
				break;

			default:
				fr_pool_free(dval);
				fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
					   fr_int2str(type_table, dattr->type, "?Unknown?"));
				return -1;
		}

		dattr->flags.has_value = 1;
	} else {
		value_fixup_t *fixup;

		fixup = (value_fixup_t *) malloc(sizeof(*fixup));
		if (!fixup) {
			fr_pool_free(dval);
			fr_strerror_printf("dict_addvalue: out of memory");
			return -1;
		}
		memset(fixup, 0, sizeof(*fixup));

		strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
		fixup->dval = dval;

		/*
		 *	Insert to the head of the list.
		 */
		fixup->next = value_fixup;
		value_fixup = fixup;

		return 0;
	}

	/*
	 *	Add the value into the dictionary.
	 */
	if (!fr_hash_table_insert(values_byname, dval)) {
		if (dattr) {
			DICT_VALUE *old;

			/*
			 *	Suppress duplicates with the same
			 *	name and value.  There are lots in
			 *	dictionary.ascend.
			 */
			old = dict_valbyname(dattr->attr, namestr);
			if (old && (old->value == dval->value)) {
				fr_pool_free(dval);
				return 0;
			}
		}

		fr_pool_free(dval);
		fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
		return -1;
	}

	/*
	 *	There are multiple VALUE's, keyed by attribute, so we
	 *	take care of that here.
	 */
	if (!fr_hash_table_replace(values_byvalue, dval)) {
		fr_strerror_printf("dict_addvalue: Failed inserting value %s",
			   namestr);
		return -1;
	}

	return 0;
}
Beispiel #25
0
/*
 *	Add an attribute to the dictionary.
 */
int dict_addattr(const char *name, int vendor, int type, int value,
		 ATTR_FLAGS flags)
{
	size_t namelen;
	static int      max_attr = 0;
	DICT_ATTR	*attr;

	namelen = strlen(name);
	if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
		fr_strerror_printf("dict_addattr: attribute name too long");
		return -1;
	}

	/*
	 *	If the value is '-1', that means use a pre-existing
	 *	one (if it already exists).  If one does NOT already exist,
	 *	then create a new attribute, with a non-conflicting value,
	 *	and use that.
	 */
	if (value == -1) {
		if (dict_attrbyname(name)) {
			return 0; /* exists, don't add it again */
		}

		value = ++max_attr;

	} else if (vendor == 0) {
		/*
		 *  Update 'max_attr'
		 */
		if (value > max_attr) {
			max_attr = value;
		}
	}

	if (value < 0) {
		fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
		return -1;
	}

	if (value >= 65536) {
		fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 65535).");
		return -1;
	}

	if (vendor) {
		DICT_VENDOR *dv;
		static DICT_VENDOR *last_vendor = NULL;

		if (flags.is_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
			fr_strerror_printf("Sub-TLV's cannot be encrypted");
			return -1;
		}

		if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
			fr_strerror_printf("TLV's cannot be encrypted");
			return -1;
		}

		if (flags.is_tlv && flags.has_tag) {
			fr_strerror_printf("Sub-TLV's cannot have a tag");
			return -1;
		}

		if (flags.has_tlv && flags.has_tag) {
			fr_strerror_printf("TLV's cannot have a tag");
			return -1;
		}

		/*
		 *	Most ATTRIBUTEs are bunched together by
		 *	VENDOR.  We can save a lot of lookups on
		 *	dictionary initialization by caching the last
		 *	vendor.
		 */
		if (last_vendor && (vendor == last_vendor->vendorpec)) {
			dv = last_vendor;
		} else {
			dv = dict_vendorbyvalue(vendor);
			last_vendor = dv;
		}

		/*
		 *	If the vendor isn't defined, die.
		 */
		if (!dv) {
			fr_strerror_printf("dict_addattr: Unknown vendor");
			return -1;
		}

		/*
		 *	FIXME: Switch over dv->type, and limit things
		 *	properly.
		 */
		if ((dv->type == 1) && (value >= 256) && !flags.is_tlv) {
			fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
			return -1;
		} /* else 256..65535 are allowed */
	}

	/*
	 *	Create a new attribute for the list
	 */
	if ((attr = fr_pool_alloc(sizeof(*attr) + namelen)) == NULL) {
		fr_strerror_printf("dict_addattr: out of memory");
		return -1;
	}

	memcpy(attr->name, name, namelen);
	attr->name[namelen] = '\0';
	attr->attr = value;
	attr->attr |= (vendor << 16); /* FIXME: hack */
	attr->vendor = vendor;
	attr->type = type;
	attr->flags = flags;
	attr->vendor = vendor;

	/*
	 *	Insert the attribute, only if it's not a duplicate.
	 */
	if (!fr_hash_table_insert(attributes_byname, attr)) {
		DICT_ATTR	*a;

		/*
		 *	If the attribute has identical number, then
		 *	ignore the duplicate.
		 */
		a = fr_hash_table_finddata(attributes_byname, attr);
		if (a && (strcasecmp(a->name, attr->name) == 0)) {
			if (a->attr != attr->attr) {
				fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
				fr_pool_free(attr);
				return -1;
			}

			/*
			 *	Same name, same vendor, same attr,
			 *	maybe the flags and/or type is
			 *	different.  Let the new value
			 *	over-ride the old one.
			 */
		}


		fr_hash_table_delete(attributes_byvalue, a);

		if (!fr_hash_table_replace(attributes_byname, attr)) {
			fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
			fr_pool_free(attr);
			return -1;
		}
	}

	/*
	 *	Insert the SAME pointer (not free'd when this entry is
	 *	deleted), into another table.
	 *
	 *	We want this behaviour because we want OLD names for
	 *	the attributes to be read from the configuration
	 *	files, but when we're printing them, (and looking up
	 *	by value) we want to use the NEW name.
	 */
	if (!fr_hash_table_replace(attributes_byvalue, attr)) {
		fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
		return -1;
	}

	if (!vendor && (value > 0) && (value < 256)) {
	 	 dict_base_attrs[value] = attr;
	}

	return 0;
}
Beispiel #26
0
/*
 *	Initialize the directory, then fix the attr member of
 *	all attributes.
 */
int dict_init(const char *dir, const char *fn)
{
	/*
	 *	Check if we need to change anything.  If not, don't do
	 *	anything.
	 */
	if (dict_stat_check(dir, fn)) {
		return 0;
	}

	/*
	 *	Free the dictionaries, and the stat cache.
	 */
	dict_free();
	stat_root_dir = strdup(dir);
	stat_root_file = strdup(fn);

	/*
	 *	Create the table of vendor by name.   There MAY NOT
	 *	be multiple vendors of the same name.
	 *
	 *	Each vendor is malloc'd, so the free function is free.
	 */
	vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
						dict_vendor_name_cmp,
						fr_pool_free);
	if (!vendors_byname) {
		return -1;
	}

	/*
	 *	Create the table of vendors by value.  There MAY
	 *	be vendors of the same value.  If there are, we
	 *	pick the latest one.
	 */
	vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
						 dict_vendor_value_cmp,
						 fr_pool_free);
	if (!vendors_byvalue) {
		return -1;
	}

	/*
	 *	Create the table of attributes by name.   There MAY NOT
	 *	be multiple attributes of the same name.
	 *
	 *	Each attribute is malloc'd, so the free function is free.
	 */
	attributes_byname = fr_hash_table_create(dict_attr_name_hash,
						   dict_attr_name_cmp,
						   fr_pool_free);
	if (!attributes_byname) {
		return -1;
	}

	/*
	 *	Create the table of attributes by value.  There MAY
	 *	be attributes of the same value.  If there are, we
	 *	pick the latest one.
	 */
	attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
						    dict_attr_value_cmp,
						    fr_pool_free);
	if (!attributes_byvalue) {
		return -1;
	}

	values_byname = fr_hash_table_create(dict_value_name_hash,
					       dict_value_name_cmp,
					       fr_pool_free);
	if (!values_byname) {
		return -1;
	}

	values_byvalue = fr_hash_table_create(dict_value_value_hash,
						dict_value_value_cmp,
						fr_pool_free);
	if (!values_byvalue) {
		return -1;
	}

	value_fixup = NULL;	/* just to be safe. */

	if (my_dict_init(dir, fn, NULL, 0) < 0)
		return -1;

	if (value_fixup) {
		DICT_ATTR *a;
		value_fixup_t *this, *next;

		for (this = value_fixup; this != NULL; this = next) {
			next = this->next;

			a = dict_attrbyname(this->attrstr);
			if (!a) {
				fr_strerror_printf(
					"dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
					this->attrstr, this->dval->name);
				return -1; /* leak, but they should die... */
			}

			this->dval->attr = a->attr;

			/*
			 *	Add the value into the dictionary.
			 */
			if (!fr_hash_table_replace(values_byname,
						     this->dval)) {
				fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
				return -1;
			}

			/*
			 *	Allow them to use the old name, but
			 *	prefer the new name when printing
			 *	values.
			 */
			if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
				fr_hash_table_replace(values_byvalue,
							this->dval);
			}
			free(this);

			/*
			 *	Just so we don't lose track of things.
			 */
			value_fixup = next;
		}
	}

	/*
	 *	Walk over all of the hash tables to ensure they're
	 *	initialized.  We do this because the threads may perform
	 *	lookups, and we don't want multi-threaded re-ordering
	 *	of the table entries.  That would be bad.
	 */
	fr_hash_table_walk(vendors_byname, null_callback, NULL);
	fr_hash_table_walk(vendors_byvalue, null_callback, NULL);

	fr_hash_table_walk(attributes_byname, null_callback, NULL);
	fr_hash_table_walk(attributes_byvalue, null_callback, NULL);

	fr_hash_table_walk(values_byvalue, null_callback, NULL);
	fr_hash_table_walk(values_byname, null_callback, NULL);

	return 0;
}
Beispiel #27
0
/*
 *	Initialize the dictionary.
 */
static int my_dict_init(const char *dir, const char *fn,
			const char *src_file, int src_line)
{
	FILE	*fp;
	char 	dirtmp[256];
	char	buf[256];
	char	*p;
	int	line = 0;
	int	vendor;
	int	block_vendor;
	struct stat statbuf;
	char	*argv[MAX_ARGV];
	int	argc;
	DICT_ATTR *da, *block_tlv = NULL;

	if (strlen(fn) >= sizeof(dirtmp) / 2 ||
	    strlen(dir) >= sizeof(dirtmp) / 2) {
		fr_strerror_printf("dict_init: filename name too long");
		return -1;
	}

	/*
	 *	First see if fn is relative to dir. If so, create
	 *	new filename. If not, remember the absolute dir.
	 */
	if ((p = strrchr(fn, FR_DIR_SEP)) != NULL) {
		strcpy(dirtmp, fn);
		dirtmp[p - fn] = 0;
		dir = dirtmp;
	} else if (dir && dir[0] && strcmp(dir, ".") != 0) {
		snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn);
		fn = dirtmp;
	}

	if ((fp = fopen(fn, "r")) == NULL) {
		if (!src_file) {
			fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
				   fn, strerror(errno));
		} else {
			fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
				   src_file, src_line, fn, strerror(errno));
		}
		return -1;
	}

	stat(fn, &statbuf); /* fopen() guarantees this will succeed */
	if (!S_ISREG(statbuf.st_mode)) {
		fclose(fp);
		fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
			   fn);
		return -1;
	}

	/*
	 *	Globally writable dictionaries means that users can control
	 *	the server configuration with little difficulty.
	 */
#ifdef S_IWOTH
	if ((statbuf.st_mode & S_IWOTH) != 0) {
		fclose(fp);
		fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable.  Refusing to start due to insecure configuration.",
			   fn);
		return -1;
	}
#endif

	dict_stat_add(fn, &statbuf);

	/*
	 *	Seed the random pool with data.
	 */
	fr_rand_seed(&statbuf, sizeof(statbuf));

	block_vendor = 0;

	while (fgets(buf, sizeof(buf), fp) != NULL) {
		line++;
		if (buf[0] == '#' || buf[0] == 0 ||
		    buf[0] == '\n' || buf[0] == '\r')
			continue;

		/*
		 *  Comment characters should NOT be appearing anywhere but
		 *  as start of a comment;
		 */
		p = strchr(buf, '#');
		if (p) *p = '\0';

		argc = str2argv(buf, argv, MAX_ARGV);
		if (argc == 0) continue;

		if (argc == 1) {
			fr_strerror_printf( "dict_init: %s[%d] invalid entry",
				    fn, line);
			fclose(fp);
			return -1;
		}

		/*
		 *	Process VALUE lines.
		 */
		if (strcasecmp(argv[0], "VALUE") == 0) {
			if (process_value(fn, line,
					  argv + 1, argc - 1) == -1) {
				fclose(fp);
				return -1;
			}
			continue;
		}

		/*
		 *	Perhaps this is an attribute.
		 */
		if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
			if (process_attribute(fn, line, block_vendor,
					      block_tlv,
					      argv + 1, argc - 1) == -1) {
				fclose(fp);
				return -1;
			}
			continue;
		}

		/*
		 *	See if we need to import another dictionary.
		 */
		if (strcasecmp(argv[0], "$INCLUDE") == 0) {
			if (my_dict_init(dir, argv[1], fn, line) < 0) {
				fclose(fp);
				return -1;
			}
			continue;
		} /* $INCLUDE */

		if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
			if (process_value_alias(fn, line,
						argv + 1, argc - 1) == -1) {
				fclose(fp);
				return -1;
			}
			continue;
		}

		/*
		 *	Process VENDOR lines.
		 */
		if (strcasecmp(argv[0], "VENDOR") == 0) {
			if (process_vendor(fn, line,
					   argv + 1, argc - 1) == -1) {
				fclose(fp);
				return -1;
			}
			continue;
		}

		if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
			if (argc != 2) {
				fr_strerror_printf(
				"dict_init: %s[%d] invalid BEGIN-TLV entry",
					fn, line);
				fclose(fp);
				return -1;
			}

			da = dict_attrbyname(argv[1]);
			if (!da) {
				fr_strerror_printf(
					"dict_init: %s[%d]: unknown attribute %s",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}

			if (da->type != PW_TYPE_TLV) {
				fr_strerror_printf(
					"dict_init: %s[%d]: attribute %s is not of type tlv",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}

			if (block_tlv) {
				fr_strerror_printf(
					"dict_init: %s[%d]: Cannot nest TLVs",
					fn, line);
				fclose(fp);
				return -1;
			}

			block_tlv = da;
			continue;
		} /* BEGIN-TLV */

		if (strcasecmp(argv[0], "END-TLV") == 0) {
			if (argc != 2) {
				fr_strerror_printf(
				"dict_init: %s[%d] invalid END-TLV entry",
					fn, line);
				fclose(fp);
				return -1;
			}

			da = dict_attrbyname(argv[1]);
			if (!da) {
				fr_strerror_printf(
					"dict_init: %s[%d]: unknown attribute %s",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}

			if (da != block_tlv) {
				fr_strerror_printf(
					"dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}
			block_tlv = NULL;
			continue;
		} /* END-VENDOR */

		if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
			if (argc != 2) {
				fr_strerror_printf(
				"dict_init: %s[%d] invalid BEGIN-VENDOR entry",
					fn, line);
				fclose(fp);
				return -1;
			}

			vendor = dict_vendorbyname(argv[1]);
			if (!vendor) {
				fr_strerror_printf(
					"dict_init: %s[%d]: unknown vendor %s",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}
			block_vendor = vendor;
			continue;
		} /* BEGIN-VENDOR */

		if (strcasecmp(argv[0], "END-VENDOR") == 0) {
			if (argc != 2) {
				fr_strerror_printf(
				"dict_init: %s[%d] invalid END-VENDOR entry",
					fn, line);
				fclose(fp);
				return -1;
			}

			vendor = dict_vendorbyname(argv[1]);
			if (!vendor) {
				fr_strerror_printf(
					"dict_init: %s[%d]: unknown vendor %s",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}

			if (vendor != block_vendor) {
				fr_strerror_printf(
					"dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
					fn, line, argv[1]);
				fclose(fp);
				return -1;
			}
			block_vendor = 0;
			continue;
		} /* END-VENDOR */

		/*
		 *	Any other string: We don't recognize it.
		 */
		fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
			   fn, line, argv[0]);
		fclose(fp);
		return -1;
	}
	fclose(fp);
	return 0;
}
Beispiel #28
0
/** Instantiate the module
 *
 * Creates a new instance of the module reading parameters from a configuration section.
 *
 * @param conf to parse.
 * @param instance Where to write pointer to configuration data.
 * @return 0 on success < 0 on failure.
 */
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	static bool version_done;

	CONF_SECTION *options;
	ldap_instance_t *inst = instance;

	inst->cs = conf;

	options = cf_section_sub_find(conf, "options");
	if (!options || !cf_pair_find(options, "chase_referrals")) {
		inst->chase_referrals_unset = true;	 /* use OpenLDAP defaults */
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) {
		inst->xlat_name = cf_section_name1(conf);
	}


	/*
	 *	Only needs to be done once, prevents races in environment
	 *	initialisation within libldap.
	 *
	 *	See: https://github.com/arr2036/ldapperf/issues/2
	 */
#ifdef HAVE_LDAP_INITIALIZE
	ldap_initialize(&inst->handle, "");
#else
	inst->handle = ldap_init("", 0);
#endif

	/*
	 *	Get version info from the LDAP API.
	 */
	if (!version_done) {
		static LDAPAPIInfo info;	/* static to quiet valgrind about this being uninitialised */
		int ldap_errno;

		version_done = true;

		ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
		if (ldap_errno == LDAP_OPT_SUCCESS) {
			if (strcmp(info.ldapai_vendor_name, LDAP_VENDOR_NAME) != 0) {
				WARN("rlm_ldap: libldap vendor changed since the server was built");
				WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
			}

			if (info.ldapai_vendor_version != LDAP_VENDOR_VERSION) {
				WARN("rlm_ldap: libldap version changed since the server was built");
				WARN("rlm_ldap: linked: %i, built: %i",
				     info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
			}

			INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name,
			     info.ldapai_vendor_version);

			ldap_memfree(info.ldapai_vendor_name);
			ldap_memfree(info.ldapai_extensions);
		} else {
			DEBUG("rlm_ldap: Falling back to build time libldap version info.  Query for LDAP_OPT_API_INFO "
			      "returned: %i", ldap_errno);
			INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
			     LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
		}
	}

	/*
	 *	If the configuration parameters can't be parsed, then fail.
	 */
	if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
	    (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
		cf_log_err_cs(conf, "Failed parsing configuration");

		goto error;
	}

	/*
	 *	Sanity checks for cacheable groups code.
	 */
	if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
		if (!inst->groupobj_name_attr) {
			cf_log_err_cs(conf, "Directive 'group.name_attribute' must be set if cacheable "
				      "group names are enabled");

			goto error;
		}
	}

	/*
	 *	Split original server value out into URI, server and port
	 *	so whatever initialization function we use later will have
	 *	the server information in the format it needs.
	 */
	if (ldap_is_ldap_url(inst->server)) {
		LDAPURLDesc *ldap_url;
		int port;

		if (ldap_url_parse(inst->server, &ldap_url)){
			cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", inst->server);
			return -1;
		}

		/*
		 *	Figure out the port from the URL
		 */
		if (ldap_url->lud_port == 0) {
			if (strcmp(ldap_url->lud_scheme, "ldaps://") == 0) {
				if (inst->start_tls == true) {
				start_tls_error:
					cf_log_err_cs(conf, "ldaps:// scheme is not compatible with 'start_tls'");
					return -1;
				}
				port = 636;
			} else {
				port = 384;
			}
		} else {
			port = ldap_url->lud_port;
		}

		inst->uri = inst->server;
		inst->server = talloc_strdup(inst, ldap_url->lud_host);

		if ((inst->port != 384) && (port != inst->port)) {
			WARN("Non-default 'port' directive %i set to %i by LDAP URI", inst->port, port);
		}
		inst->port = port;

		/*
		 *	@todo We could set a few other top level
		 *	directives using the URL, like base_dn
		 *	and scope.
		 */

		ldap_free_urldesc(ldap_url);
	/*
	 *	We need to construct an LDAP URI
	 */
	} else {
		switch (inst->port) {
		default:
		case 384:
			inst->uri = talloc_asprintf(inst, "ldap://%s:%i/", inst->server, inst->port);
			break;

		case 636:
			if (inst->start_tls == true) goto start_tls_error;
			inst->uri = talloc_asprintf(inst, "ldaps://%s:%i/", inst->server, inst->port);
			break;
		}
	}

#ifdef LDAP_OPT_X_TLS_NEVER
	/*
	 *	Workaround for servers which support LDAPS but not START TLS
	 */
	if (inst->port == LDAPS_PORT || inst->tls_mode) {
		inst->tls_mode = LDAP_OPT_X_TLS_HARD;
	} else {
		inst->tls_mode = 0;
	}
#endif

	/*
	 *	Convert dereference strings to enumerated constants
	 */
	if (inst->dereference_str) {
		inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1);
		if (inst->dereference < 0) {
			cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
				      "'finding' or 'always'", inst->dereference_str);
			goto error;
		}
	}

#if LDAP_SET_REBIND_PROC_ARGS != 3
	/*
	 *	The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
	 *	variable for the username, password, etc.
	 */
	if (inst->rebind == true) {
		cf_log_err_cs(conf, "Cannot use 'rebind' directive as this version of libldap "
			      "does not support the API that we need");

		goto error;
	}
#endif

	/*
	 *	Convert scope strings to enumerated constants
	 */
	inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
	if (inst->userobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->userobj_scope_str);
		goto error;
	}

	inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
	if (inst->groupobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->groupobj_scope_str);
		goto error;
	}

	inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
	if (inst->clientobj_scope < 0) {
		cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
			      ", 'base' or 'children'"
#else
			      " or 'base'"
#endif
			 , inst->clientobj_scope_str);
		goto error;
	}

	if (inst->tls_require_cert_str) {
#ifdef LDAP_OPT_X_TLS_NEVER
		/*
		 *	Convert cert strictness to enumerated constants
		 */
		inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
		if (inst->tls_require_cert < 0) {
			cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
				      "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str);
			goto error;
		}
#else
		cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
			      "version of libldap. Please upgrade or substitute current libldap and "
			      "rebuild this module");

		goto error;
#endif
	}
	/*
	 *	Build the attribute map
	 */
	if (map_afrom_cs(&inst->user_map, cf_section_sub_find(inst->cs, "update"),
			 PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst,
			 LDAP_MAX_ATTRMAP) < 0) {
		return -1;
	}

	/*
	 *	Group comparison checks.
	 */
	if (cf_section_name2(conf)) {
		static ATTR_FLAGS flags;
		char buffer[256];

		snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
		if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating group attribute: %s", fr_strerror());

			return -1;
		}
		inst->group_da = dict_attrbyname(buffer);
		if (!inst->group_da) {
			LDAP_ERR("Failed creating attribute %s", buffer);

			goto error;
		}

		paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
	/*
	 *	Were the default instance
	 */
	} else {
		inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
		paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
				false, rlm_ldap_groupcmp, inst);
	}

	xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);

	/*
	 *	Setup the cache attribute
	 */
	if (inst->cache_attribute) {
		static ATTR_FLAGS flags;

		if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
			LDAP_ERR("Error creating cache attribute: %s", fr_strerror());

			goto error;
		}
		inst->cache_da = dict_attrbyname(inst->cache_attribute);
	} else {
		inst->cache_da = inst->group_da;	/* Default to the group_da */
	}

	/*
	 *	Initialize the socket pool.
	 */
	inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
	if (!inst->pool) goto error;

	/*
	 *	Bulk load dynamic clients.
	 */
	if (inst->do_clients) {
		CONF_SECTION *cs;

		cs = cf_section_sub_find(inst->cs, "client");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no client section found");
			goto error;
		}

		cs = cf_section_sub_find(cs, "attribute");
		if (!cs) {
			cf_log_err_cs(conf, "Told to load clients but no attribute section found");
			goto error;
		}

		if (rlm_ldap_client_load(inst, cs) < 0) {
			cf_log_err_cs(conf, "Error loading clients");

			return -1;
		}
	}

	return 0;

error:
	return -1;
}
/*
 *	Allow single attribute values to be retrieved from the cache.
 */
static ssize_t cache_xlat(void *instance, REQUEST *request,
			  char const *fmt, char *out, size_t freespace)
{
	rlm_cache_entry_t 	*c;
	rlm_cache_t		*inst = instance;
	rlm_cache_handle_t	*handle;

	VALUE_PAIR		*vp, *vps;
	pair_lists_t		list;
	DICT_ATTR const		*target;
	char const		*p = fmt;
	size_t			len;
	int			ret = 0;

	list = radius_list_name(&p, PAIR_LIST_REQUEST);

	target = dict_attrbyname(p);
	if (!target) {
		REDEBUG("Unknown attribute \"%s\"", p);
		return -1;
	}

	if (cache_acquire(&handle, inst, request) < 0) return -1;

	switch (cache_find(&c, inst, request, handle, fmt)) {
	case RLM_MODULE_OK:		/* found */
		break;

	case RLM_MODULE_NOTFOUND:	/* not found */
		*out = '\0';
		return 0;

	default:
		return -1;
	}

	switch (list) {
	case PAIR_LIST_REQUEST:
		vps = c->packet;
		break;

	case PAIR_LIST_REPLY:
		vps = c->reply;
		break;

	case PAIR_LIST_CONTROL:
		vps = c->control;
		break;

	case PAIR_LIST_UNKNOWN:
		REDEBUG("Unknown list qualifier in \"%s\"", fmt);
		ret = -1;
		goto finish;

	default:
		REDEBUG("Unsupported list \"%s\"", fr_int2str(pair_lists, list, "<UNKNOWN>"));
		ret = -1;
		goto finish;
	}

	vp = pairfind(vps, target->attr, target->vendor, TAG_ANY);
	if (!vp) {
		RDEBUG("No instance of this attribute has been cached");
		*out = '\0';
		goto finish;
	}

	len = vp_prints_value(out, freespace, vp, 0);
	if (is_truncated(len, freespace)) {
		REDEBUG("Insufficient buffer space to write cached value");
		ret = -1;
		goto finish;
	}

finish:
	cache_free(inst, &c);
	cache_release(inst, request, &handle);

	return ret;
}
Beispiel #30
0
/*
 *	Process the VALUE-ALIAS command
 *
 *	This allows VALUE mappings to be shared among multiple
 *	attributes.
 */
static int process_value_alias(const char* fn, const int line, char **argv,
			       int argc)
{
	DICT_ATTR *my_da, *da;
	DICT_VALUE *dval;

	if (argc != 2) {
		fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
			fn, line);
		return -1;
	}

	my_da = dict_attrbyname(argv[0]);
	if (!my_da) {
		fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
			   fn, line, argv[1]);
		return -1;
	}

	if (my_da->flags.has_value) {
		fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE",
			   fn, line, argv[0]);
		return -1;
	}

	if (my_da->flags.has_value_alias) {
		fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
			   fn, line, argv[0]);
		return -1;
	}

	da = dict_attrbyname(argv[1]);
	if (!da) {
		fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
			   fn, line, argv[1]);
		return -1;
	}

	if (!da->flags.has_value) {
		fr_strerror_printf("dict_init: %s[%d]: VALUE-ALIAS cannot refer to ATTRIBUTE %s: It has no values",
			   fn, line, argv[1]);
		return -1;
	}

	if (da->flags.has_value_alias) {
		fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
			   fn, line, argv[1]);
		return -1;
	}

	if (my_da->type != da->type) {
		fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
			   fn, line);
		return -1;
	}

	if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
		fr_strerror_printf("dict_addvalue: out of memory");
		return -1;
	}

	dval->name[0] = '\0';	/* empty name */
	dval->attr = my_da->attr;
	dval->value = da->attr;

	if (!fr_hash_table_insert(values_byname, dval)) {
		fr_strerror_printf("dict_init: %s[%d]: Error create alias",
			   fn, line);
		fr_pool_free(dval);
		return -1;
	}

	return 0;
}