static void *lt_malloc(size_t size)
{
void *out;
-
+
out = malloc(size);
if (!out) {
ERROR("Failed allocating %zu bytes, OOM", size);
exit(1);
}
-
+
return out;
}
static void lt_const_free(const void *ptr)
{
void *tmp;
-
+
memcpy(&tmp, &ptr, sizeof(tmp));
free(tmp);
}
exit(1);
}
init_count_chars(out);
-
+
return out;
}
raw = flatten_count_chars(&tmpcc, 1);
command = shell_esc(raw);
-
+
memcpy(&tmp, &raw, sizeof(tmp));
free(tmp);
spawn_args[2] = command;
spawn_args[3] = NULL;
ret = external_spawn(cmd, spawn_args[0], spawn_args);
-
+
free(command);
-
+
return ret;
}
} else {
strncpy(var, arg, sizeof(var) - 1);
var[sizeof(var) - 1] = '\0';
-
+
value[0] = '\0';
}
ERROR("Unknown mode \"%s\"\n", value);
exit(1);
}
-
+
} else if (strcmp(var, "shared") == 0) {
if ((cmd->mode == MODE_LINK) && (cmd->output == OUT_GENERAL)) {
cmd->output = OUT_DYNAMIC_LIB_ONLY;
}
cmd->options.shared = SHARE_SHARED;
-
+
} else if (strcmp(var, "export-all") == 0) {
cmd->options.export_all = 1;
-
+
} else if (strcmp(var, "dry-run") == 0) {
NOTICE("Dry-run mode on!\n");
cmd->options.dry_run = 1;
-
+
} else if (strcmp(var, "version") == 0) {
NOTICE("Version " VERSION "\n");
-
+
} else if (strcmp(var, "help") == 0) {
usage(0);
-
+
} else if (strcmp(var, "config") == 0) {
print_config(value);
-
+
exit(0);
} else {
return 0;
if (ext == NULL) {
return tmppath;
}
-
+
len = ext - newname;
if (strncmp(newname, "mod_", 4) == 0) {
static const char *file_name(const char *path)
{
const char *name;
-
+
name = strrchr(path, '/');
if (!name) {
name = strrchr(path, '\\'); /* eww windows? */
if (ext) {
char *trimmed;
-
+
trimmed = lt_malloc(ext - name + 1);
strncpy(trimmed, name, ext - name);
trimmed[ext-name] = 0;
-
+
return trimmed;
}
if (!newext) {
ERROR("Library path does not have an extension");
free(newarg);
-
+
return NULL;
}
newext++;
ext = newarg + arglen;
strcpy(ext, OBJECT_EXT);
-
+
DEBUG("Checking (obj): %s\n", newarg);
if (stat(newarg, &sb) == 0) {
return newarg;
}
-
+
free(newarg);
return NULL;
if (!ext) {
ERROR("Error: Library path does not have an extension");
free(newarg);
-
+
return NULL;
}
ext++;
if (rv == 0) {
return newarg;
}
-
+
free(newarg);
return NULL;
if (f == NULL) {
return NULL;
}
-
+
path = lt_malloc(PATH_MAX);
fgets(path, PATH_MAX, f);
fclose(f);
-
+
if (path[strlen(path)-1] == '\n') {
path[strlen(path)-1] = '\0';
}
-
+
/* Check that we have an absolute path.
* Otherwise the file could be a GNU libtool file.
*/
if (path[0] != '/') {
free(path);
-
+
return NULL;
}
return path;
#ifdef DYNAMIC_LINK_OPTS
if (cmd->options.pic_mode != PIC_AVOID) {
DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_OPTS);
-
+
push_count_chars(args, DYNAMIC_LINK_OPTS);
if (cmd->undefined_flag) {
push_count_chars(args, "-undefined");
else {
#ifdef DYNAMIC_LINK_UNDEFINED
DEBUG("Adding linker opt: %s\n", DYNAMIC_LINK_UNDEFINED);
-
+
push_count_chars(args, DYNAMIC_LINK_UNDEFINED);
#endif
}
tmpdir = flatten_count_chars(&tmpdir_cc, 0);
NOTICE("Making: %s\n", tmpdir);
-
+
safe_mkdir(cmd, tmpdir);
push_count_chars(cmd->tmp_dirs, tmpdir);
if (chdir(tmpdir) != 0) {
NOTICE("Warning: could not explode %s\n", lib);
-
+
return 1;
}
* Were linking and have an archived object or object file
* push it onto the list of object files which'll get used
* to create the input files list for the linker.
- *
+ *
* We assume that these are outside of the project were building,
* as there's no reason to create .a files as part of the build
* process.
*/
if (!strcmp(ext, STATIC_LIB_EXT) && (cmd->mode == MODE_LINK)) {
struct stat sb;
-
+
if (!stat(arg, &sb)) {
DEBUG("Adding object: %s\n", arg);
-
+
push_count_chars(cmd->obj_files, arg);
-
+
return 1;
}
}
ERROR("Can not find suitable object file for %s\n", arg);
exit(1);
}
-
+
if (cmd->mode == MODE_LINK) {
DEBUG("Adding object: %s\n", newarg);
-
+
push_count_chars(cmd->obj_files, newarg);
} else {
push_count_chars(cmd->arglist, newarg);
}
-
+
return 1;
}
*/
if (cmd->output == OUT_LIB) {
char *tmp;
-
+
tmp = strdup(arg);
tmp[pathlen] = '\0';
push_count_chars(cmd->arglist, tmp);
-
+
} else {
cmd->output = OUT_LIB;
cmd->output_name = arg;
default:
break;
}
-
+
return 1;
}
char *tmp = lt_malloc(strlen(arg) + 4);
strcpy(tmp, arg);
strcpy(strrchr(tmp, '.') + 1, "lo");
-
+
cmd->basename = tmp;
cmd->fake_output_name = strrchr(cmd->basename, '/');
if (strcmp(ext, DYNAMIC_LIB_EXT) == 0) {
ERROR("Please build libraries with .la target, not ."
DYNAMIC_LIB_EXT "\n");
-
+
exit(1);
}
if (strcmp(ext, STATIC_LIB_EXT) == 0) {
ERROR("Please build libraries with .la target, not ."
STATIC_LIB_EXT "\n");
-
+
exit(1);
}
arg = LINK_C;
cmd->mode = MODE_LINK;
}
-
+
return arg;
}
if (ext) {
*ext = '\0';
}
-
+
strcat(implib_file, ".");
strcat(implib_file, STATIC_LIB_EXT);
ERROR("Installation mode requires -rpath\n");
exit(1);
}
-
+
{
char *tmp = lt_malloc(PATH_MAX);
strcpy(tmp, cmd->install_path);
-
+
if (cmd->shared_name.install) {
strcat(tmp, strrchr(cmd->shared_name.install, '/'));
} else {
strcat(tmp, strrchr(cmd->shared_name.normal, '/'));
}
-
+
push_count_chars(cmd->shared_opts.normal, tmp);
}
#endif
* rerun ranlib afterwards.
*/
const char *lib_args[3], *static_lib_name;
-
+
{
char *tmp;
size_t len1, len2;
-
+
len1 = strlen(cmd->arglist->vals[cmd->arglist->num - 1]);
static_lib_name = file_name(cmd->static_name.install);
lib_args[0] = RANLIB;
lib_args[1] = tmp;
lib_args[2] = NULL;
-
+
external_spawn(cmd, RANLIB, lib_args);
-
+
free(tmp);
}
#endif
case MODE_EXECUTE:
{
char *l, libpath[PATH_MAX];
-
+
if (strlen(cmd->arglist->vals[0]) >= PATH_MAX) {
ERROR("Libpath too long no buffer space");
rv = 1;
-
+
goto finish;
}
}
finish:
-
+
free(cctemp);
return rv;
}
if (!dir) {
return;
}
-
+
if ((strlen(dirname) + 1 + sizeof(entry->d_name)) >= sizeof(fullname)) {
ERROR("Dirname too long, out of buffer space");
}
rmdir(dirname);
-
+
(void) closedir(dir);
}
arg = automode(base, cmd);
if (arg != base) {
push_count_chars(cmd->arglist, arg);
-
+
assert(cmd->mode != MODE_UNKNOWN);
}
parse_short_opt(arg + 1, cmd);
if (arg_used) continue;
-
+
/*
* We haven't done anything with it yet, but
* there are still some arg/value pairs.
push_count_chars(cmd->arglist, arg);
arg = argv[++a];
-
+
NOTICE(" %s\n", arg);
push_count_chars(cmd->arglist, arg);
/* Aha, we should try to link both! */
cmd->install_path = argv[++a];
arg_used = 1;
-
+
} else if (!strcmp(arg + 1, "release")) {
/* Store for later deciphering */
cmd->version_info = argv[++a];
arg_used = 1;
-
+
} else if (!strcmp(arg + 1, "version-info")) {
/* Store for later deciphering */
cmd->version_info = argv[++a];
arg_used = 1;
-
+
} else if (!strcmp(arg + 1,
"export-symbols-regex")) {
/* Skip the argument. */
++a;
arg_used = 1;
-
+
} else if (!strcmp(arg + 1, "undefined")) {
cmd->undefined_flag = argv[++a];
arg_used = 1;
* Add dir to runtime library search path.
*/
} else if ((arg[1] == 'R') && !arg[2]) {
-
+
add_runtime_dir_lib(argv[++a], cmd);
arg_used = 1;
}
}
DEBUG("Adding: %s\n", arg);
-
+
push_count_chars(cmd->arglist, arg);
}
}
}
cleanup_tmp_dirs(&cmd);
-
+
return rc;
}
int fr_isbase64(char c);
size_t fr_base64_encode(uint8_t const *in, size_t inlen, char *out, size_t outlen);
-
+
ssize_t fr_base64_encode_alloc(uint8_t const *in, size_t inlen, char **out);
ssize_t fr_base64_decode(char const *in, size_t inlen, uint8_t *out, size_t outlen);
/*
* Requires typeof(), which is in most modern C compilers.
*/
-
+
/*
#define VERIFY_VP(_x) do { (void) talloc_get_type_abort(_x, VALUE_PAIR); \
if (_x->da) { \
#endif
typedef struct attr_flags {
- unsigned int is_unknown : 1; //!< Attribute number or vendor is unknown.
+ unsigned int is_unknown : 1; //!< Attribute number or vendor is unknown.
unsigned int is_tlv : 1; //!< Is a sub attribute.
unsigned int vp_free : 1; //!< Should be freed when VALUE_PAIR is freed.
-
+
unsigned int has_tag : 1; //!< Tagged attribute.
unsigned int array : 1; //!< Pack multiples into 1 attr.
unsigned int has_value : 1; //!< Has a value.
extern const FR_NAME_NUMBER dict_attr_types[];
extern const size_t dict_attr_sizes[PW_TYPE_MAX][2];
-/** dictionary attribute
+/** dictionary attribute
*
*/
typedef struct dict_attr {
/** Union containing all data types supported by the server
*
- * This union contains all data types that can be represented with VALUE_PAIRs. It may also be used in other parts
+ * This union contains all data types that can be represented with VALUE_PAIRs. It may also be used in other parts
* of the server where values of different types need to be stored.
*
* PW_TYPE should be an enumeration of the values in this union.
/** Stores an attribute, a value and various bits of other data
*
- * VALUE_PAIRs are the main data structure used in the server, they specify an attribute, it's children and
+ * VALUE_PAIRs are the main data structure used in the server, they specify an attribute, it's children and
* it's siblings.
*
* They also specify what behaviour should be used when the attribute is merged into a new list/tree.
// VALUE_LIST *list; //!< List of values for
//!< multivalued attribute.
// value_data_t *data; //!< Value data for this attribute.
-
+
char const *xlat; //!< Source string for xlat expansion.
} value;
-
+
value_type_t type; //!< Type of pointer in value union.
-
+
size_t length; //!< of Data field.
value_data_t data;
} VALUE_PAIR;
/** Abstraction to allow iterating over different configurations of VALUE_PAIRs
*
- * This allows functions which do not care about the structure of collections of VALUE_PAIRs
+ * This allows functions which do not care about the structure of collections of VALUE_PAIRs
* to iterate over all members in a collection.
*
* Field within a vp_cursor should not be accessed directly, and vp_cursors should only be
typedef struct value_pair_raw {
char l_opand[64]; //!< Left hand side of the pair.
char r_opand[1024]; //!< Right hand side of the pair.
-
+
FR_TOKEN quote; //!< Type of quoting around the r_opand.
-
+
FR_TOKEN op; //!< Operator.
} VALUE_PAIR_RAW;
*
* For server code, do not call radlog, vradlog et al directly, use one of the logging macros instead.
*
- * R* - Macros prefixed with an R will automatically prepend request information to the
+ * R* - Macros prefixed with an R will automatically prepend request information to the
* log messages.
* INFO | WARN | ERROR - Macros containing these words will be displayed at all log levels.
- * *DEBUG* - Macros with the word DEBUG, will only be displayed if the server or request debug
+ * *DEBUG* - Macros with the word DEBUG, will only be displayed if the server or request debug
* level is above 0.
* *[IWE]DEBUG[0-9]? - Macros with I, W, E as (or just after) the prefix, will log with the priority
* specified by the integer if the server or request log level at or above that integer.
- * If there is no integer the level is 1. The I|W|E prefix determines the type
+ * If there is no integer the level is 1. The I|W|E prefix determines the type
* (INFO, WARN, ERROR), if there is no I|W|E prefix the DEBUG type will be used.
*/
-
+
/*
* Log server driven messages like threadpool exhaustion and connection failures
*/
#define _SL(_l, _p, _f, ...) if (debug_flag >= _p) radlog(_l, _f, ## __VA_ARGS__)
-
+
#define AUTH(fmt, ...) _SL(L_AUTH, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define ACCT(fmt, ...) _SL(L_ACCT, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define PROXY(fmt, ...) _SL(L_PROXY, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-
+
#define DEBUG(fmt, ...) _SL(L_DBG, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define DEBUG2(fmt, ...) _SL(L_DBG, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
#define DEBUG3(fmt, ...) _SL(L_DBG, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
#define DEBUG4(fmt, ...) _SL(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
-
+
#define INFO(fmt, ...) _SL(L_INFO, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define DEBUGI(fmt, ...) _SL(L_INFO, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-
+
#define WARN(fmt, ...) _SL(L_WARN, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define WDEBUG(fmt, ...) _SL(L_DBG_WARN, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define WDEBUG2(fmt, ...) _SL(L_DBG_WARN, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-
+
#define ERROR(fmt, ...) _SL(L_ERR, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define EDEBUG(fmt, ...) _SL(L_DBG_ERR, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define EDEBUG2(fmt, ...) _SL(L_DBG_ERR, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-
+
/*
* Log request driven messages which including elements from the current request, like section and module
*
_RL(_l, _p, _f, ## __VA_ARGS__); \
} \
} while(0)
-
+
#define RAUTH(fmt, ...) _RL(L_AUTH, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define RACCT(fmt, ...) _RL(L_ACCT, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define RPROXY(fmt, ...) _RL(L_PROXY, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-
+
#define RDEBUG(fmt, ...) _RL(L_DBG, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define RDEBUG2(fmt, ...) _RL(L_DBG, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
#define RDEBUG3(fmt, ...) _RL(L_DBG, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
#define RDEBUG4(fmt, ...) _RL(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
-
+
#define RINFO(fmt, ...) _RL(L_INFO, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define RIDEBUG(fmt, ...) _RL(L_INFO, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-
+
#define RWARN(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define RWDEBUG(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define RWDEBUG2(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-
+
#define RERROR(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define REDEBUG(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
#define REDEBUG2(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
//!< various section functions, ordering
//!< determines which function is mapped to
//!< which section.
-
+
} module_t;
int setup_modules(int, CONF_SECTION *);
fr_request_process_t process; //!< The function to call to
//!< move the request through
//!< the state machine.
-
+
RAD_REQUEST_FUNP handle; //!< The function to call to
//!< move the request through
//!< the various server
//!< configuration sections.
-
+
struct main_config_t *root; //!< Pointer to the main config
//!< hack to try and deal with
//!< hup.
request_data_t *data; //!< Request metadata.
-
+
RADCLIENT *client; //!< The client that originally
//!< sent us the request.
-
+
#ifdef HAVE_PTHREAD_H
pthread_t child_pid; //!< Current thread handling
//!< the request.
log_debug_t options; //!< Request options, currently
//!< just holds the debug level
//!< for the request.
-
+
char const *module; //!< Module the request is
//!< currently being processed
- //!< by.
+ //!< by.
char const *component; //!< Section the request is
//!< in.
int rate_pps_old;
int rate_pps_now;
int max_rate;
-
+
/* for outgoing sockets */
home_server *home;
fr_ipaddr_t other_ipaddr;
int client_add(RADCLIENT_LIST *clients, RADCLIENT *client);
#ifdef WITH_DYNAMIC_CLIENTS
void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client);
-RADCLIENT *client_from_query(TALLOC_CTX *ctx, char const *identifier, char const *secret, char const *shortname,
+RADCLIENT *client_from_query(TALLOC_CTX *ctx, char const *identifier, char const *secret, char const *shortname,
char const *type, char const *server, bool require_ma);
RADCLIENT *client_from_request(RADCLIENT_LIST *clients, REQUEST *request);
#endif
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape,
void *escape_ctx);
-
+
ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape,
void *escape_ctx);
-
+
typedef ssize_t (*RAD_XLAT_FUNC)(void *instance, REQUEST *, char const *, char *, size_t);
int xlat_register(char const *module, RAD_XLAT_FUNC func, RADIUS_ESCAPE_STRING escape,
void *instance);
CONF_SECTION *cs;
char const *virtual_server; /* for pre/post-proxy */
-
+
home_server *fallback;
int in_fallback;
time_t time_all_dead;
*out = '\0';
return -1;
}
-
+
while (inlen) {
*p++ = b64str[(in[0] >> 2) & 0x3f];
*p++ = b64str[((in[0] << 4) + (--inlen ? in[1] >> 4 : 0)) & 0x3f];
- *p++ = (inlen ? b64str[((in[1] << 2) + (--inlen ? in[2] >> 6 : 0)) & 0x3f] : '=');
+ *p++ = (inlen ? b64str[((in[1] << 2) + (--inlen ? in[2] >> 6 : 0)) & 0x3f] : '=');
*p++ = inlen ? b64str[in[2] & 0x3f] : '=';
if (inlen) inlen--;
}
p[0] = '\0';
-
+
return p - out;
}
if (!*out) {
return -1;
}
-
+
return fr_base64_encode(in, inlen, *out, outlen);
}
size_t outlen)
{
uint8_t *p = out;
-
+
if (outlen < FR_BASE64_DEC_LENGTH(inlen)) {
return -1;
}
if ((inlen != 4) || (in[3] != '=')) break;
} else {
if (!fr_isbase64(in[2])) break;
-
+
*p++ = ((b64[us(in[1])] << 4) & 0xf0) | (b64[us(in[2])] >> 2);
-
+
if (inlen == 3) break;
if (in[3] == '=') {
*p++ = ((b64[us(in[2])] << 6) & 0xc0) | b64[us(in[3])];
}
}
-
+
in += 4;
inlen -= 4;
}
if (inlen != 0) {
return -1;
}
-
+
return p - out;
}
if (ret < 0) {
talloc_free(*out);
*out = '\0';
-
+
return -1;
}
-
+
return ret;
}
const uint8_t *p;
const DICT_ATTR *da;
DICT_ATTR *n;
-
+
namelen = strlen(name);
if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
fr_strerror_printf("dict_addattr: attribute name too long");
{
DICT_ATTR *tmp;
memcpy(&tmp, &dval, sizeof(tmp));
-
+
if (!fr_hash_table_insert(values_byname, tmp)) {
if (dattr) {
DICT_VALUE *old;
fr_strerror_printf("Parent attribute is undefined.");
return -1;
}
-
+
if (!da->flags.has_tlv && !da->flags.extended) {
fr_strerror_printf("Parent attribute %s cannot have sub-attributes",
da->name);
if (*pvendor >= FR_MAX_VENDOR) {
fr_strerror_printf("Cannot handle vendor ID larger than 2^24");
-
+
return -1;
}
char buffer[256];
strlcpy(buffer, fr_strerror(), sizeof(buffer));
-
+
fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
return -1;
}
} else {
type = PW_TYPE_OCTETS;
-
+
p = strchr(argv[2] + 7, ']');
if (!p) {
fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
/* Boolean flag, means this is a
tagged attribute */
flags.has_tag = 1;
-
+
} else if (strncmp(key, "encrypt=", 8) == 0) {
/* Encryption method, defaults to 0 (none).
Currently valid is just type 2,
fn, line);
return -1;
}
-
+
} else if (strncmp(key, "array", 6) == 0) {
flags.array = 1;
-
+
switch (type) {
case PW_TYPE_IPADDR:
case PW_TYPE_BYTE:
}
flags.has_tlv = 1;
}
-
+
if (block_tlv) {
/*
* TLV's can be only one octet.
}
/*
- *
+ *
*/
value <<= fr_attr_shift[tlv_depth];
value |= block_tlv->attr;
fclose(fp);
return -1;
}
-
+
p = argv[2] + 7;
da = dict_attrbyname(p);
if (!da) {
fclose(fp);
return -1;
}
-
+
/*
* Pack the encapsulating
* attribute into the upper 8
void dict_attr_free(DICT_ATTR const **da)
{
DICT_ATTR **tmp;
-
+
if (!da || !*da) return;
-
+
/* Don't free real DAs */
if (!(*da)->flags.is_unknown) {
return;
}
-
+
memcpy(&tmp, &da, sizeof(*tmp));
free(*tmp);
-
- *tmp = NULL;
+
+ *tmp = NULL;
}
/** Copies a dictionary attr
const DICT_ATTR *dict_attr_copy(DICT_ATTR const *da, int vp_free)
{
DICT_ATTR *copy;
-
+
if (!da) return NULL;
-
+
if (!da->flags.is_unknown) {
return da;
}
-
+
copy = malloc(DICT_ATTR_SIZE);
if (!copy) {
fr_strerror_printf("Out of memory");
return NULL;
}
-
+
memcpy(copy, da, DICT_ATTR_SIZE);
copy->flags.vp_free = (vp_free != 0);
-
+
return copy;
}
int dv_type = 1;
size_t len = 0;
size_t bufsize = DICT_ATTR_MAX_NAME_LEN;
-
+
da = malloc(DICT_ATTR_SIZE);
if (!da) {
fr_strerror_printf("Out of memory");
return NULL;
}
memset(da, 0, DICT_ATTR_SIZE);
-
+
da->attr = attr;
da->vendor = vendor;
da->type = PW_TYPE_OCTETS;
da->flags.is_unknown = true;
da->flags.vp_free = (vp_free != 0);
-
+
p = da->name;
-
+
len = snprintf(p, bufsize, "Attr-");
p += len;
bufsize -= len;
dv_type = dv->type;
}
len = snprintf(p, bufsize, "26.%u.", vendor);
-
+
p += len;
bufsize -= len;
}
p += print_attr_oid(p, bufsize , attr, dv_type);
-
+
return da;
}
char const *p = attribute;
char *q;
-
+
DICT_VENDOR *dv;
const DICT_ATTR *da;
}
p++;
}
-
+
/*
* Attr-%d
*/
}
p = q;
-
+
/*
* Vendor-%d-Attr-%d
* VendorName-Attr-%d
fr_strerror_printf("Invalid OID");
return NULL;
}
-
+
/*
* Look for OIDs. Require the "Attr-26.Vendor-Id.type"
* format, and disallow "Vendor-%d-Attr-%d" and
fr_strerror_printf("Cannot parse attributes without "
"dictionaries");
return NULL;
- }
-
+ }
+
if ((attr != PW_VENDOR_SPECIFIC) &&
!(da->flags.extended || da->flags.long_extended)) {
fr_strerror_printf("Standard attributes cannot use "
if (dv_type > 3) dv_type = 3; /* hack */
}
}
-
+
/*
* Parse the next number. It could be a Vendor-Type
* of 1..2^24, or it could be a TLV.
if (*q != '.') {
goto invalid;
}
-
+
if (dv_type != 1) {
goto invalid;
}
}
return 0;
-}
+}
void fr_event_loop_exit(fr_event_list_t *el, int code)
*/
if (el->changed) {
FD_ZERO(&master_fds);
-
+
for (i = 0; i < el->max_readers; i++) {
if (el->readers[i].fd < 0) continue;
-
+
if (el->readers[i].fd > maxfd) {
maxfd = el->readers[i].fd;
}
FD_SET(el->readers[i].fd, &master_fds);
}
-
+
el->changed = 0;
}
when = el->now;
} while (fr_event_run(el, &when) == 1);
}
-
+
if (rcode <= 0) continue;
for (i = 0; i < el->max_readers; i++) {
if (ef->fd < 0) continue;
if (!FD_ISSET(ef->fd, &read_fds)) continue;
-
+
ef->handler(el, ef->fd, ef->ctx);
if (el->changed) break;
#define COUNT ((j * SPLIT) + i)
for (i = 0; i < SPLIT; i++) {
array[COUNT % MAX] = COUNT;
-
+
if (!fr_fifo_push(fi, &array[COUNT % MAX])) {
fprintf(stderr, "%d %d\tfailed pushing %d\n",
j, i, COUNT);
exit(2);
}
-
+
if (fr_fifo_num_elements(fi) != (i + 1)) {
fprintf(stderr, "%d %d\tgot size %d expected %d\n",
j, i, i + 1, fr_fifo_num_elements(fi));
for (i = 0; i < SPLIT; i++) {
int *p;
-
+
p = fr_fifo_pop(fi);
if (!p) {
fprintf(stderr, "No pop at %d\n", i);
exit(3);
}
-
+
if (*p != COUNT) {
fprintf(stderr, "%d %d\tgot %d expected %d\n",
j, i, *p, COUNT);
exit(4);
}
-
+
if (fr_fifo_num_elements(fi) != SPLIT - (i + 1)) {
fprintf(stderr, "%d %d\tgot size %d expected %d\n",
j, i, SPLIT - (i + 1), fr_fifo_num_elements(fi));
}
fr_fifo_free(fi);
-
+
exit(0);
}
#endif
if (!node) {
return fr_hash_table_insert(ht, data);
}
-
+
if (ht->free) {
memcpy(&tofree, &node->data, sizeof(tofree));
ht->free(tofree);
memcpy(&tofree, &node->data, sizeof(tofree));
ht->free(tofree);
}
-
+
free(node);
}
}
for (node = ht->buckets[i]; node != &ht->null; node = next) {
void *arg;
-
+
next = node->next;
memcpy(&arg, node->data, sizeof(arg));
rcode = callback(context, arg);
-
+
if (rcode != 0) return rcode;
}
}
int fr_heap_insert(fr_heap_t *hp, void *data)
{
int child = hp->num_elements;
-
+
/*
* Heap is full. Double it's size.
*/
if (child == hp->size) {
void **p;
-
+
p = malloc(2 * hp->size * sizeof(*p));
if (!p) return 0;
-
+
memcpy(p, hp->p, sizeof(*p) * hp->size);
free(hp->p);
hp->p = p;
hp->p[child] = data;
hp->num_elements++;
-
+
return fr_heap_bubble(hp, child);
}
*/
while (child > 0) {
int parent = HEAP_PARENT(child);
-
+
/*
* Parent is smaller than the child. We're done.
*/
if (hp->cmp(hp->p[parent], hp->p[child]) < 0) break;
-
+
/*
* Child is smaller than the parent, repeat.
*/
int max;
if (!hp || (hp->num_elements == 0)) return 0;
-
+
max = hp->num_elements - 1;
-
+
/*
* Extract element. Default is the first one.
*/
}
fr_heap_delete(hp);
-
+
return 0;
}
#endif
uint8_t k_opad[65]; /* outer padding - key XORd with opad */
uint8_t tk[16];
int i;
-
+
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
FR_MD5_CTX tctx;
char *buffer;
pthread_once(&fr_strerror_once, fr_strerror_make_key);
-
+
buffer = pthread_getspecific(fr_strerror_key);
if (!buffer) {
int ret;
-
+
buffer = malloc(FR_STRERROR_BUFSIZE);
if (!buffer) return; /* panic and die! */
-
+
ret = pthread_setspecific(fr_strerror_key, buffer);
if (ret != 0) {
fr_perror("Failed recording thread error: %s",
strerror(ret));
-
+
return;
}
}
{
#ifdef F_WRLCK
struct flock fl;
-
+
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
-
+
return fcntl(fd, F_SETLKW, (void *)&fl);
#else
#error "missing definition for F_WRLCK, all file locks will fail"
-
+
return -1;
#endif
}
{
#ifdef F_WRLCK
struct flock fl;
-
+
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_CUR;
-
+
return fcntl(fd, F_SETLK, (void *)&fl);
#else
#error "missing definition for F_WRLCK, all file locks will fail"
{
#ifdef F_WRLCK
struct flock fl;
-
+
fl.l_start = 0;
fl.l_len = lock_len;
fl.l_pid = getpid();
hex += 2;
bin++;
}
-
+
*hex = '\0';
return len * 2;
}
fr_strerror_printf("IPv4 address is too small");
return 0;
}
-
+
memcpy(&s4, sa, sizeof(s4));
ipaddr->af = AF_INET;
ipaddr->ipaddr.ip4addr = s4.sin_addr;
if (port) *port = ntohs(s4.sin_port);
-
+
#ifdef HAVE_STRUCT_SOCKADDR_IN6
} else if (sa->ss_family == AF_INET6) {
struct sockaddr_in6 s6;
-
+
if (salen < sizeof(s6)) {
fr_strerror_printf("IPv6 address is too small");
return 0;
}
-
+
memcpy(&s6, sa, sizeof(s6));
ipaddr->af = AF_INET6;
ipaddr->ipaddr.ip6addr = s6.sin6_addr;
if (ipaddr->ipaddr.ip4addr.s_addr == INADDR_ANY) {
return 1;
}
-
+
#ifdef HAVE_STRUCT_SOCKADDR_IN6
} else if (ipaddr->af == AF_INET6) {
if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->ipaddr.ip6addr))) {
return 1;
}
#endif
-
+
} else {
fr_strerror_printf("Unknown address family");
return -1;
if (ipaddr->af == AF_INET) {
UNUSED int flag;
-
+
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
/*
* Disable PMTU discovery. On Linux, this
fr_strerror_printf("Failed setting sockopt "
"IPPROTO_IP - IP_MTU_DISCOVER: %s",
strerror(errno));
- return -1;
+ return -1;
}
#endif
if (!ps->dst_any &&
(fr_ipaddr_cmp(&request->dst_ipaddr,
&ps->dst_ipaddr) != 0)) continue;
-
+
/*
* Otherwise, this socket is OK to use.
*/
if (inlen == 0) inlen = strlen(in);
/*
- *
+ *
*/
while ((inlen > 0) && (outlen > 4)) {
/*
/** Print the value of an attribute to a string
- *
+ *
* @param[out] out Where to write the string.
* @param[in] outlen Size of outlen.
* @param[in] vp to print.
for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->length; q++) {
s = bufsize - (p - buffer);
if (s < 4) return -1;
-
+
if (*q == '"') {
*p++ = '\\';
*p++ = '"';
*p++ = *q;
} else {
*p++ = '\\';
-
+
if (*q == '\b') {
*p++ = 'b';
} else if (*q == '\f') {
default:
/* -1 to account for trailing double quote */
s = bufsize - ((p - buffer) - 1);
-
+
len = vp_prints_value(p, s, vp, 0);
if (len >= (s - 1)) return -1;
-
+
p += len;
break;
}
size_t len = 0;
if (!buffer) return 0;
-
+
len = snprintf(p, bufsize, "Attr-");
p += len;
bufsize -= len;
dv_type = dv->type;
}
len = snprintf(p, bufsize, "26.%u.", vendor);
-
+
p += len;
bufsize -= len;
}
if (!vp || !vp->da) return 0;
VERIFY_VP(vp);
-
+
if ((vp->op > T_OP_INVALID) &&
(vp->op < T_TOKEN_LAST)) {
token = vp_tokens[vp->op];
*/
if (data_len < 4) {
rad_recv_discard(sockfd);
-
+
return 1;
} else { /* we got 4 bytes of data. */
*/
if (packet_len < AUTH_HDR_LEN) {
rad_recv_discard(sockfd);
-
+
return 1;
/*
*/
} else if (packet_len > MAX_PACKET_LEN) {
rad_recv_discard(sockfd);
-
+
return 1;
}
}
*/
if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
rad_recv_discard(sockfd);
-
+
return 1;
}
*/
tlv1 = vp->da->attr;
tlv2 = next->da->attr;
-
+
tlv1 &= ((1 << fr_attr_shift[nest]) - 1);
tlv2 &= ((1 << fr_attr_shift[nest]) - 1);
-
+
if (tlv1 != tlv2) return 0;
return 1;
while (vp) {
if (room <= 2) return ptr - start;
-
+
ptr[0] = (vp->da->attr >> fr_attr_shift[nest]) & fr_attr_mask[nest];
ptr[1] = 2;
-
+
my_room = room;
if (room > 255) my_room = 255;
room -= ptr[1];
ptr += ptr[1];
*pvp = vp;
-
+
if (!do_next_tlv(svp, vp, nest)) break;
}
#ifndef NDEBUG
if ((fr_debug_flag > 3) && fr_log_fp) {
const DICT_ATTR *da;
-
+
da = dict_attrbyvalue(svp->da->attr & ((1 << fr_attr_shift[nest ]) - 1), svp->da->vendor);
if (da) fprintf(fr_log_fp, "\t%s = ...\n", da->name);
}
{
int check_len = len - ptr[1];
int total = len + hdr_len;
-
+
/*
* Pass 1: Check if the addition of the headers
* overflows the available room. If so, return
* what we were capable of encoding.
*/
-
+
while (check_len > (255 - hdr_len)) {
total += hdr_len;
check_len -= (255 - hdr_len);
if ((ptr + ptr[1] + total) > end) {
return (ptr + ptr[1]) - start;
}
-
+
/*
* Pass 2: Now that we know there's enough room,
* re-arrange the data to form a set of valid
*/
while (1) {
int sublen = 255 - ptr[1];
-
+
if (len <= sublen) {
break;
}
-
+
len -= sublen;
memmove(ptr + 255 + hdr_len, ptr + 255, sublen);
memcpy(ptr + 255, ptr, hdr_len);
ptr[1] += sublen;
if (vsa_offset) ptr[vsa_offset] += sublen;
ptr[flag_offset] |= 0x80;
-
+
ptr += 255;
ptr[1] = hdr_len;
if (vsa_offset) ptr[vsa_offset] = 3;
if (!vp->da->flags.long_extended) {
if (room < 3) return 0;
-
+
ptr[1] = 3;
ptr[2] = vp->da->attr & fr_attr_mask[0];
evs[1] = (vp->da->vendor >> 16) & 0xff;
evs[2] = (vp->da->vendor >> 8) & 0xff;
evs[3] = vp->da->vendor & 0xff;
- evs[4] = vp->da->attr & fr_attr_mask[0];
+ evs[4] = vp->da->attr & fr_attr_mask[0];
ptr[1] += 5;
}
}
ptr[1] += len;
-
+
#ifndef NDEBUG
if ((fr_debug_flag > 3) && fr_log_fp) {
int jump = 3;
fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
if (!vp->da->flags.long_extended) {
fprintf(fr_log_fp, "%02x ", ptr[2]);
-
+
} else {
fprintf(fr_log_fp, "%02x %02x ", ptr[2], ptr[3]);
jump = 4;
fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ",
ptr[0], ptr[1], ptr[2], ptr[3]);
break;
-
+
case 2:
if ((fr_debug_flag > 3) && fr_log_fp)
fprintf(fr_log_fp, "\t\t%02x%02x ",
ptr[0], ptr[1]);
break;
-
+
case 1:
if ((fr_debug_flag > 3) && fr_log_fp)
fprintf(fr_log_fp, "\t\t%02x ", ptr[0]);
break;
}
-
+
switch (dv->length) {
default:
break;
*/
if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
if (room < 18) return -1;
-
+
debug_pair(vp);
ptr[0] = PW_MESSAGE_AUTHENTICATOR;
ptr[1] = 18;
fprintf(fr_log_fp, "\t\t50 12 ...\n");
}
#endif
-
+
*pvp = (*pvp)->next;
return 18;
}
while (reply) {
size_t last_len;
char const *last_name = NULL;
-
+
VERIFY_VP(reply);
/*
fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
return -1;
}
-#endif
+#endif
switch (dv->type) {
case 4:
data, attrlen, packetlen, pvp);
return rcode;
}
-
+
/*
* VSAs should normally be in TLV format.
*/
while (attrlen > 0) {
ssize_t vsa_len;
-
+
vsa_len = data2vp_vsa(packet, original, secret, dv,
data, attrlen, tail);
if (vsa_len < 0) {
fr_strerror_printf("ERROR: rad_vp2data buffer passed too small");
return -1;
}
-
+
switch(vp->da->type) {
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
case PW_TYPE_BYTE:
out[0] = vp->vp_integer & 0xff;
break;
-
+
case PW_TYPE_SHORT:
out[0] = (vp->vp_integer >> 8) & 0xff;
out[1] = vp->vp_integer & 0xff;
break;
-
+
case PW_TYPE_INTEGER:
lvalue = htonl(vp->vp_integer);
memcpy(out, &lvalue, sizeof(lvalue));
break;
-
+
case PW_TYPE_INTEGER64:
lvalue64 = htonll(vp->vp_integer64);
memcpy(out, &lvalue64, sizeof(lvalue64));
lvalue = htonl(vp->vp_date);
memcpy(out, &lvalue, sizeof(lvalue));
break;
-
+
case PW_TYPE_SIGNED:
{
int32_t slvalue;
-
+
slvalue = htonl(vp->vp_signed);
memcpy(out, &slvalue, sizeof(slvalue));
break;
}
/* unknown type: ignore it */
- default:
+ default:
fr_strerror_printf("ERROR: Unknown attribute type %d",
vp->da->type);
return -1;
}
-
+
return len;
}
* random pool.
*/
fr_rand_seed(packet->data, AUTH_HDR_LEN);
-
+
/*
* There may be VP's already in the packet. Don't
* destroy them. Instead, add the decoded attributes to
#ifdef O_NONBLOCK
{
int flags;
-
+
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
fr_strerror_printf("Failure getting socket flags: %s",
strerror(errno));
close(sockfd);
return -1;
}
-
+
flags |= O_NONBLOCK;
if( fcntl(sockfd, F_SETFL, flags) < 0) {
fr_strerror_printf("Failure setting socket flags: %s",
close(sockfd);
return -1;
}
-
+
if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
fr_strerror_printf("Failure binding to IP: %s",
strerror(errno));
fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes.");
return -1;
}
-
+
packet->data = talloc_array(packet, uint8_t, packet_len);
if (!packet->data) {
fr_strerror_printf("Out of memory");
socklen_t salen;
RADIUS_PACKET *packet;
struct sockaddr_storage src;
-
+
salen = sizeof(src);
newfd = accept(sockfd, (struct sockaddr *) &src, &salen);
return NULL;
}
-
+
packet = rad_alloc(NULL, 0);
if (!packet) {
close(newfd);
char const *p;
if (!ptr || !*ptr || !buf) return T_OP_INVALID;
-
+
p = *ptr;
while (*p && (isspace((int)*p))) p++;
if (!name) {
return def;
}
-
+
for (this = table; this->name != NULL; this++) {
if (strcasecmp(this->name, name) == 0) {
return this->number;
* Match up to the length of the table entry if len is < 0.
*/
max = (len < 0) ? tlen : (unsigned)len;
-
+
if (strncasecmp(this->name, name, max) == 0) {
return this->number;
}
proto = SOL_IP;
flag = IP_PKTINFO;
#endif
-
+
#ifdef IP_RECVDSTADDR
/*
* Set the IP_RECVDSTADDR option (BSD). Note:
*/
return -1;
}
-
+
/*
* Unsupported. Don't worry about it.
*/
#else
struct sockaddr_in *dst = (struct sockaddr_in *) to;
struct sockaddr_in *src = (struct sockaddr_in *) &si;
-
+
if (*tolen < sizeof(*dst)) {
errno = EINVAL;
return -1;
#else
struct sockaddr_in6 *dst = (struct sockaddr_in6 *) to;
struct sockaddr_in6 *src = (struct sockaddr_in6 *) &si;
-
+
if (*tolen < sizeof(*dst)) {
errno = EINVAL;
return -1;
#endif
/*
* Unknown address family.
- */
+ */
else {
errno = EINVAL;
return -1;
else if (from->sa_family == AF_INET6) {
#if !defined(IPV6_PKTINFO)
return sendto(s, buf, len, flags, to, tolen);
-#else
+#else
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from;
struct in6_pktinfo *pkt;
/*
* Unknown address family.
- */
+ */
else {
errno = EINVAL;
return -1;
static char const *months[] = {
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec" };
-
+
#define attribute_eq(_x, _y) ((_x && _y) && (_x->da == _y->da) && (_x->tag == _y->tag))
/** Dynamically allocate a new attribute
fr_strerror_printf("Out of memory");
return NULL;
}
-
+
vp->da = da;
vp->op = T_OP_EQ;
vp->type = VT_NONE;
if (!vp) return;
VERIFY_VP(vp);
-
+
/*
* The lack of DA means something has gone wrong
*/
if (!vps) {
return;
}
-
+
for (vp = paircursor(&cursor, vps);
vp;
vp = pairnext(&cursor)) {
int pair2unknown(VALUE_PAIR *vp)
{
const DICT_ATTR *da;
-
+
VERIFY_VP(vp);
if (vp->da->flags.is_unknown) {
return 0;
}
-
+
da = dict_attrunknown(vp->da->attr, vp->da->vendor, true);
if (!da) {
return -1;
}
-
+
vp->da = da;
-
+
return 0;
}
VALUE_PAIR *paircursorc(vp_cursor_t *cursor, VALUE_PAIR const * const *node)
{
memset(cursor, 0, sizeof(*cursor));
-
+
if (!node || !cursor) {
return NULL;
}
-
+
memcpy(&cursor->first, &node, sizeof(cursor->first));
cursor->current = *cursor->first;
-
+
if (cursor->current) {
VERIFY_VP(cursor->current);
cursor->next = cursor->current->next;
}
-
+
return cursor->current;
}
-VALUE_PAIR *pairfirst(vp_cursor_t *cursor)
+VALUE_PAIR *pairfirst(vp_cursor_t *cursor)
{
cursor->current = *cursor->first;
-
+
if (cursor->current) {
VERIFY_VP(cursor->current);
cursor->next = cursor->current->next;
if (!i) {
cursor->next = NULL;
cursor->current = NULL;
-
+
return NULL;
- }
-
+ }
+
cursor->next = i->next;
cursor->current = i;
cursor->found = i;
-
+
return i;
}
if (cursor->current) {
VERIFY_VP(cursor->current);
- /*
+ /*
* Set this now in case 'current' gets freed before
* pairnext is called again.
*/
cursor->next = cursor->current->next;
-
+
/*
* Next call to pairfindnext will start from the current
* position in the list, not the last found instance.
*/
cursor->found = NULL;
}
-
+
return cursor->current;
}
if (cursor->current) {
VERIFY_VP(cursor->current);
}
-
+
return cursor->current;
}
-/** Insert a VP
+/** Insert a VP
*
* @todo don't use with pairdelete
*/
if (!add) {
return;
}
-
+
VERIFY_VP(add);
/*
*cursor->first = add;
cursor->current = add;
cursor->next = cursor->current->next;
-
+
return;
}
-
+
/*
* We don't yet know where the last VALUE_PAIR is
*
if (!cursor->last) {
cursor->last = cursor->current ? cursor->current : *cursor->first;
}
-
+
VERIFY_VP(cursor->last);
-
+
/*
* Something outside of the cursor added another VALUE_PAIR
*/
cursor->last = i;
}
}
-
+
/*
- * Either current was never set, or something iterated to the end of the
+ * Either current was never set, or something iterated to the end of the
* attribute list.
*/
if (!cursor->current) {
cursor->current = add;
}
-
+
cursor->last->next = add;
}
VALUE_PAIR *pairremove(vp_cursor_t *cursor)
{
VALUE_PAIR *vp, *last;
-
+
vp = paircurrent(cursor);
if (!vp) {
return NULL;
}
-
+
last = *cursor->first;
while (last && (last->next != vp)) {
last = last->next;
}
-
+
pairnext(cursor); /* Advance the cursor past the one were about to delete */
-
+
last->next = vp->next; /* re-link the list */
vp->next = NULL;
-
+
return vp;
}
{
VALUE_PAIR *fast;
VALUE_PAIR *slow;
-
+
/*
* Stopping condition - no more elements left to split
*/
if (!source || !source->next) {
*front = source;
*back = NULL;
-
+
return;
}
-
+
/*
* Fast advances twice as fast as slow, so when it gets to the end,
* slow will point to the middle of the linked list.
*/
slow = source;
fast = source->next;
-
+
while (fast) {
fast = fast->next;
if (fast) {
static VALUE_PAIR *pairsort_merge(VALUE_PAIR *a, VALUE_PAIR *b, bool with_tag)
{
VALUE_PAIR *result = NULL;
-
+
if (!a) return b;
if (!b) return a;
-
+
/*
* Compare the DICT_ATTRs and tags
*/
result = b;
result->next = pairsort_merge(a, b->next, with_tag);
}
-
+
return result;
}
VALUE_PAIR *head = *vps;
VALUE_PAIR *a;
VALUE_PAIR *b;
-
+
/*
* If there's 0-1 elements it must already be sorted.
*/
if (!head || !head->next) {
return;
}
-
+
pairsort_split(head, &a, &b); /* Split into sublists */
pairsort(&a, with_tag); /* Traverse left */
pairsort(&b, with_tag); /* Traverse right */
-
+
/*
* merge the two sorted lists together
*/
{
vp_cursor_t filter_cursor;
vp_cursor_t list_cursor;
-
+
VALUE_PAIR *check, *match, *last_check = NULL, *last_match;
if (!filter && !list) {
if (!filter || !list) {
return false;
}
-
+
/*
* This allows us to verify the sets of validate and reply are equal
* i.e. we have a validate rule which matches every reply attribute.
*/
pairsort(&filter, true);
pairsort(&list, true);
-
+
paircursor(&list_cursor, &list);
for (check = paircursor(&filter_cursor, &filter);
check;
if (!attribute_eq(paircurrent(&list_cursor), paircurrent(&filter_cursor))) {
return false;
}
-
+
last_match = paircurrent(&list_cursor);
paircursor(&list_cursor, &last_match); /* not strictly needed */
last_check = check;
/*
* There were additional VALUE_PAIRS left in the list
- */
+ */
if (paircurrent(&list_cursor)) {
return false;
}
-
+
return true;
}
fr_strerror_printf("out of memory");
return NULL;
}
-
+
memcpy(n, vp, sizeof(*n));
-
+
/*
* Now copy the value
*/
if (vp->type == VT_XLAT) {
n->value.xlat = talloc_strdup(n, n->value.xlat);
}
-
+
n->da = dict_attr_copy(vp->da, true);
if (!n->da) {
pairbasicfree(n);
return NULL;
}
-
+
n->next = NULL;
if ((n->da->type == PW_TYPE_TLV) ||
talloc_free(p);
return n;
}
-
+
n = pairalloc(ctx, da);
if (!n) {
- return NULL;
+ return NULL;
}
memcpy(n, vp, sizeof(*n));
if (n->type == VT_XLAT) {
n->value.xlat = talloc_strdup(n, n->value.xlat);
}
-
+
if ((n->da->type == PW_TYPE_TLV) ||
(n->da->type == PW_TYPE_OCTETS) ||
(n->da->type == PW_TYPE_STRING)) {
unsigned int attr, unsigned int vendor, int8_t tag)
{
vp_cursor_t src, dst;
-
+
VALUE_PAIR *out = NULL, *vp;
-
+
paircursor(&dst, &out);
for (vp = paircursor(&src, &from);
vp;
if ((attr > 0) && ((vp->da->attr != attr) || (vp->da->vendor != vendor))) {
continue;
}
-
+
if ((tag != TAG_ANY) && vp->da->flags.has_tag && (vp->tag != tag)) {
continue;
}
}
pairinsert(&dst, vp);
}
-
+
return out;
}
VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *from)
{
vp_cursor_t src, dst;
-
+
VALUE_PAIR *out = NULL, *vp;
-
+
paircursor(&dst, &out);
for (vp = paircursor(&src, &from);
vp;
}
pairinsert(&dst, vp); /* paircopy sets next pointer to NULL */
}
-
+
return out;
}
found = pairfind(*to, i->da->attr, i->da->vendor,
TAG_ANY);
-
+
switch (i->op) {
/*
} else {
*to = *from;
}
-
+
for (i = *from; i; i = i->next) {
(void) talloc_steal(ctx, i);
}
(i->tag != tag)) {
continue;
}
-
+
/*
* vendor=0, attr = PW_VENDOR_SPECIFIC means
* "match any vendor attribute".
case PW_TYPE_COMBO_IP:
{
const DICT_ATTR *da;
-
+
if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) > 0) {
da = dict_attrbytype(vp->da->attr, vp->da->vendor,
PW_TYPE_IPV6ADDR);
if (!da) {
return false;
}
-
+
vp->length = 16; /* length of IPv6 address */
} else {
fr_ipaddr_t ipaddr;
-
+
da = dict_attrbytype(vp->da->attr, vp->da->vendor,
PW_TYPE_IPADDR);
if (!da) {
vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
vp->length = 4;
}
-
+
vp->da = da;
}
break;
{
VALUE_PAIR *vp;
const DICT_ATTR *da;
-
+
uint8_t *data;
size_t size;
if (value && (strncasecmp(value, "0x", 2) != 0)) {
fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
"string, not \"%s\"", attribute, value);
-
+
dict_attr_free(&da);
return NULL;
}
dict_attr_free(&da);
return NULL;
}
-
+
vp->op = (op == 0) ? T_OP_EQ : op;
-
+
if (!value) return vp;
size = strlen(value + 2);
if (!value) break;
pairbasicfree(vp);
-
+
if (1) {
int compare;
regex_t reg;
-
+
compare = regcomp(®, value, REG_EXTENDED);
if (compare != 0) {
regerror(compare, ®, buffer, sizeof(buffer));
vp = pairmake(ctx, NULL, attribute, NULL, op);
if (!vp) return NULL;
-
+
if (pairmark_xlat(vp, value) < 0) {
pairbasicfree(vp);
return NULL;
int pairmark_xlat(VALUE_PAIR *vp, char const *value)
{
char *raw;
-
+
/*
* valuepair should not already have a value.
*/
if (vp->type != VT_NONE) {
return -1;
}
-
+
raw = talloc_strdup(vp, value);
if (!raw) {
return -1;
}
-
+
vp->type = VT_XLAT;
vp->value.xlat = raw;
vp->length = 0;
- return 0;
+ return 0;
}
/** Read a single valuepair from a buffer, and advance the pointer
if (*p == '#') {
fr_strerror_printf("Read a comment instead of a token");
-
+
return T_HASH;
}
raw->op = gettoken(ptr, buf, sizeof(buf));
if (raw->op < T_EQSTART || raw->op > T_EQEND) {
fr_strerror_printf("Expecting operator");
-
+
return T_OP_INVALID;
}
quote = gettoken(ptr, raw->r_opand, sizeof(raw->r_opand));
if (quote == T_EOL) {
fr_strerror_printf("Failed to get value");
-
+
return T_OP_INVALID;
}
* Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
*/
p = *ptr;
-
+
next = gettoken(&p, buf, sizeof(buf));
switch (next) {
case T_EOL:
case T_HASH:
break;
-
+
case T_COMMA:
*ptr = p;
break;
-
+
default:
fr_strerror_printf("Expected end of line or comma");
- return T_OP_INVALID;
+ return T_OP_INVALID;
}
ret = next;
} else {
raw->quote = T_SINGLE_QUOTED_STRING;
}
-
+
break;
default:
raw->quote = quote;
-
+
break;
}
do {
raw.l_opand[0] = '\0';
raw.r_opand[0] = '\0';
-
+
previous_token = last_token;
-
+
last_token = pairread(&p, &raw);
if (last_token == T_OP_INVALID) break;
-
- if (raw.quote == T_DOUBLE_QUOTED_STRING) {
+
+ if (raw.quote == T_DOUBLE_QUOTED_STRING) {
vp = pairmake(ctx, NULL, raw.l_opand, NULL, raw.op);
if (!vp) {
last_token = T_OP_INVALID;
}
if (pairmark_xlat(vp, raw.r_opand) < 0) {
pairbasicfree(vp);
-
+
break;
}
} else {
break;
}
}
-
+
*tail = vp;
tail = &((*tail)->next);
} while (*p && (last_token == T_COMMA));
mask <<= (8 - common);
mask--;
mask = ~mask;
-
+
if ((one[i] & mask) == ((two[i] & mask))) {
return true;
}
-
+
return false;
}
RDEBUG2("Found Auth-Type = %s", dict_valnamebyattr(PW_AUTH_TYPE, 0, auth_type));
if (auth_type == PW_AUTHTYPE_REJECT) {
RDEBUG2("Auth-Type = Reject, rejecting user");
-
+
return -2;
}
}
{ "src_ipaddr", PW_TYPE_STRING_PTR,
0, &cl_srcipaddr, NULL },
-
+
{ "require_message_authenticator", PW_TYPE_BOOLEAN,
offsetof(RADCLIENT, message_authenticator), 0, "no" },
/* Replace '/' with '\0' */
*prefix_ptr = '\0';
}
-
+
/*
* Always get the numeric representation of IP
*/
if ((c->prefix < -1) || (c->prefix > 32)) {
cf_log_err_cs(cs, "Netmask must be between 0 and 32");
-
+
goto error;
}
-
+
} else if (cf_pair_find(cs, "ipv6addr")) {
c->ipaddr.af = AF_INET6;
c->ipaddr.ipaddr.ip6addr = cl_ip6addr;
-
+
if ((c->prefix < -1) || (c->prefix > 128)) {
cf_log_err_cs(cs,
"Netmask must be between 0 and 128");
if (hs_proto) {
if (strcmp(hs_proto, "udp") == 0) {
hs_proto = NULL;
-
+
} else if (strcmp(hs_proto, "tcp") == 0) {
hs_proto = NULL;
c->proto = IPPROTO_TCP;
-
+
} else if (strcmp(hs_proto, "*") == 0) {
hs_proto = NULL;
c->proto = IPPROTO_IP; /* fake for dual */
-
+
} else {
cf_log_err_cs(cs,
"Unknown proto \"%s\".", hs_proto);
#else
WDEBUG("Server not build with udpfromto, ignoring client src_ipaddr");
#endif
-
+
cl_srcipaddr = NULL;
}
-
+
if (c->prefix < 0) switch (c->ipaddr.af) {
case AF_INET:
c->prefix = 32;
*/
cp = cf_pair_find(cs, "directory");
if (!cp) goto add_client;
-
+
value = cf_pair_value(cp);
if (!value) {
cf_log_err_cs(cs,
}
DEBUG("including dynamic clients in %s", value);
-
+
dir = opendir(value);
if (!dir) {
cf_log_err_cs(cs, "Error reading directory %s: %s", value, strerror(errno));
client_free(c);
return NULL;
}
-
+
/*
* Read the directory, ignoring "." files.
*/
* Validate, and add to the list.
*/
if (!client_validate(clients, c, dc)) {
-
+
client_free(c);
closedir(dir);
return NULL;
RADCLIENT *c;
char *id;
char *prefix;
-
+
rad_assert(identifier);
rad_assert(secret);
-
+
c = talloc_zero(ctx, RADCLIENT);
#ifdef WITH_DYNAMIC_CLIENTS
if (prefix) {
c->prefix = atoi(prefix + 1);
if ((c->prefix < 0) || (c->prefix > 128)) {
- ERROR("Invalid Prefix value '%s' for IP.", prefix + 1);
+ ERROR("Invalid Prefix value '%s' for IP.", prefix + 1);
talloc_free(c);
-
+
return NULL;
}
-
+
/* Replace '/' with '\0' */
*prefix = '\0';
}
if (ip_hton(id, AF_UNSPEC, &c->ipaddr) < 0) {
ERROR("Failed to look up hostname %s: %s", id, fr_strerror());
talloc_free(c);
-
+
return NULL;
}
-
+
{
char buffer[256];
ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
* Other values (secret, shortname, nas_type, virtual_server)
*/
c->secret = talloc_strdup(c, secret);
-
- if (shortname) {
+
+ if (shortname) {
c->shortname = talloc_strdup(c, shortname);
}
-
+
if (type) {
c->nas_type = talloc_strdup(c, type);
}
-
+
if (server) {
c->server = talloc_strdup(c, server);
}
-
+
c->message_authenticator = require_ma;
return c;
c->cs = request->client->cs;
c->ipaddr.af = AF_UNSPEC;
c->src_ipaddr.af = AF_UNSPEC;
-
+
for (i = 0; dynamic_config[i].name != NULL; i++) {
const DICT_ATTR *da;
VALUE_PAIR *vp;
* Not required. Skip it.
*/
if (!dynamic_config[i].dflt) continue;
-
- DEBUG("- Cannot add client %s: Required attribute \"%s\" is missing.",
+
+ DEBUG("- Cannot add client %s: Required attribute \"%s\" is missing.",
ip_ntoh(&request->packet->src_ipaddr,
buffer, sizeof(buffer)),
dynamic_config[i].name);
WDEBUG("Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address.");
#endif
}
-
+
break;
case PW_TYPE_IPV6ADDR:
WDEBUG("Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address.");
#endif
}
-
+
break;
case PW_TYPE_STRING_PTR:
ip_ntoh(&request->packet->src_ipaddr,
buffer, sizeof(buffer)),
ip_ntoh(&c->ipaddr,
- buf2, sizeof(buf2)));
+ buf2, sizeof(buf2)));
goto error;
}
if (!client_validate(clients, request->client, c)) {
return NULL;
}
-
+
if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
DEBUG("- Cannot add client %s: Client IP and src address are different IP version.",
ip_ntoh(&request->packet->src_ipaddr,
buffer, sizeof(buffer)));
-
+
goto error;
}
cs = cf_file_read(filename);
if (!cs) return NULL;
-
+
cs = cf_section_sub_find(cs, "client");
if (!cs) {
ERROR("No \"client\" section found in client file");
#else
struct ucred cr;
socklen_t cl = sizeof(cr);
-
+
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
return -1;
}
socklen_t socklen;
struct sockaddr_un salocal;
struct stat buf;
-
+
if (!path) {
ERROR("No path provided, was NULL.");
return -1;
}
-
+
len = strlen(path);
if (len >= sizeof(salocal.sun_path)) {
ERROR("Path too long in socket filename.");
memset(&salocal, 0, sizeof(salocal));
salocal.sun_family = AF_UNIX;
memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
-
+
socklen = SUN_LEN(&salocal);
/*
) {
ERROR("Cannot turn %s into socket", path);
close(sockfd);
- return -1;
+ return -1;
}
/*
#ifdef O_NONBLOCK
{
int flags;
-
+
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
ERROR("Failure getting socket flags: %s",
strerror(errno));
close(sockfd);
return -1;
}
-
+
flags |= O_NONBLOCK;
if( fcntl(sockfd, F_SETFL, flags) < 0) {
ERROR("Failure setting socket flags: %s",
*/
static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
void const *base)
-
+
{
int i;
const void *data;
}
indent++;
-
+
/*
* Print
*/
if (!variables[i].data) {
continue;
}
-
+
data = variables[i].data;;
-
+
} else if (variables[i].data) {
data = variables[i].data;;
-
+
} else {
data = (((char const *)base) + variables[i].offset);
}
cprintf(listener, "%.*s%s = ?\n", indent, tabs,
variables[i].name);
break;
-
+
case PW_TYPE_INTEGER:
cprintf(listener, "%.*s%s = %u\n", indent, tabs,
variables[i].name, *(int const *) data);
break;
-
+
case PW_TYPE_IPADDR:
inet_ntop(AF_INET, data, buffer, sizeof(buffer));
break;
variables[i].name,
((*(int const *) data) == 0) ? "no" : "yes");
break;
-
+
case PW_TYPE_STRING_PTR:
case PW_TYPE_FILE_INPUT:
case PW_TYPE_FILE_OUTPUT:
cprintf(listener, "%.*s%s = \n", indent, tabs,
variables[i].name);
}
-
+
break;
}
}
fclose(fp);
return 0;
}
-
+
ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
if (!ci) {
cprintf(listener, "ERROR: No such item <reference>\n");
cprintf(listener, "invalid\n");
break;
}
-
+
return 1;
}
#endif
&packet->src_ipaddr.ipaddr,
buffer, sizeof(buffer)),
packet->code, packet->id);
-
- for (vp = paircursor(&cursor, &packet->vps);
+
+ for (vp = paircursor(&cursor, &packet->vps);
vp;
vp = pairnext(&cursor)) {
vp_prints(buffer, sizeof(buffer), vp);
cprintf(listener, "\trequests\t" PU "\n", stats->total_requests);
cprintf(listener, "\tresponses\t" PU "\n", stats->total_responses);
-
+
if (auth) {
cprintf(listener, "\taccepts\t\t" PU "\n",
stats->total_access_accepts);
#if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
if (sock->uid_name) {
struct passwd *pw;
-
+
pw = getpwnam(sock->uid_name);
if (!pw) {
ERROR("Failed getting uid for %s: %s",
/*
* FIXME: check for absolute pathnames?
- * check for uid/gid on the other end...
+ * check for uid/gid on the other end...
*/
this->fd = fr_server_domain_socket(sock->path);
memcpy(str, buffer, len + 1);
argv[argc] = str;
-
+
memcpy(&str, &p, sizeof(str));
} else {
argv[argc] = str;
fr_command_table_t *table, int recursive)
{
int i;
-
+
for (i = 0; table[i].command != NULL; i++) {
if (table[i].help) {
cprintf(listener, "%s\n",
/*
* This is the last argument, but
* there's a sub-table. Print help.
- *
+ *
*/
if (argc == 1) {
table = table[i].table;
strerror(errno));
return -1;
}
-
+
if (sock) {
magic = htonl(2); /* protocol version */
} else {
*/
if (co->offset < 16) {
ssize_t r;
-
+
r = read(this->fd,
co->buffer + 16 + co->offset, 16 - co->offset);
if (r == 0) {
if (errno == ECONNRESET) goto close_socket;
#endif
if (errno == EINTR) return 0;
-
+
ERROR("Failed reading from control socket; %s",
strerror(errno));
goto close_socket;
socklen_t salen;
struct sockaddr_storage src;
fr_command_socket_t *sock = listener->data;
-
+
salen = sizeof(src);
DEBUG2(" ... new connection request on command socket.");
if (sock->uid_name && (sock->uid != uid)) {
ERROR("Unauthorized connection to %s from uid %ld",
-
+
sock->path, (long int) uid);
close(newfd);
return 0;
}
-
+
if (sock->gid_name && (sock->gid != gid)) {
ERROR("Unauthorized connection to %s from gid %ld",
sock->path, (long int) gid);
const FR_NAME_NUMBER conf_property_name[] = {
{ "name", CONF_PROPERTY_NAME},
{ "instance", CONF_PROPERTY_INSTANCE},
-
+
{ NULL , -1 }
};
CONF_PAIR *cf_itemtopair(CONF_ITEM const *ci)
{
CONF_PAIR *out;
-
+
if (ci == NULL) {
return NULL;
}
rad_assert(ci->type == CONF_ITEM_PAIR);
-
+
memcpy(&out, &ci, sizeof(out));
return out;
}
CONF_SECTION *cf_itemtosection(CONF_ITEM const *ci)
{
CONF_SECTION *out;
-
+
if (ci == NULL) {
return NULL;
}
rad_assert(ci->type == CONF_ITEM_SECTION);
-
+
memcpy(&out, &ci, sizeof(out));
return out;
}
CONF_ITEM *cf_pairtoitem(CONF_PAIR const *cp)
{
CONF_ITEM *out;
-
+
if (cp == NULL) {
return NULL;
}
-
+
memcpy(&out, &cp, sizeof(out));
return out;
}
CONF_ITEM *cf_sectiontoitem(CONF_SECTION const *cs)
{
CONF_ITEM *out;
-
+
if (cs == NULL) {
return NULL;
}
-
+
memcpy(&out, &cs, sizeof(out));
return out;
}
static CONF_ITEM *cf_datatoitem(CONF_DATA const *cd)
{
CONF_ITEM *out;
-
+
if (cd == NULL) {
return NULL;
}
-
+
memcpy(&out, &cd, sizeof(out));
return out;
}
*/
if (*p == '.') {
p++;
-
+
/*
* Just '.' means the current section
*/
if (*p == '\0') {
return cf_sectiontoitem(cs);
}
-
+
/*
* ..foo means "foo from the section
* enclosing this section" (etc.)
if (cs->item.parent) {
cs = cs->item.parent;
}
-
+
/*
- * .. means the section
+ * .. means the section
* enclosing this section
*/
if (!*++p) {
next = cf_section_sub_find(cs, p);
if (next) return &(next->item);
-
+
/*
* "foo" is "in the current section, OR in main".
*/
memcpy(name, ptr, end - ptr);
name[end - ptr] = '\0';
-
+
q = strchr(name, ':');
- if (q) {
+ if (q) {
*(q++) = '\0';
}
-
+
ci = cf_reference_item(parentcs, outercs, name);
if (!ci) {
ERROR("%s[%d]: Reference \"%s\" not found", cf, *lineno, input);
ERROR("%s[%d]: Can only reference properties of sections", cf, *lineno);
return NULL;
}
-
+
switch (fr_str2int(conf_property_name, q, CONF_PROPERTY_INVALID)) {
case CONF_PROPERTY_NAME:
strcpy(p, mycs->name1);
break;
-
+
case CONF_PROPERTY_INSTANCE:
strcpy(p, mycs->name2 ? mycs->name2 : mycs->name1);
break;
-
+
default:
ERROR("%s[%d]: Invalid property '%s'", cf, *lineno, q);
return NULL;
}
p += strlen(p);
ptr = end + 1;
-
+
} else if (ci->type == CONF_ITEM_PAIR) {
/*
* Substitute the value of the variable.
* with a default value.
*
* Returns -1 on error, -2 if deprecated, 0 for correctly parsed,
- * and 1 if the default value was used. Note that the default
+ * and 1 if the default value was used. Note that the default
* value will be used ONLY if the CONF_PAIR is NULL.
*/
int cf_item_parse(CONF_SECTION *cs, char const *name, int type, void *data, char const *dflt)
if (attribute) {
required = 1;
}
-
+
cp = cf_pair_find(cs, name);
if (cp) {
value = cp->value;
if (deprecated) {
cf_log_err(&(cs->item), "Configuration item \"%s\" is deprecated", name);
-
+
return -2;
}
cf_log_info(cs, "%.*s\t%s = \"%s\"",
cs->depth, parse_spaces, name, value);
*q = value ? talloc_strdup(cs, value) : NULL;
-
+
/*
* And now we "stat" the file.
*/
if (stat(*q, &buf) == 0) {
time_t *mtime = talloc(cs, time_t);
-
+
*mtime = buf.st_mtime;
/* FIXME: error? */
cf_data_add_internal(cs, *q, mtime, NULL, type);
ERROR("Can't find IP address for host %s", value);
return -1;
}
-
+
if (strspn(value, "0123456789.") == strlen(value)) {
cf_log_info(cs, "%.*s\t%s = %s",
cs->depth, parse_spaces, name, value);
cf_log_err(&(cs->item), "Replace \"%s\" with \"%s\"", variables[i].name,
variables[i + 1].name);
}
-
+
goto error;
}
} /* for all variables in the configuration section */
*/
if (cbuf == buf) {
if (at_eof) break;
-
+
ptr = buf;
while (*ptr && isspace((int) *ptr)) ptr++;
case T_EOL:
case T_HASH:
goto do_bare_word;
-
+
default:
ERROR("%s[%d]: Invalid expansion: %s",
filename, *lineno, ptr);
*/
if (stat(value, &stat_buf) < 0) {
ERROR("%s[%d]: Failed reading directory %s: %s",
- filename, *lineno,
+ filename, *lineno,
value, strerror(errno));
return -1;
}
filename, *lineno, buf2);
return -1;
}
-
+
if (this->template) {
ERROR("%s[%d]: Section already has a template",
filename, *lineno);
server = server->item.parent;
if (!server) goto invalid_location;
}
-
+
slen = fr_condition_tokenize(this, ptr, &cond, &error);
if (p) *p = '{';
buf2[slen] = '\0';
ptr += slen;
t2 = T_BARE_WORD;
-
+
if (gettoken(&ptr, buf3, sizeof(buf3)) != T_LCBRACE) {
talloc_free(cond);
EDEBUG("%s[%d]: Expected '{'",
} else {
value = buf3;
}
-
+
/*
* Add this CONF_PAIR to our CONF_SECTION
*/
((pair->value_type == T_DOUBLE_QUOTED_STRING) ||
(pair->value_type == T_BACK_QUOTED_STRING))) {
VALUE_PAIR *vp;
-
+
vp = pairmake(pair, NULL, pair->attr, NULL, pair->op);
if (!vp) {
return NULL;
}
-
+
if (pairmark_xlat(vp, pair->value) < 0) {
pairbasicfree(vp);
return NULL;
}
-
+
return vp;
}
if (strcmp(cf_itemtosection(ci)->name1, name1) != 0) {
continue;
}
-
+
their2 = cf_itemtosection(ci)->name2;
if ((!name2 && !their2) ||
return cf_itemtosection(ci);
}
}
-
+
return NULL;
}
/** Find a CONF_SECTION with both names.
- *
+ *
*/
CONF_SECTION *cf_section_sub_find_name2(CONF_SECTION const *cs,
char const *name1, char const *name2)
default: /* should really be an error. */
break;
-
+
}
}
default: /* should really be an error. */
break;
-
+
}
}
struct fr_connection {
fr_connection_t *prev; //!< Previous connection in list.
fr_connection_t *next; //!< Next connection in list.
-
+
time_t created; //!< Time connection was created.
time_t last_used; //!< Last time the connection was
//!< reserved.
-
+
uint64_t num_uses; //!< Number of times the connection
//!< has been reserved.
int in_use; //!< Whether the connection is currently
*
* @see fr_connection
*/
-struct fr_connection_pool_t {
+struct fr_connection_pool_t {
int start; //!< Number of initial connections
int min; //!< Minimum number of concurrent
//!< connections to keep open.
//!< of whether it's idle or not).
int idle_timeout; //!< How long a connection can be idle
//!< before being closed.
-
+
int trigger; //!< If true execute connection triggers
//!< associated with the connection
//!< pool.
-
- int spread; //!< If true requests will be spread
+
+ int spread; //!< If true requests will be spread
//!< across all connections, instead of
//!< re-using the most recently used
//!< connections first.
//!< already spawning a connection.
time_t last_at_max; //!< Last time we hit the maximum number
//!< of allowed connections.
-
+
uint64_t count; //!< Number of connections spawned over
//!< the lifetime of the pool.
int num; //!< Number of connections in the pool.
fr_connection_t *head; //!< Start of the connection list.
fr_connection_t *tail; //!< End of the connection list.
-
+
bool spawning; //!< Whether we are currently attempting
//!< to spawn a new connection.
//!< that relates to this pool.
void *ctx; //!< Pointer to context data that will
//!< be passed to callbacks.
-
+
char *log_prefix; //!< Log prefix to prepend to all log
//!< messages created by the connection
//!< pool code.
if (pool->head) {
pool->head->prev = this;
}
-
+
this->next = pool->head;
this->prev = NULL;
pool->head = this;
{
fr_connection_t *this;
void *conn;
-
+
rad_assert(pool != NULL);
/*
if ((pool->last_failed == now) || pool->spawning) {
int complain = false;
-
+
if (pool->last_throttled != now) {
complain = true;
-
+
pool->last_throttled = now;
}
pthread_mutex_unlock(&pool->mutex);
-
+
if (complain) {
if (pool->spawning) {
ERROR("%s: Cannot open new connection, "
pool->log_prefix);
}
}
-
+
return NULL;
}
pthread_mutex_unlock(&pool->mutex);
INFO("%s: Opening additional connection (%" PRIu64 ")", pool->log_prefix, pool->count);
-
+
this = rad_malloc(sizeof(*this));
memset(this, 0, sizeof(*this));
conn = pool->create(pool->ctx);
if (!conn) {
ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, pool->count);
-
+
pool->last_failed = now;
free(this);
pool->spawning = false; /* atomic, so no lock is needed */
return NULL;
}
-
+
this->created = now;
- this->connection = conn;
+ this->connection = conn;
/*
* And lock the mutex again while we link the new
pthread_mutex_unlock(&pool->mutex);
return 0;
}
-
+
INFO("%s: Opening connection successful (%" PRIu64 ")", pool->log_prefix, pool->count);
}
if (this->in_use) {
rad_assert(this->in_use == true);
this->in_use = false;
-
+
rad_assert(pool->active > 0);
pool->active--;
}
for (this = pool->head; this != NULL; this = next) {
next = this->next;
-
+
INFO("%s: Closing connection (%" PRIu64 ")", pool->log_prefix, this->number);
-
+
fr_connection_close(pool, this);
}
rad_assert(pool->head == NULL);
rad_assert(pool->tail == NULL);
rad_assert(pool->num == 0);
-
+
free(pool->log_prefix);
free(pool);
}
* @param[in] a Callback to check the status of connections.
* @param[in] d Callback to delete connections.
* @param[in] prefix to prepend to all log message, if NULL will create prefix
- * from parent conf section names.
+ * from parent conf section names.
* @return A new connection pool or NULL on error.
*/
fr_connection_pool_t *fr_connection_pool_init(CONF_SECTION *parent,
pool->create = c;
pool->alive = a;
pool->delete = d;
-
+
pool->head = pool->tail = NULL;
#ifdef HAVE_PTHREAD_H
} else {
pool->log_prefix = strdup(prefix);
}
-
+
DEBUG("%s: Initialising connection pool", pool->log_prefix);
if (cs) {
* not to.
*/
for (i = 0; i < pool->start; i++) {
- this = fr_connection_spawn(pool, now);
+ this = fr_connection_spawn(pool, now);
if (!this) {
error:
fr_connection_pool_delete(pool);
{
rad_assert(pool != NULL);
rad_assert(this != NULL);
-
+
/*
* Don't terminated in-use connections
*/
if ((pool->num <= pool->min) &&
(pool->last_complained < now)) {
WARN("%s: You probably need to lower \"min\"", pool->log_prefix);
-
+
pool->last_complained = now;
}
fr_connection_close(pool, this);
pool->log_prefix, this->number, (int) (now - this->last_used));
goto do_delete;
}
-
+
return 1;
}
}
rad_assert(idle != NULL);
-
+
INFO("%s: Closing connection (%" PRIu64 "): Too many free connections (%d > %d)", pool->log_prefix,
idle->number, spare, pool->spare);
fr_connection_close(pool, idle);
fr_connection_t *this;
time_t now;
int ret = 1;
-
+
if (!pool) return 1;
now = time(NULL);
complain = true;
pool->last_at_max = now;
}
-
+
pthread_mutex_unlock(&pool->mutex);
-
+
if (complain) {
ERROR("%s: No connections available and at max connection limit", pool->log_prefix);
}
-
+
return NULL;
}
this->in_use = true;
pthread_mutex_unlock(&pool->mutex);
-
+
DEBUG("%s: Reserved connection (%" PRIu64 ")", pool->log_prefix, this->number);
-
+
return this->connection;
}
rad_assert(this->in_use == true);
this->in_use = false;
-
+
/*
* Determines whether the last used connection gets
* re-used first.
this = fr_connection_find(pool, conn);
if (!this) return NULL;
-
+
conn_number = this->number;
rad_assert(this->in_use == true);
-
+
DEBUG("%s: Reconnecting (%" PRIu64 ")", pool->log_prefix, conn_number);
-
+
new_conn = pool->create(pool->ctx);
if (!new_conn) {
time_t now = time(NULL);
-
+
if (pool->last_complained == now) {
now = 0;
} else {
pool->last_complained = now;
}
-
+
this->in_use = false;
rad_assert(pool->active > 0);
pool->active--;
-
+
fr_connection_close(pool, this);
pthread_mutex_unlock(&pool->mutex);
-
+
/*
* Can't create a new socket.
* Try grabbing a pre-existing one.
*/
new_conn = fr_connection_get(pool);
if (new_conn) return new_conn;
-
+
if (!now) return NULL;
-
+
ERROR("%s: Failed to reconnect (%" PRIu64 "), and no other connections available", pool->log_prefix,
conn_number);
-
+
return NULL;
}
-
+
pool->delete(pool->ctx, conn);
this->connection = new_conn;
pthread_mutex_unlock(&pool->mutex);
* handle this, then it's very broken.
*/
if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
-
+
RDEBUG3("Received response for request %d. Will read the next packet in %d seconds",
request->number, data->delay_time / USEC);
-
+
data->last_packet = now;
data->signal = 1;
data->state = STATE_REPLIED;
*
* t_rtt the packet has been processed successfully,
* wait for t_delay to enforce load factor.
- *
+ *
* t_rtt + t_delay wait for signal that the server is idle.
- *
+ *
*/
int detail_recv(rad_listen_t *listener)
{
case STATE_UNOPENED:
open_file:
rad_assert(listener->fd < 0);
-
+
if (!detail_open(listener)) return 0;
rad_assert(data->state == STATE_UNLOCKED);
{
struct stat buf;
-
+
if (fstat(listener->fd, &buf) < 0) {
ERROR("Failed to stat "
"detail file %s: %s",
data->filename,
strerror(errno));
-
+
goto cleanup;
}
if (((off_t) ftell(data->fp)) == buf.st_size) {
case STATE_NO_REPLY:
data->state = STATE_QUEUED;
goto alloc_packet;
-
+
/*
* We have a reply. Clean up the old
* request, and go read another one.
data->state = STATE_HEADER;
goto do_header;
}
-
+
paircursor(&cursor, &data->vps);
/*
data->client_ip.af = AF_INET;
if (ip_hton(value, AF_INET, &data->client_ip) < 0) {
ERROR("Failed parsing Client-IP-Address");
-
+
pairfree(&data->vps);
goto cleanup;
}
*/
alloc_packet:
data->tries++;
-
+
/*
* The writer doesn't check that the record was
* completely written. If the disk is full, this can
*/
if (data->state != STATE_QUEUED) {
ERROR("Truncated record: treating it as EOF for detail file %s", data->filename_work);
- goto cleanup;
+ goto cleanup;
}
/*
}
data->signal = 0;
-
+
DEBUG2("Detail listener %s state %s signalled %d waiting %d.%06d sec",
data->filename, fr_int2str(state_names, data->state, "?"),
data->signal,
}
if (data->max_outstanding == 0) data->max_outstanding = 1;
-
+
/*
* If the filename is a glob, use "detail.work" as the
* work file name.
}
strlcat(buffer, "detail.work",
sizeof(buffer) - strlen(buffer));
-
+
} else {
snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
}
/** Expand the RHS of a template
*
- * @note Length of expanded string can be found with talloc_array_length(*out) - 1
+ * @note Length of expanded string can be found with talloc_array_length(*out) - 1
*
* @param out where to write a pointer to the newly allocated buffer.
* @param request Current request.
{
VALUE_PAIR *vp;
*out = NULL;
-
+
rad_assert(vpt->type != VPT_TYPE_LIST);
switch (vpt->type) {
EVAL_DEBUG("FAIL %d", __LINE__);
return -1;
}
-
+
compare = regexec(®, lhs, REQUEST_MAX_REGEX + 1, rxmatch, 0);
regfree(®);
*/
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
*/
pairfree(&vp);
return NULL;
}
-
+
return vp;
}
* TRUE || ... = TRUE
*/
if (rcode && (c->next_op == COND_OR)) return true;
-
+
c = c->next;
}
for (i = 0; i < tailto; i++) {
if (!to_list[i]) continue;
-
+
vp = to_list[i];
RDEBUG4("::: to[%d] = %s", i, vp->da->name);
}
elapsed->tv_usec += end->tv_usec;
elapsed->tv_usec -= start->tv_usec;
-
+
if (elapsed->tv_usec >= USEC) {
elapsed->tv_usec -= USEC;
elapsed->tv_sec++;
char argv_buf[4096];
#define MAX_ENVP 1024
char *envp[MAX_ENVP];
-
+
argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv, true, sizeof(argv_buf), argv_buf);
if (argc <= 0) {
RDEBUG("invalid command line '%s'.", cmd);
}
}
}
-
+
envp[0] = NULL;
if (input_pairs) {
devnull = open("/dev/null", O_RDWR);
if (devnull < 0) {
RDEBUG("Failed opening /dev/null: %s\n", strerror(errno));
-
- /*
+
+ /*
* Where the status code is interpreted as a module rcode
* one is subtracted from it, to allow 0 to equal success
*
* 2 is RLM_MODULE_FAIL + 1
*/
- exit(2);
+ exit(2);
}
/*
*/
execve(argv[0], argv, envp);
printf("Failed to execute \"%s\": %s", argv[0], strerror(errno)); /* fork output will be captured */
-
- /*
+
+ /*
* Where the status code is interpreted as a module rcode
* one is subtracted from it, to allow 0 to equal success
*
RDEBUG("Wait is not supported");
return -1;
}
-
+
{
/*
* The _spawn and _exec families of functions are
* to close your program (_P_OVERLAY), to wait
* until the new process is finished (_P_WAIT) or
* for the two to run concurrently (_P_NOWAIT).
-
+
* _spawn and _exec are useful for instances in
* which you have simple requirements for running
* the program, don't want the overhead of the
*/
do {
int flags;
-
+
if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
nonblock = false;
break;
}
-
+
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) < 0) {
nonblock = false;
gettimeofday(&when, NULL);
tv_sub(&when, &start, &elapsed);
if (elapsed.tv_sec >= timeout) goto too_long;
-
+
when.tv_sec = timeout;
when.tv_usec = 0;
tv_sub(&when, &elapsed, &wake);
* @param[in] user_msg buffer to append plaintext (non valuepair) output.
* @param[in] msg_len length of user_msg buffer.
* @param[in] input_pairs list of value pairs - these will be available in the environment of the child.
- * @param[out] output_pairs list of value pairs - child stdout will be parsed and added into this list
+ * @param[out] output_pairs list of value pairs - child stdout will be parsed and added into this list
* of value pairs.
* @return 0 if exec_wait==0, exit code if exec_wait!=0, -1 on error.
*/
if (!exec_wait) {
return 0;
}
-
+
#ifndef __MINGW32__
done = radius_readfrom_program(request, from_child, pid, 10, answer, sizeof(answer));
if (done < 0) {
if (userparse(request, answer, &vp) == T_OP_INVALID) {
REDEBUG("Unparsable reply from '%s'", cmd);
-
+
return -1;
} else {
/*
child_pid = rad_waitpid(pid, &status);
if (child_pid == 0) {
REDEBUG("Timeout waiting for child");
-
+
return -2;
}
if (child_pid == pid) {
if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
-
+
RDEBUG("Program returned code (%d): %s", status, answer);
return status;
char newfile[8192];
DEBUG2("reading pairlist file %s", file);
-
+
/*
* Open the file. The error message should be a little
* more useful...
}
t = NULL;
-
+
if (pairlist_read(ctx, newfile, &t, 0) != 0) {
pairlist_free(&pl);
ERROR("%s[%d]: Could not open included file %s: %s",
*out = '\0';
return 0;
}
-
+
strlcpy(out, value, outlen);
return strlen(out);
client = client_find(clients, ipaddr,sock->proto);
if (!client) {
char name[256], buffer[128];
-
+
#ifdef WITH_DYNAMIC_CLIENTS
unknown: /* used only for dynamic clients */
#endif
now = time(NULL);
if (last_printed == now) return NULL;
-
+
last_printed = now;
}
if (!client->client_server && !client->dynamic) return client;
now = time(NULL);
-
+
/*
* It's a dynamically generated client, check it.
*/
* Lives forever. Return it.
*/
if (client->lifetime == 0) return client;
-
+
/*
* Rate-limit the deletion of known clients.
* This makes them last a little longer, but
* It's not dead yet. Return it.
*/
if ((client->created + client->lifetime) > now) return client;
-
+
/*
* This really puts them onto a queue for later
* deletion.
sock->packet->dst_ipaddr = sock->my_ipaddr;
sock->packet->dst_port = sock->my_port;
}
-
+
/*
* Grab the packet currently being processed.
*/
listen_socket_t *sock;
fr_ipaddr_t src_ipaddr;
RADCLIENT *client = NULL;
-
+
salen = sizeof(src);
DEBUG2(" ... new connection request on TCP socket.");
-
+
newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
if (newfd < 0) {
/*
{
this->recv = dual_tcp_recv;
-
+
#ifdef WITH_TLS
if (this->tls) {
this->recv = dual_tls_recv;
ip_ntoh(&sock->my_ipaddr, buffer, bufsize);
}
FORWARD;
-
+
ADDSTRING(", ");
snprintf(buffer, bufsize, "%d", sock->my_port);
FORWARD;
ip_ntoh(&sock->other_ipaddr, buffer, bufsize);
}
FORWARD;
-
+
ADDSTRING(", ");
snprintf(buffer, bufsize, "%d", sock->other_port);
FORWARD;
#endif /* WITH_TCP */
ADDSTRING(" address ");
-
+
if ((sock->my_ipaddr.af == AF_INET) &&
(sock->my_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {
strlcpy(buffer, "*", bufsize);
}
#endif
- }
+ }
#else /* WITH_TLS */
/*
* Built without TLS. Disallow it.
if (check_config) {
if (home_server_find(&sock->my_ipaddr, sock->my_port, sock->proto)) {
char buffer[128];
-
+
EDEBUG("We have been asked to listen on %s port %d, which is also listed as a home server. This can create a proxy loop.",
ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)),
sock->my_port);
"Broadcast can only be set for DHCP listeners. Delete this line from the configuration file.");
return -1;
}
-
+
rad_assert(cp != NULL);
value = cf_pair_value(cp);
if (!value) {
*/
if (this->type == RAD_LISTEN_PROXY) return 0;
#endif
-
+
/*
* The more specific configurations are preferred to more
* generic ones.
request->reply->src_ipaddr = request->client->src_ipaddr;
}
#endif
-
+
if (rad_send(request->reply, request->packet,
request->client->secret) < 0) {
RERROR("Failed sending reply: %s",
request->reply->src_ipaddr = request->client->src_ipaddr;
}
#endif
-
+
if (rad_send(request->reply, request->packet,
request->client->secret) < 0) {
RERROR("Failed sending reply: %s",
vp = pairfind(request->config_items, PW_HOME_SERVER_POOL, 0, TAG_ANY);
if (!vp) return 0;
-
+
if (!home_pool_byname(vp->vp_strvalue, HOME_TYPE_COA)) {
REDEBUG2("Cannot proxy to unknown pool %s",
vp->vp_strvalue);
default:
request->reply->code = nak;
break;
-
+
case RLM_MODULE_HANDLED:
return rcode;
-
+
case RLM_MODULE_NOOP:
case RLM_MODULE_NOTFOUND:
case RLM_MODULE_OK:
*/
request->reply->code = nak;
break;
-
+
case RLM_MODULE_HANDLED:
return rcode;
-
+
case RLM_MODULE_NOOP:
case RLM_MODULE_NOTFOUND:
case RLM_MODULE_OK:
#else
char const *proto_for_port = "udp";
int sock_type = SOCK_DGRAM;
-
+
if (sock->proto == IPPROTO_TCP) {
#ifdef WITH_VMPS
if (this->type == RAD_LISTEN_VQP) {
#endif
proto_for_port = "tcp";
- sock_type = SOCK_STREAM;
+ sock_type = SOCK_STREAM;
}
#endif
}
}
#endif
-
+
/*
* Bind to a device BEFORE touching IP addresses.
*/
close(this->fd);
return -1;
}
-
+
#ifdef HAVE_STRUCT_SOCKADDR_IN6
if (sock->my_ipaddr.af == AF_INET6) {
/*
* design a little simpler.
*/
#ifdef IPV6_V6ONLY
-
+
if (IN6_IS_ADDR_UNSPECIFIED(&sock->my_ipaddr.ipaddr.ip6addr)) {
int on = 1;
-
+
if (setsockopt(this->fd, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&on, sizeof(on)) < 0) {
ERROR("Failed setting socket to IPv6 "
- "only: %s", strerror(errno));
-
+ "only: %s", strerror(errno));
+
close(this->fd);
return -1;
}
if (sock->my_ipaddr.af == AF_INET) {
UNUSED int flag;
-
+
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
/*
* Disable PMTU discovery. On Linux, this
&flag, sizeof(flag)) < 0) {
ERROR("Failed disabling PMTU discovery: %s",
strerror(errno));
-
+
close(this->fd);
- return -1;
+ return -1;
}
#endif
if (setsockopt(this->fd, IPPROTO_IP, IP_DONTFRAG,
&flag, sizeof(flag)) < 0) {
ERROR("Failed setting don't fragment flag: %s",
- strerror(errno));
-
+ strerror(errno));
+
close(this->fd);
return -1;
}
#ifdef SO_BROADCAST
if (sock->broadcast) {
int on = 1;
-
+
if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
ERROR("Can't set broadcast option: %s",
strerror(errno));
if (rcode < 0) {
char buffer[256];
close(this->fd);
-
+
this->print(this, buffer, sizeof(buffer));
ERROR("Failed binding to %s: %s\n",
buffer, strerror(errno));
return -1;
}
-
+
/*
* FreeBSD jail issues. We bind to 0.0.0.0, but the
* kernel instead binds us to a 1.2.3.4. If this
{
struct sockaddr_storage src;
socklen_t sizeof_src = sizeof(src);
-
+
memset(&src, 0, sizeof_src);
if (getsockname(this->fd, (struct sockaddr *) &src,
&sizeof_src) < 0) {
strerror(errno));
return -1;
}
-
+
if (!fr_sockaddr2ipaddr(&src, sizeof_src,
&sock->my_ipaddr, &sock->my_port)) {
ERROR("Socket has unsupported address family");
if (sock->my_port == 0) {
struct sockaddr_storage src;
socklen_t sizeof_src = sizeof(src);
-
+
memset(&src, 0, sizeof_src);
if (getsockname(this->fd, (struct sockaddr *) &src,
&sizeof_src) < 0) {
listen_free(&this);
return NULL;
}
-
+
if (!fr_sockaddr2ipaddr(&src, sizeof_src,
&sock->my_ipaddr, &sock->my_port)) {
ERROR("Socket has unsupported address family");
(ipaddr->ipaddr.ip4addr.s_addr == htonl(INADDR_LOOPBACK))) {
return 1;
}
-
+
#ifdef HAVE_STRUCT_SOCKADDR_IN6
if ((ipaddr->af == AF_INET6) &&
(IN6_IS_ADDR_LINKLOCAL(&ipaddr->ipaddr.ip6addr))) {
cs = cf_subsection_find_next(config, cs, "server")) {
CONF_SECTION *subcs;
char const *name2 = cf_section_name2(cs);
-
+
for (subcs = cf_subsection_find_next(cs, NULL, "listen");
subcs != NULL;
subcs = cf_subsection_find_next(cs, subcs, "listen")) {
listen_free(head);
return -1;
}
-
+
*last = this;
last = &(this->next);
} /* loop over "listen" directives in virtual servers */
memset(&home, 0, sizeof(home));
/*
- *
+ *
*/
home.proto = IPPROTO_UDP;
home.src_ipaddr = server_ipaddr;
&& (this->type != RAD_LISTEN_ACCT)
#endif
) continue;
-
+
sock = this->data;
if ((sock->my_port == port) &&
sizeof(buffer) - len) ;
if (len == 0) colourise = false;
}
-
+
/*
* Mark the point where we treat the buffer as unsanitized.
*/
timeval = time(NULL);
CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
-
+
len = strlen(buffer);
len += strlcpy(buffer + len,
if (len < sizeof(buffer)) {
len += vsnprintf(buffer + len, sizeof(buffer) - len - 1, fmt, ap);
}
-
+
/*
* Filter out characters not in Latin-1.
*/
if (colourise && (len < sizeof(buffer))) {
len += strlcpy(buffer + len, VTC_RESET, sizeof(buffer) - len);
}
-
+
if (len < (sizeof(buffer) - 2)) {
buffer[len] = '\n';
buffer[len + 1] = '\0';
buffer[sizeof(buffer) - 2] = '\n';
buffer[sizeof(buffer) - 1] = '\0';
}
-
+
switch (default_log.dest) {
#ifdef HAVE_SYSLOG_H
* This is SLOW! Doing it for every log message
* in every request is NOT recommended!
*/
-
+
/* FIXME: escape chars! */
if (radius_xlat(buffer, sizeof(buffer), request, filename, NULL, NULL) < 0) {
va_end(ap);
return;
}
request->radlog = rl;
-
+
p = strrchr(buffer, FR_DIR_SEP);
if (p) {
*p = '\0';
} else
#endif
CTIME_R(&timeval, buffer, sizeof(buffer) - 1);
-
+
len = strlen(buffer);
p = strrchr(buffer, '\n');
if (p) {
p[0] = ' ';
p[1] = '\0';
}
-
+
len += strlcpy(buffer + len,
fr_int2str(levels, type, ": "),
sizeof(buffer) - len);
-
+
if (len >= sizeof(buffer)) goto finish;
}
-
+
if (request && request->module[0]) {
len = snprintf(buffer + len, sizeof(buffer) - len, "%s : ",
request->module);
-
+
if (len >= sizeof(buffer)) goto finish;
}
-
+
vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
-
+
finish:
switch (type) {
case L_DBG_WARN:
return;
}
-
+
if (!ctx) {
talloc_report_full(NULL, fd);
} else {
do {
INFO("Context level %i", i++);
-
+
talloc_report_full(ctx, fd);
} while ((ctx = talloc_parent(ctx)) && (talloc_get_name(ctx) != null_ctx)); /* Stop before we hit NULL ctx */
}
-
+
fclose(fd);
}
CONF_PAIR *cp;
CONF_ITEM *ci;
char buffer[1024];
-
+
/*
* Expand it safely.
*/
*out = '\0';
return 0;
}
-
+
strlcpy(out, value, outlen);
return strlen(out);
no_core.rlim_cur = 0;
no_core.rlim_max = 0;
-
+
if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
ERROR("Failed disabling core dumps: %s",
strerror(errno));
void fr_suid_up(void)
{
uid_t ruid, euid, suid;
-
+
if (getresuid(&ruid, &euid, &suid) < 0) {
ERROR("Failed getting saved UID's");
_exit(1);
progname, uid_name, strerror(errno));
_exit(1);
}
-
+
if (geteuid() != server_uid) {
fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n",
progname);
/* Set UID. */
if (uid_name) {
struct passwd *pw;
-
+
pw = getpwnam(uid_name);
if (pw == NULL) {
fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
return 0;
}
-
+
if (chown(mainconfig.log_file, server_uid, server_gid) < 0) {
fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
progname, mainconfig.log_file, strerror(errno));
return 0;
}
}
- }
+ }
if (uid_name) {
doing_setuid = true;
cf_file_free(cs);
return -1;
}
-
+
if (!radlog_dest) {
fprintf(stderr, "radiusd: Error: No log destination specified.\n");
cf_file_free(cs);
return -1;
}
-
+
default_log.dest = fr_str2int(log_str2dst, radlog_dest,
L_DST_NUM_DEST);
if (default_log.dest == L_DST_NUM_DEST) {
cf_file_free(cs);
return -1;
}
-
+
if (default_log.dest == L_DST_SYSLOG) {
/*
* Make sure syslog_facility isn't NULL
}
p = NULL;
}
-
+
if (mainconfig.max_request_time == 0) mainconfig.max_request_time = 100;
if (mainconfig.reject_delay > 5) mainconfig.reject_delay = 5;
if (mainconfig.cleanup_delay > 5) mainconfig.cleanup_delay =5;
void hup_logfile(void)
{
int fd, old_fd;
-
+
if (default_log.dest != L_DST_FILES) return;
fd = open(mainconfig.log_file,
rcode = radius_map2request(request, map, "update", radius_map2vp, NULL);
if (rcode < 0) {
myresult = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
-
+
MOD_LOG_CLOSE_BRACE();
goto handle_priority;
}
goto handle_result;
}
#endif
-
+
if (child->type == MOD_REFERENCE) {
modref *mr = mod_callabletoref(child);
char const *server = request->server;
myresult = RLM_MODULE_NOOP;
goto handle_priority;
}
-
+
request->server = mr->ref_name;
RDEBUG("server %s { # nested call", mr->ref_name);
myresult = indexed_modcall(component, 0, request);
radius_exec_program(request, mx->xlat_name, false, true,
NULL, 0, request->packet->vps, NULL);
}
-
+
goto skip; /* don't change anything on the stack */
}
g = rad_malloc(sizeof(*g)); /* never fails */
memset(g, 0, sizeof(*g));
csingle = mod_grouptocallable(g);
-
+
csingle->parent = parent;
csingle->next = NULL;
}
csingle->type = MOD_UPDATE;
csingle->method = component;
-
+
g->grouptype = GROUPTYPE_SIMPLE;
g->children = NULL;
g->cs = cs;
memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
sizeof(csingle->actions));
-
+
mr->ref_name = strdup(server);
mr->ref_cs = cs;
memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
sizeof(csingle->actions));
-
+
mx->xlat_name = strdup(fmt);
if (fmt[0] != '%') {
char *p;
if (!subcs &&
(cs = cf_section_find("policy")) != NULL) {
char buffer[256];
-
+
snprintf(buffer, sizeof(buffer), "%s.%s",
modrefname, comp2str[component]);
if (!this) do {
int i;
char *p;
-
+
/*
* Maybe it's module.method
*/
strlcpy(buffer, modrefname, sizeof(buffer));
buffer[p - modrefname] = '\0';
component = i;
-
+
this = find_module_instance(modules, buffer, 1);
if (this &&
!this->entry->module->methods[i]) {
cf_log_err(ci, "No such server \"%s\".", buffer);
return NULL;
}
-
+
return do_compile_modserver(parent, component, ci,
modrefname, cs, buffer);
}
*/
if (cf_item_is_section(ci)) {
CONF_ITEM *csi;
-
+
cs = cf_itemtosection(ci);
for (csi=cf_item_find_next(cs, NULL);
csi != NULL;
* Prefer loading our libraries by absolute path.
*/
snprintf(buffer, sizeof(buffer), "%s/%s%s", radlib_dir, name, LT_SHREXT);
-
+
check_lib_access(buffer);
-
+
handle = dlopen(buffer, flags);
if (handle) return handle;
if (!name) return 0;
hash = fr_hash_string(name);
-
+
return hash & (VIRTUAL_SERVER_HASH_SIZE - 1);
}
{
int i;
virtual_server_t **last;
-
+
for (i = 0; i < VIRTUAL_SERVER_HASH_SIZE; i++) {
virtual_server_t *server, *next;
static int module_conf_parse(module_instance_t *node, void **handle)
{
*handle = NULL;
-
+
/*
* If there is supposed to be instance data, allocate it now.
* Also parse the configuration data, if required.
(cf_section_parse(node->cs, *handle, node->entry->module->config) < 0)) {
cf_log_err_cs(node->cs,"Invalid configuration for module \"%s\"", node->name);
talloc_free(*handle);
-
+
return -1;
}
-
+
/*
* Set the destructor.
*/
talloc_set_destructor((void *) *handle, node->entry->module->detach);
}
}
-
+
return 0;
}
if (instname[0] == '-') {
instname++;
}
-
+
/*
* Module instances are declared in the modules{} block
* and referenced later by their name, which is the
* If there's already a module instance, return it.
*/
strlcpy(myNode.name, instname, sizeof(myNode.name));
-
+
node = rbtree_finddata(instance_tree, &myNode);
if (node) {
return node;
if (!do_link) {
return NULL;
}
-
+
name1 = cf_section_name1(cs);
/*
if (cp) {
value = cf_pair_value(cp);
}
-
+
if (value && (strcmp(value, "yes") == 0)) goto print_inst;
cf_log_module(cs, "Skipping instantiation of %s", instname);
cf_log_module(cs, "Instantiating module \"%s\" from file %s", instname,
cf_section_filename(cs));
}
-
+
strlcpy(node->name, instname, sizeof(node->name));
/*
*/
if (module_conf_parse(node, &node->insthandle) < 0) {
talloc_free(node);
-
+
return NULL;
}
((node->entry->module->instantiate)(cs, node->insthandle) < 0)) {
cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", node->name);
talloc_free(node);
-
+
return NULL;
}
int comp, int idx)
{
indexed_modcallable myc;
-
+
myc.comp = comp;
myc.idx = idx;
section_type_value[comp].typename);
}
}
-
+
if (server->subcs[comp]) {
if (idx == 0) {
RDEBUG("# Executing section %s from file %s",
if (next_ci && cf_item_is_section(next_ci)) {
char const *next_name;
CONF_SECTION *next_cs;
-
+
next_cs = cf_itemtosection(next_ci);
next_name = cf_section_name1(next_cs);
if ((strcmp(next_name, "else") == 0) ||
}
if (!cf_item_is_section(modref)) continue;
-
+
subsubcs = cf_itemtosection(modref);
name1 = cf_section_name1(subsubcs);
subcs = cf_section_sub_find(cs,
section_type_value[comp].section);
if (!subcs) continue;
-
+
if (cf_item_find_next(subcs, NULL) == NULL) continue;
-
+
cf_log_module(cs, "Loading %s {...}",
section_type_value[comp].section);
subcs = cf_section_sub_find(cs, "vmps");
if (subcs) {
- cf_log_module(cs, "Checking vmps {...} for more modules to load");
+ cf_log_module(cs, "Checking vmps {...} for more modules to load");
if (load_component_section(subcs, components,
RLM_COMPONENT_POST_AUTH) < 0) {
goto error;
RLM_COMPONENT_POST_AUTH, 0);
if (c) server->mc[RLM_COMPONENT_POST_AUTH] = c->modulelist;
found = 1;
-
+
subcs = cf_subsection_find_next(cs, subcs, "dhcp");
}
#endif
if (module_conf_parse(node, &insthandle) < 0) {
cf_log_err_cs(cs, "HUP failed for module \"%s\" (parsing config failed). "
"Using old configuration", node->name);
-
+
return 0;
}
-
+
if ((node->entry->module->instantiate)(cs, insthandle) < 0) {
cf_log_err_cs(cs, "HUP failed for module \"%s\". Using old configuration.", node->name);
talloc_free(insthandle);
-
+
return 0;
}
node->mh = mh;
node->insthandle = insthandle;
-
+
/*
* FIXME: Set a timeout to come back in 60s, so that
* we can pro-actively clean up the old instances.
p++;
continue;
}
-
+
*(q++) = *(p++);
}
ip = &packet->dst_ipaddr;
port = packet->dst_port;
}
-
+
/*
* Client-specific debugging re-prints the input
* packet into the client log.
}
for (vp = paircursor(&cursor, &packet->vps);
- vp;
+ vp;
vp = pairnext(&cursor)) {
vp_prints(buffer, sizeof(buffer), vp);
RDEBUG("\t%s", buffer);
*/
case FR_ACTION_TIMER:
break;
-
+
#ifdef WITH_PROXY
/*
* Child is still alive, and we're receiving more
request_common(request, action);
break;
#endif
-
+
default:
RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
break;
if (request->in_request_hash) {
fr_packet_list_yank(pl, request->packet);
request->in_request_hash = false;
-
+
/*
* @todo: do final states for TCP sockets, too?
*/
request_stats_final(request);
-
+
#ifdef WITH_TCP
request->listener->count--;
#endif
}
-
+
#ifdef WITH_PROXY
/*
* Wait for the proxy ID to expire. This allows us to
rad_assert("Internal sanity check failed");
exit(2);
}
-
+
gettimeofday(&now, NULL);
#ifdef WITH_PROXY
wait_some_more:
#endif
{
rad_assert(request->listener != NULL);
-
+
/*
* The socket was closed. Tell the request that
* there is no point in continuing.
(request->master_state != REQUEST_STOP_PROCESSING)) {
when = request->packet->timestamp;
when.tv_sec += request->root->max_request_time;
-
+
/*
* Taking too long: tell it to die.
*/
* delay time.
*/
request->reply->timestamp = now;
-
+
RDEBUG2("Sending delayed reject");
DEBUG_PACKET(request, request->reply, 1);
request->process = request_cleanup_delay;
#endif
if (request->packet->vps == NULL) {
rcode = request->listener->decode(request->listener, request);
-
+
#ifdef WITH_UNLANG
if (debug_condition) {
/*
}
}
#endif
-
+
DEBUG_PACKET(request, request->packet, 0);
} else {
rcode = 0;
}
} else if (request->reply->code == 0) {
vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
-
+
if (!vp || (vp->vp_integer != PW_AUTHENTICATION_REJECT)) {
RDEBUG2("There was no response configured: "
"rejecting request");
}
-
+
request->reply->code = PW_AUTHENTICATION_REJECT;
}
}
-
+
/*
* Copy Proxy-State from the request to the reply.
*/
pairfree(&request->packet->vps);
request->username = NULL;
request->password = NULL;
-
+
#ifdef WITH_PROXY
if (request->proxy) {
pairfree(&request->proxy->vps);
pairfree(&request->proxy_reply->vps);
}
#endif
-
+
RDEBUG2("Finished request %u.", request->number);
}
#ifdef HAVE_PTHREAD_H
request->child_pid = NO_SUCH_CHILD_PID;
-#endif
+#endif
request->child_state = REQUEST_DONE;
}
break;
case PW_ACCOUNTING_REQUEST:
FR_STATS_INC(acct, total_dup_requests);
break;
-#endif
+#endif
#ifdef WITH_COA
case PW_COA_REQUEST:
FR_STATS_INC(coa, total_dup_requests);
if (timercmp(&end, &now, <=)) {
listener->print(listener, buffer, sizeof(buffer));
DEBUG("Reached maximum lifetime on socket %s", buffer);
-
+
do_close:
-
+
listener->status = RAD_LISTEN_STATUS_CLOSED;
event_new_fd(listener);
return;
rad_listen_t *this = ctx;
RADIUS_PACKET **proxy_p = data;
REQUEST *request;
-
+
request = fr_packet2myptr(REQUEST, proxy, proxy_p);
if (request->proxy->sockfd != this->fd) return 0;
rad_listen_t *this = ctx;
RADIUS_PACKET **packet_p = data;
REQUEST *request;
-
+
request = fr_packet2myptr(REQUEST, packet, packet_p);
if (request->packet->sockfd != this->fd) return 0;
}
rad_assert(request->proxy->id >= 0);
-
+
request->proxy_listener = proxy_listener;
if (!fr_packet_list_insert(proxy_list, &request->proxy)) {
fr_packet_list_id_free(proxy_list, request->proxy);
int rcode;
int post_proxy_type = 0;
VALUE_PAIR *vp;
-
+
/*
* Delete any reply we had accumulated until now.
*/
pairfree(&request->reply->vps);
-
+
/*
* Run the packet through the post-proxy stage,
* BEFORE playing games with the attributes.
*/
vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
-
+
/*
* If we have a proxy_reply, and it was a reject, setup
* post-proxy-type Reject
vp->vp_integer = dval->value;
}
}
-
+
if (vp) {
post_proxy_type = vp->vp_integer;
-
+
RDEBUG2(" Found Post-Proxy-Type %s",
dict_valnamebyattr(PW_POST_PROXY_TYPE, 0,
post_proxy_type));
}
-
+
if (request->home_pool && request->home_pool->virtual_server) {
char const *old_server = request->server;
-
+
request->server = request->home_pool->virtual_server;
RDEBUG2(" server %s {", request->server);
rcode = process_post_proxy(post_proxy_type, request);
* attributes from us and remote server.
*/
pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
-
+
/*
* Add the attributes left in the proxy
* reply to the reply list.
*/
pairfilter(request->reply, &request->reply->vps,
&request->proxy_reply->vps, 0, 0, TAG_ANY);
-
+
/*
* Free proxy request pairs.
*/
pairfree(&request->proxy->vps);
}
-
+
switch (rcode) {
default: /* Don't do anything */
break;
case RLM_MODULE_FAIL:
return 0;
-
+
case RLM_MODULE_HANDLED:
return 0;
}
#endif
request->process(request, FR_ACTION_PROXY_REPLY);
-
+
return 1;
}
if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
"Fail-Authentication");
-
+
} else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
"Fail-Accounting");
request_cleanup_delay_init(request, NULL);
return 0;
}
-
+
if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail");
-
+
if (!dval) {
DEBUG("No Post-Proxy-Type Fail: ignoring");
pairdelete(&request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
request_cleanup_delay_init(request, NULL);
return 0;
}
-
+
vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
if (!vp) vp = radius_paircreate(request, &request->config_items,
PW_POST_PROXY_TYPE, 0);
*/
if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
pool = realm->auth_pool;
-
+
#ifdef WITH_ACCOUNTING
} else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
pool = realm->acct_pool;
case PW_AUTHENTICATION_REQUEST:
pool_type = HOME_TYPE_AUTH;
break;
-
+
#ifdef WITH_ACCOUNTING
case PW_ACCOUNTING_REQUEST:
pool_type = HOME_TYPE_ACCT;
pool = home_pool_byname(vp->vp_strvalue, pool_type);
}
-
+
if (!pool) {
RWDEBUG2("Cancelling proxy as no home pool exists");
return 0;
if (request->home_pool->virtual_server) {
char const *old_server = request->server;
-
+
request->server = request->home_pool->virtual_server;
RDEBUG2(" server %s {", request->server);
rcode = process_pre_proxy(pre_proxy_type, request);
#endif
rad_assert(old_home != NULL);
-
+
/*
* Find a live home server for the request.
*/
if (!setup_post_proxy_fail(request)) {
return 0;
}
-
+
request_queue_or_run(request, proxy_running);
return 0;
}
PW_ACCT_DELAY_TIME, 0);
if (vp) {
struct timeval now;
-
+
gettimeofday(&now, NULL);
vp->vp_integer += now.tv_sec - request->proxy_retransmit.tv_sec;
}
* work.
*/
if (home->state == HOME_STATE_ALIVE) break;
-
+
/*
* We haven't received enough ping responses to mark it
* "alive". Wait a bit.
home->num_sent_pings = 0;
home->num_received_pings = 0;
gettimeofday(&home->revive_time, NULL);
-
+
fr_event_delete(el, &home->ev);
RPROXY("Marking home server %s port %d alive",
} else {
#ifdef WITH_ACCOUNTING
request->proxy->code = PW_ACCOUNTING_REQUEST;
-
+
pairmake(request->proxy, &request->proxy->vps,
"User-Name", home->ping_user_name, T_OP_SET);
pairmake(request->proxy, &request->proxy->vps,
home->zombie_period_start.tv_sec = home->last_packet_sent;
home->zombie_period_start.tv_usec = 0;
}
-
+
fr_event_delete(el, &home->ev);
home->num_sent_pings = 0;
home->num_received_pings = 0;
-
+
PROXY( "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
buffer, sizeof(buffer)),
} else if ((vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL) {
ipaddr.af = AF_INET6;
ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
-
+
} else if ((vp = pairfind(coa->proxy->vps, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) {
coa->home_pool = home_pool_byname(vp->vp_strvalue,
HOME_TYPE_COA);
case PW_DISCONNECT_REQUEST:
coa->proxy->code = vp->vp_integer;
break;
-
+
default:
DEBUG("Cannot set CoA Packet-Type to code %d",
vp->vp_integer);
if (coa->home_pool && coa->home_pool->virtual_server) {
char const *old_server = coa->server;
-
+
coa->server = coa->home_pool->virtual_server;
RDEBUG2(" server %s {", coa->server);
rcode = process_pre_proxy(pre_proxy_type, coa);
delay -= delay / 10;
delay += request->delay;
request->delay = delay;
-
+
when = request->proxy->timestamp;
tv_add(&when, delay);
if (!setup_post_proxy_fail(request)) {
return;
}
-
+
request_queue_or_run(request, proxy_running);
return;
}
case FR_ACTION_TIMER:
request_coa_timer(request);
break;
-
+
case FR_ACTION_PROXY_REPLY:
request_common(request, action);
break;
case FR_ACTION_TIMER:
request_coa_timer(request);
break;
-
+
case FR_ACTION_PROXY_REPLY:
rad_assert(request->parent == NULL);
#ifdef HAVE_PTHREAD_H
case FR_ACTION_RUN:
request_running(request, action);
break;
-
+
default:
RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
break;
listener->print(listener, buffer, sizeof(buffer));
ERROR("FATAL: Asked to read from closed socket: %s",
buffer);
-
+
rad_panic("Socket was closed on us!");
_exit(1);
}
-
+
listener->recv(listener);
}
if (sock->home) {
sock->home->limit.num_connections++;
-
+
#ifdef HAVE_PTHREAD_H
/*
* If necessary, add it to the list of
}
}
}
-#endif
+#endif
#ifdef WITH_DETAIL
/*
*/
if (this->type == RAD_LISTEN_DETAIL) {
this->status = RAD_LISTEN_STATUS_KNOWN;
-
+
/*
* Set up the first poll interval.
*/
exit(1);
}
FD_MUTEX_UNLOCK(&fd_mutex);
-
+
this->status = RAD_LISTEN_STATUS_KNOWN;
return 1;
}
this->status = RAD_LISTEN_STATUS_FINISH;
goto finish;
}
- }
+ }
#ifdef WITH_PROXY
else {
int count;
*/
gettimeofday(&when, NULL);
when.tv_sec += 30;
-
+
if (!fr_event_insert(el,
(fr_event_callback_t) event_new_fd,
this, &when, &sock->ev)) {
rad_panic("Failed to insert event");
}
-
+
return 1;
}
*/
this->status = RAD_LISTEN_STATUS_FINISH;
}
-
+
finish:
if (this->status == RAD_LISTEN_STATUS_FINISH) {
listen_socket_t *sock = this->data;
FD_MUTEX_LOCK(&fd_mutex);
fr_event_fd_delete(el, 0, this->fd);
FD_MUTEX_UNLOCK(&fd_mutex);
-
+
#ifdef WITH_PROXY
/*
* Remove it from the list of sockets to be used
#ifdef WITH_DETAIL
if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
rad_listen_t *this;
-
+
/*
* FIXME: O(N) loops suck.
*/
/*
* Sockets should only be added to the
* proxy_listener_list if they have limits.
- *
+ *
*/
rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
if (listen_init(cs, &head, spawn_flag) < 0) {
_exit(1);
}
-
+
mainconfig.listen = head;
/*
{
int length = 0;
char *p;
-
+
p = buffer + 1;
while (*p && (outlen > 0)) {
*endptr = p + 1;
*p = '\0';
-
+
p = buffer + 1;
while (isspace((int) *p)) p++;
-
+
length = encode_tlv(p, output, outlen);
if (length == 0) return 0;
-
+
return length;
}
int attr;
int length;
char *p;
-
+
attr = decode_attr(buffer, &p);
if (attr == 0) return 0;
int attr;
int length, total;
char *p;
-
+
attr = decode_attr(buffer, &p);
if (attr == 0) return 0;
attr += len;
if (len == 0) break;
}
-
+
pairfree(&head);
outlen = len;
goto print_hex;
while (vp) {
tail = &(vp->next);
vp = vp->next;
- }
+ }
attr += my_len;
- len -= my_len;
+ len -= my_len;
}
/*
vp = pairnext(&cursor)) {
vp_prints(p, sizeof(output) - (p - output), vp);
p += strlen(p);
-
+
if (vp->next) {strcpy(p, ", ");
p += 2;
}
}
-
+
pairfree(&head);
} else if (my_len < 0) {
strlcpy(output, fr_strerror(), sizeof(output));
if (strncmp(p, "condition ", 10) == 0) {
p += 10;
parse_condition(p, output, sizeof(output));
- continue;
+ continue;
}
if (strncmp(p, "xlat ", 5) == 0) {
p += 5;
parse_xlat(p, output, sizeof(output));
- continue;
+ continue;
}
fprintf(stderr, "Unknown input at line %d of %s\n",
vp->value.xlat = NULL;
vp->type = VT_DATA;
}
-
+
if (!vp->da->vendor) switch (vp->da->attr) {
default:
break;
p[1] = vp->length;
// talloc_free(vp->vp_octets);
vp->vp_octets = p;
-
+
da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
if (!da) {
goto oom;
}
-
+
vp->da = da;
}
-
+
break;
}
} /* loop over the VP's we read in */
* And we're done.
*/
return 1;
-
+
oom:
fprintf(stderr, "radclient: Out of memory\n");
free(radclient);
if (fp != stdin) fclose(fp);
- return 0;
+ return 0;
}
} else {
totaldeny++;
}
-
+
if (radclient->resend == resend_count) {
radclient->done = 1;
}
int force_af = AF_UNSPEC;
fr_debug_flag = 0;
-
+
talloc_set_log_stderr();
filename_tree = rbtree_create(filename_cmp, NULL, 0);
exit(EXIT_FAILURE);
}
fr_log_fp = fdopen(default_log.fd, "a");
- break;
+ break;
case 'i':
if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
}
flag |= 2;
break;
-
+
case 'P':
/* Force the PID to be written, even in -f mode */
write_pid = true;
fr_log_fp = stdout;
default_log.dest = L_DST_STDOUT;
default_log.fd = STDOUT_FILENO;
-
+
version();
exit(EXIT_SUCCESS);
case 'X':
} else {
setlinebuf(stdout); /* unbuffered output */
}
-
+
/*
* Now we have logging check that the OpenSSL
*/
*/
if (check_config) {
DEBUG("Configuration appears to be OK.");
-
+
/* for -C -m|-M */
if (mainconfig.debug_memory) {
goto cleanup;
}
-
+
exit(EXIT_SUCCESS);
}
* about to die.
*/
signal(SIGTERM, SIG_IGN);
-
+
/*
* Send a TERM signal to all
* associated processes
#ifndef __MINGW32__
if (spawn_flag) kill(-radius_pid, SIGTERM);
#endif
-
+
/*
* We're exiting, so we can delete the PID
* file. (If it doesn't exist, we can ignore
if (dont_fork == false) {
unlink(mainconfig.pid_file);
}
-
+
radius_event_free();
cleanup:
* Detach any modules.
*/
detach_modules();
-
+
xlat_free(); /* modules may have xlat's */
/*
* Free the configuration items.
*/
free_mainconfig();
-
+
rad_const_free(radius_dir);
-
+
#ifdef WIN32
WSACleanup();
#endif
saremote.sun_family = AF_UNIX;
memcpy(saremote.sun_path, path, len + 1); /* SUN_LEN does strlen */
-
+
socklen = SUN_LEN(&saremote);
if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
#ifdef O_NONBLOCK
{
int flags;
-
+
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
fprintf(stderr, "%s: Failure getting socket flags: %s",
progname, strerror(errno));
close(sockfd);
return -1;
}
-
+
flags |= O_NONBLOCK;
if( fcntl(sockfd, F_SETFL, flags) < 0) {
fprintf(stderr, "%s: Failure setting socket flags: %s",
progname, server, strerror(errno));
exit(1);
}
-
+
return sockfd;
}
for (total = 0; total < sizeof(challenge); ) {
r = read(sockfd, challenge + total, sizeof(challenge) - total);
if (r == 0) exit(1);
-
+
if (r < 0) {
#ifdef ECONNRESET
if (errno == ECONNRESET) {
}
#endif
if (errno == EINTR) continue;
-
+
fprintf(stderr, "%s: Failed reading data: %s\n",
progname, strerror(errno));
exit(1);
FILE *inputfp = stdin;
char const *output_file = NULL;
char const *server = NULL;
-
+
char *commands[MAX_COMMANDS];
int num_commands = -1;
while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) {
char const *value;
CONF_PAIR *cp = cf_pair_find(subcs, "type");
-
+
if (!cp) continue;
value = cf_pair_value(cp);
fprintf(stderr, "%s: Socket %s is not FreeRADIUS administration socket\n", progname, file);
exit(1);
}
-
+
memcpy(&magic, buffer + 4, 4);
magic = ntohl(magic);
size = run_command(sockfd, commands[i],
buffer, sizeof(buffer));
if (size < 0) exit(1);
-
+
if (buffer[0]) {
fputs(buffer, outputfp);
fprintf(outputfp, "\n");
#else
if (!quiet) {
line = readline("radmin> ");
-
+
if (!line) break;
-
+
if (!*line) {
free(line);
continue;
}
-
+
#ifdef USE_READLINE_HISTORY
add_history(line);
#endif
progname);
exit(1);
}
-
+
*p = '\0';
/*
if ((packet->code == PW_AUTHENTICATION_REQUEST) ||
(packet->code == PW_ACCOUNTING_REQUEST)) {
rbtree_deletebydata(filter_tree, packet);
-
+
if (!rbtree_insert(filter_tree, packet)) {
oom:
fprintf(stderr, "radsniff: Out of memory\n");
rbtree_deletebydata(filter_tree, packet);
return 1;
}
-
+
/*
* Else see if a previous Access-Request
* matched. If so, also print out the
*/
reply = rad_alloc_reply(NULL, packet);
if (!reply) goto oom;
-
+
compare = 1;
if (rbtree_finddata(filter_tree, reply)) {
compare = 0;
}
-
+
rad_free(&reply);
return compare;
}
-
+
return 1;
}
}
elapsed->tv_usec += end->tv_usec;
elapsed->tv_usec -= start->tv_usec;
-
+
if (elapsed->tv_usec >= USEC) {
elapsed->tv_usec -= USEC;
elapsed->tv_sec++;
{
static int count = 1; /* Packets seen */
-
+
/*
* Define pointers for packet's attributes
*/
const struct ip_header *ip; /* The IP header */
const struct udp_header *udp; /* The UDP header */
const uint8_t *payload; /* Packet payload */
-
+
/*
* And define the size of the structures we're using
*/
int size_ethernet = sizeof(struct ethernet_header);
int size_ip = sizeof(struct ip_header);
int size_udp = sizeof(struct udp_header);
-
+
/*
* For FreeRADIUS
*/
} else {
ip = (struct ip_header const *)(data + size_ethernet);
}
-
+
udp = (struct udp_header const *)(((uint8_t const *) ip) + size_ip);
payload = (uint8_t const *)(((uint8_t const *) udp) + size_udp);
if (!rad_packet_ok(packet, 0)) {
DEBUG(log_dst, "Packet: %s\n", fr_strerror());
-
+
DEBUG(log_dst, " From %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
DEBUG(log_dst, " To: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
DEBUG(log_dst, " Type: %s\n", fr_packet_codes[packet->code]);
rad_free(&packet);
return;
}
-
+
switch (packet->code) {
case PW_COA_REQUEST:
/* we need a 16 x 0 byte vector for decrypting encrypted VSAs */
*/
INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
-
+
DEBUG1(log_dst, "\t(%d packets)", count++);
-
+
if (!start_pcap.tv_sec) {
start_pcap = header->ts;
}
INFO(log_dst, "\t+%u.%03u", (unsigned int) elapsed.tv_sec,
(unsigned int) elapsed.tv_usec / 1000);
-
+
if (fr_debug_flag > 1) {
DEBUG(log_dst, "\n");
if (packet->vps) {
pairfree(&packet->vps);
}
}
-
+
INFO(log_dst, "\n");
-
+
if (!to_stdout && (fr_debug_flag > 4)) {
rad_print_hex(packet);
}
-
+
fflush(log_dst);
check_filter:
char const *from_dev = NULL; /* Capture from device */
char const *from_file = NULL; /* Read from pcap file */
int from_stdin = 0; /* Read from stdin */
-
+
pcap_t *in = NULL; /* PCAP input handle */
-
+
int limit = -1; /* How many packets to sniff */
-
+
char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */
char *to_file = NULL; /* PCAP output file */
-
+
char *pcap_filter = NULL; /* PCAP filter string */
char *radius_filter = NULL;
int port = 1812;
-
+
struct bpf_program fp; /* Holds compiled filter */
bpf_u_int32 ip_mask = PCAP_NETMASK_UNKNOWN; /* Device Subnet mask */
bpf_u_int32 ip_addr = 0; /* Device IP */
-
+
char buffer[1024];
int opt;
FR_TOKEN parsecode;
char const *radius_dir = RADIUS_DIR;
-
+
fr_debug_flag = 2;
log_dst = stdout;
talloc_set_log_stderr();
-
+
/*
* Get options
*/
usage(64);
}
}
-
+
/* What's the point in specifying -F ?! */
if (from_stdin && from_file && to_file) {
usage(64);
}
-
+
/* Can't read from both... */
if (from_file && from_dev) {
usage(64);
}
-
+
/* Reading from file overrides stdin */
if (from_stdin && (from_file || from_dev)) {
from_stdin = 0;
}
-
+
/* Writing to file overrides stdout */
if (to_file && to_stdout) {
to_stdout = 0;
}
-
+
/*
* If were writing pcap data stdout we *really* don't want to send
* logging there as well.
snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
port, port + 1, 3799);
}
-
+
/*
* There are times when we don't need the dictionaries.
*/
fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\" (%s)\n", radius_filter, fr_strerror());
exit(64);
}
-
+
if (!filter_vps) {
fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter);
exit(64);
INFO(log_dst, "Capturing from interface \"%s\"\n", from_dev);
}
-
+
/*
* Print captures values which will be used
*/
} else {
fprintf(stderr, "radsniff: No capture devices available\n");
}
-
+
if (!in) {
fprintf(stderr, "radsniff: Failed opening input (%s)\n", errbuf);
exit(1);
fprintf(stderr, "radsniff: Failed compiling PCAP filter (%s)\n", pcap_geterr(in));
exit(1);
}
-
+
if (pcap_setfilter(in, &fp) < 0) {
fprintf(stderr, "radsniff: Failed applying PCAP filter (%s)\n", pcap_geterr(in));
exit(1);
* Enter the main capture loop...
*/
pcap_loop(in, limit, got_packet, NULL);
-
+
/*
* ...were done capturing.
*/
if (out) {
pcap_dump_close(out);
}
-
+
if (filter_tree) {
rbtree_free(filter_tree);
}
-
+
INFO(log_dst, "Done sniffing\n");
-
+
return 0;
}
int zap = 0;
raddb_dir = RADIUS_DIR;
-
+
talloc_set_log_stderr();
while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
char name[sizeof(rt.login) + 1];
if (rt.type != P_LOGIN) continue; /* hide logout sessions */
-
+
/*
* We don't show shell users if we are
* fingerd, as we have done that above.
if (!request || !request->home_server) {
RWDEBUG("No home_server associated with this request");
-
+
*out = '\0';
return 0;
}
if (!request || !request->home_pool) {
RWDEBUG("No home_pool associated with this request");
-
+
*out = '\0';
return 0;
}
}
if (!cf_section_sub_find_name2(rc->cs, "server", home->server)) {
-
+
cf_log_err_cs(cs,
"No such server %s", home->server);
goto error;
if (hs_proto) {
if (strcmp(hs_proto, "udp") == 0) {
hs_proto = NULL;
-
+
} else if (strcmp(hs_proto, "tcp") == 0) {
hs_proto = NULL;
home->proto = IPPROTO_TCP;
-
+
if (home->ping_check != HOME_PING_CHECK_NONE) {
cf_log_err_cs(cs,
"Only 'status_check = none' is allowed for home servers with 'proto = tcp'");
cf_log_err_cs(cs, "Failed parsing src_ipaddr");
goto error;
}
-
+
} else {
/*
* Source isn't specified: Source is
free(home2);
return 0;
}
-
+
if (!home->server &&
!rbtree_insert(home_servers_byaddr, home2)) {
rbtree_deletebydata(home_servers_byname, home2);
pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) *
num_home_servers));
if (!pool) return NULL; /* just for pairanoia */
-
+
memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) *
num_home_servers));
if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
server_type, &pool->fallback)) {
-
+
goto error;
}
if (cp) {
static FR_NAME_NUMBER pool_types[] = {
{ "load-balance", HOME_POOL_LOAD_BALANCE },
-
+
{ "fail-over", HOME_POOL_FAIL_OVER },
{ "fail_over", HOME_POOL_FAIL_OVER },
-
+
{ "round-robin", HOME_POOL_LOAD_BALANCE },
{ "round_robin", HOME_POOL_LOAD_BALANCE },
cp = cf_pair_find(cs, "virtual_server");
if (cp) {
- pool->virtual_server = cf_pair_value(cp);
+ pool->virtual_server = cf_pair_value(cp);
if (!pool->virtual_server) {
cf_log_err_cp(cp, "No value given for virtual_server");
goto error;
if (strcasecmp(host, "fail_over") == 0) {
cf_log_info(cs, "\tldflag = fail_over");
-
+
} else if (strcasecmp(host, "round_robin") == 0) {
ldflag = HOME_POOL_LOAD_BALANCE;
cf_log_info(cs, "\tldflag = round_robin");
-
+
} else {
cf_log_err_cs(cs, "Unknown value \"%s\" for ldflag", host);
return 0;
return 0;
}
}
-
+
cf_log_info(cs, "\tauthhost = %s", host);
if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
return 0;
}
-
+
secret = cf_pair_value(cp);
if (!secret) {
cf_log_err_cp(cp, "No value specified for secret");
return 0;
}
}
-
+
cf_log_info(cs, "\taccthost = %s", host);
if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
if (name2[0] == '~') {
int rcode;
regex_t reg;
-
+
/*
* Include substring matches.
*/
realm_regex_t *rr, **last;
rr = rad_malloc(sizeof(*rr));
-
+
last = &realms_regex;
while (*last) last = &((*last)->next); /* O(N^2)... sue me. */
if (cs) {
if (cf_section_parse(cs, rc, proxy_config) < 0) {
ERROR("Failed parsing proxy section");
-
+
free(rc);
realms_free();
return 0;
{
REALM myrealm;
REALM *realm;
-
+
if (!name) name = "NULL";
myrealm.name = name;
{
REALM myrealm;
REALM *realm;
-
+
if (!name) name = "NULL";
myrealm.name = name;
ERROR("no memory");
exit(1);
}
-
+
/*
* Copy the request, then look up name
* and plain-text password in the copy.
break;
}
/* FALL-THROUGH */
-
+
case HOME_POOL_LOAD_BALANCE:
case HOME_POOL_FAIL_OVER:
start = 0;
if (pool->in_fallback) goto update_and_return;
pool->in_fallback = true;
-
+
/*
* Run the trigger once an hour saying that
* they're all dead.
home_pool_t *home_pool_byname(char const *name, int type)
{
home_pool_t mypool;
-
+
memset(&mypool, 0, sizeof(mypool));
mypool.name = name;
mypool.server_type = type;
}
elapsed->tv_usec += end->tv_usec;
elapsed->tv_usec -= start->tv_usec;
-
+
if (elapsed->tv_usec >= USEC) {
elapsed->tv_usec -= USEC;
elapsed->tv_sec++;
*/
rad_assert(request->packet->code == PW_STATUS_SERVER);
rad_assert(request->listener->type == RAD_LISTEN_NONE);
-
+
flag = pairfind(request->packet->vps, 127, VENDORPEC_FREERADIUS, TAG_ANY);
if (!flag || (flag->vp_integer == 0)) return;
((flag->vp_integer & 0xc0) == 0)) {
request_stats_addvp(request, authvp, &radius_auth_stats);
}
-
+
#ifdef WITH_ACCOUNTING
/*
* Accounting
vp = radius_paircreate(request, &request->reply->vps,
177, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = hup_time.tv_sec;
-
+
#ifdef HAVE_PTHREAD_H
int i, array[RAD_LISTEN_MAX], pps[2];
for (i = 0; i <= 4; i++) {
vp = radius_paircreate(request, &request->reply->vps,
162 + i, VENDORPEC_FREERADIUS);
-
+
if (!vp) continue;
vp->vp_integer = array[i];
}
for (i = 0; i < 2; i++) {
vp = radius_paircreate(request, &request->reply->vps,
181 + i, VENDORPEC_FREERADIUS);
-
+
if (!vp) continue;
vp->vp_integer = pps[i];
}
ipaddr.af = AF_INET;
ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
cl = listener_find_client_list(&ipaddr, server_port->vp_integer);
-
+
/*
* Not found: don't do anything
*/
}
}
}
-
+
if (server_ip) {
pairadd(&request->reply->vps,
paircopyvp(request->reply, server_ip));
server_port = pairfind(request->packet->vps, 171, VENDORPEC_FREERADIUS, TAG_ANY);
if (!server_port) return;
-
+
ipaddr.af = AF_INET;
ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
this = listener_find_byipaddr(&ipaddr,
server_port->vp_integer,
IPPROTO_UDP);
-
+
/*
* Not found: don't do anything
*/
if (!this) return;
-
+
pairadd(&request->reply->vps,
paircopyvp(request->reply, server_ip));
pairadd(&request->reply->vps,
(request->listener->type == RAD_LISTEN_NONE))) {
request_stats_addvp(request, authvp, &this->stats);
}
-
+
#ifdef WITH_ACCOUNTING
if (((flag->vp_integer & 0x02) != 0) &&
((request->listener->type == RAD_LISTEN_ACCT) ||
server_port = pairfind(request->packet->vps, 171, VENDORPEC_FREERADIUS, TAG_ANY);
if (!server_port) return;
-
+
#ifndef NDEBUG
memset(&ipaddr, 0, sizeof(ipaddr));
#endif
* Not found: don't do anything
*/
if (!home) return;
-
+
pairadd(&request->reply->vps,
paircopyvp(request->reply, server_ip));
pairadd(&request->reply->vps,
*/
if (ema->f1 == 0) {
if (ema->window > 10000) ema->window = 10000;
-
+
ema->f1 = (2 * F_EMA_SCALE) / (ema->window + 1);
ema->f10 = (2 * F_EMA_SCALE) / ((10 * ema->window) + 1);
}
tdiff = start->tv_sec;
tdiff -= end->tv_sec;
-
+
micro = (int) tdiff;
if (micro > 40) micro = 40; /* don't overflow 32-bit ints */
micro *= USEC;
micro += start->tv_usec;
micro -= end->tv_usec;
-
+
micro *= EMA_SCALE;
if (ema->ema1 == 0) {
ema->ema10 = micro;
} else {
int diff;
-
+
diff = ema->f1 * (micro - ema->ema1);
ema->ema1 += (diff / 1000000);
-
+
diff = ema->f10 * (micro - ema->ema10);
ema->ema10 += (diff / 1000000);
}
-
-
+
+
#ifdef WITH_STATS_DEBUG
DEBUG("time %d %d.%06d\t%d.%06d\t%d.%06d\n",
n, micro / PREC, (micro / EMA_SCALE) % USEC,
ema->ema1 / PREC, (ema->ema1 / EMA_SCALE) % USEC,
ema->ema10 / PREC, (ema->ema10 / EMA_SCALE) % USEC);
n++;
-#endif
+#endif
}
#endif /* WITH_STATS */
}
gettimeofday(&now, NULL);
-
+
/*
* Calculate the instantaneous arrival rate into
* the queue.
&thread_pool.pps_in.pps_now,
&thread_pool.pps_in.time_old,
&now);
-
+
thread_pool.pps_in.pps_now++;
}
#endif /* WITH_ACCOUNTING */
last_complained = now;
complain = true;
}
-
+
pthread_mutex_unlock(&thread_pool.queue_mutex);
/*
struct timeval now;
gettimeofday(&now, NULL);
-
+
/*
* Calculate the instantaneous departure rate
* from the queue.
vp = radius_paircreate(request, &request->config_items,
182, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = thread_pool.pps_in.pps;
-
+
vp = radius_paircreate(request, &request->config_items,
183, VENDORPEC_FREERADIUS);
if (vp) {
thread_pool.stop_flag = 0;
#endif
thread_pool.spawn_flag = *spawn_flag;
-
+
/*
* Don't bother initializing the mutexes or
* creating the hash tables. They won't be used.
*/
if (!*spawn_flag) return 0;
-
+
#ifdef WNOHANG
if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) {
ERROR("FATAL: Failed to initialize wait mutex: %s",
{
int verify_mode;
tls_session_t *ssn = NULL;
-
+
ssn = talloc_zero(conf, tls_session_t);
if (!ssn) return NULL;
if (conf->session_cache_enable) {
state->allow_session_resumption = 1; /* otherwise it's zero */
}
-
+
RDEBUG2("Initiate");
return state;
}
void session_close(tls_session_t *ssn)
-{
+{
SSL_set_quiet_shutdown(ssn->ssl, 1);
SSL_shutdown(ssn->ssl);
ocsp_ok = 2;
goto ocsp_skip;
}
-
+
DEBUG2("[ocsp] --> Responder URL = http://%s:%s%s", host, port, path);
/* Setup BIO socket to OCSP responder */
for (p = subject + 16; *p != '\0'; p++) {
if (*p == ' ') *p = '-';
}
-
+
vp = pairmake(NULL, certs, subject, issuer, T_OP_ADD);
if (vp) debug_pair_list(vp);
}
BIO_free_all(out);
}
-
+
switch (ctx->error) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
if (strlen(conf->psk_password) > (2 * PSK_MAX_PSK_LEN)) {
ERROR("psk_hexphrase is too long (max %d)",
PSK_MAX_PSK_LEN);
- return NULL;
+ return NULL;
}
hex_len = fr_hex2bin(conf->psk_password,
(uint8_t *) buffer, psk_len);
if (psk_len != (2 * hex_len)) {
ERROR("psk_hexphrase is not all hex");
- return NULL;
+ return NULL;
}
goto post_ca;
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
-
+
/*
* Check if the loaded private key is the right one
*/
/*
* Callbacks, etc. for session resumption.
- */
+ */
if (conf->session_cache_enable) {
SSL_CTX_sess_set_new_cb(ctx, cbtls_new_session);
SSL_CTX_sess_set_get_cb(ctx, cbtls_get_session);
RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed.");
return -1;
}
-
+
/*
* Else resumption IS allowed, so we store the
* user data in the cache.
vp = paircopy2(NULL, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
-
+
vp = paircopy2(NULL, request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
-
+
vp = paircopy2(NULL, request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
} else {
vp_cursor_t cursor;
-
+
RDEBUG("Adding cached attributes for session %s:", buffer);
debug_pair_list(vps);
fr_tls_status_t tls_application_data(tls_session_t *ssn,
REQUEST *request)
-
+
{
int err;
- /*
+ /*
* Decrypt the complete record.
*/
err = BIO_write(ssn->into_ssl, ssn->dirty_in.data,
ssn->dirty_in.used, err);
return FR_TLS_FAIL;
}
-
+
/*
* Clear the dirty buffer now that we are done with it
* and init the clean_out buffer to store decrypted data
*/
record_init(&ssn->dirty_in);
record_init(&ssn->clean_out);
-
+
/*
* Read (and decrypt) the tunneled data from the
* SSL session, and put it into the decrypted
*/
err = SSL_read(ssn->ssl, ssn->clean_out.data,
sizeof(ssn->clean_out.data));
-
+
if (err < 0) {
int code;
RDEBUG("SSL_read Error");
-
+
code = SSL_get_error(ssn->ssl, err);
switch (code) {
case SSL_ERROR_WANT_READ:
}
return FR_TLS_FAIL;
}
-
+
if (err == 0) {
RWDEBUG("No data inside of the tunnel.");
}
-
+
/*
* Passed all checks, successfully decrypted data
*/
ssn->clean_out.used = err;
-
+
return FR_TLS_OK;
}
case application_data:
RDEBUG2("ACK handshake fragment handler in application data");
return FR_TLS_REQUEST;
-
+
/*
* For the rest of the conditions, switch over
* to the default section below.
listener->status = RAD_LISTEN_STATUS_REMOVE_FD;
listener->tls = NULL; /* parent owns this! */
-
+
if (sock->parent) {
/*
* Decrement the number of connections.
sock->client->limit.num_connections--;
}
}
-
+
/*
* Tell the event handler that an FD has disappeared.
*/
DEBUG("Client has closed connection");
event_new_fd(listener);
-
+
/*
* Do NOT free the listener here. It's in use by
* a request, and will need to hang around until
listen_socket_t *sock = listener->data;
p = sock->ssn->dirty_out.data;
-
+
while (p < (sock->ssn->dirty_out.data + sock->ssn->dirty_out.used)) {
RDEBUG3("Writing to socket %d", request->packet->sockfd);
rcode = write(request->packet->sockfd, p,
(sock->ssn->dirty_out.data + sock->ssn->dirty_out.used) - p);
if (rcode <= 0) {
RDEBUG("Error writing to TLS socket: %s", strerror(errno));
-
+
tls_socket_close(listener);
return 0;
}
}
sock->ssn->dirty_out.used = 0;
-
+
return 1;
}
tls_socket_close(listener);
return 0;
}
-
+
if (rcode < 0) {
RDEBUG("Error reading TLS socket: %s", strerror(errno));
goto do_close;
* Normal socket close.
*/
if (rcode == 0) goto do_close;
-
+
sock->ssn->dirty_in.used = rcode;
dump_hex("READ FROM SSL", sock->ssn->dirty_in.data, sock->ssn->dirty_in.used);
RDEBUG("Non-TLS data sent to TLS socket: closing");
goto do_close;
}
-
+
/*
* Skip ahead to reading application data.
*/
RDEBUG("FAILED in TLS handshake receive");
goto do_close;
}
-
+
if (sock->ssn->dirty_out.used > 0) {
tls_socket_write(listener, request);
PTHREAD_MUTEX_UNLOCK(&sock->mutex);
RDEBUG("Failed signing packet: %s", fr_strerror());
return 0;
}
-
+
PTHREAD_MUTEX_LOCK(&sock->mutex);
/*
* Write the packet to the SSL buffers.
DEBUG("proxy recv says %s",
ERR_error_string(err, NULL));
}
-
+
goto do_close;
}
}
(data[2] << 8) | data[3]);
goto do_close;
}
-
+
rcode = SSL_read(sock->ssn->ssl, data + 4, length);
if (rcode <= 0) {
switch (SSL_get_error(sock->ssn->ssl, rcode)) {
{
int des;
int ret = 1;
-
+
if ((des = open(filename, O_RDONLY)) == -1) {
if (errno == ENOENT) {
ret = 0;
} else {
close(des);
}
-
+
return ret;
}
if (rcode < 0) {
return rcode;
}
-
+
/*
* Set things like sticky bits that aren't supported by
* mkdir.
if (mode & ~0777) {
rcode = chmod(directory, mode);
}
-
+
return rcode;
}
char const *p = *name;
char const *q;
pair_lists_t output;
-
+
/* This should never be a NULL pointer or zero length string */
rad_assert(name && *name);
/*
* We couldn't determine the list if:
- *
+ *
* A colon delimiter was found, but the next char was a
* number, indicating a tag, not a list qualifier.
*
(!q && isupper((int) *p))) {
return unknown;
}
-
+
if (q) {
*name = (q + 1); /* Consume the list and delimiter */
return fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
if (!p) {
return REQUEST_CURRENT;
}
-
+
/*
* We may get passed "127.0.0.1".
*/
int radius_request(REQUEST **context, request_refs_t name)
{
REQUEST *request = *context;
-
+
switch (name) {
case REQUEST_CURRENT:
return 0;
-
+
case REQUEST_PARENT: /* for future use in request chaining */
case REQUEST_OUTER:
if (!request->parent) {
fr_int2str(request_refs, name, "<INVALID>"));
return -1;
}
-
+
*context = request->parent;
-
+
break;
-
+
case REQUEST_UNKNOWN:
default:
rad_assert(0);
return -1;
}
-
+
return 0;
}
vp_cursor_t cursor;
VALUE_PAIR *check_item;
VALUE_PAIR *auth_item;
-
+
int result = 0;
int compare;
int other;
int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
{
ssize_t len;
-
+
char buffer[1024];
-
+
if (vp->type != VT_XLAT) return 0;
-
+
vp->type = VT_DATA;
-
+
len = radius_xlat(buffer, sizeof(buffer), request, vp->value.xlat, NULL, NULL);
if (len < 0) {
return -1;
}
-
+
/*
* Parse the string into a new value.
*/
if (!pairparsevalue(vp, buffer)){
return -2;
}
-
+
return 0;
}
* it over.
*/
radius_xlat_do(request, i);
-
+
found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
switch (i->op) {
*/
if (!talloc_get_type(vp, VALUE_PAIR)) {
ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
-
- log_talloc_report(vp);
+
+ log_talloc_report(vp);
rad_assert(0);
}
-
+
vp_print(fr_log_fp, vp);
}
fflush(fr_log_fp);
vp_cursor_t cursor;
char buffer[256];
if (!vp || !request || !request->radlog) return;
-
+
for (vp = paircursor(&cursor, &vp);
vp;
vp = pairnext(&cursor)) {
*/
if (!talloc_get_type(vp, VALUE_PAIR)) {
REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
-
- log_talloc_report(vp);
+
+ log_talloc_report(vp);
rad_assert(0);
}
-
+
vp_prints(buffer, sizeof(buffer), vp);
-
+
request->radlog(L_DBG, level, request, "\t%s", buffer);
- }
+ }
}
/** Resolve attribute pair_lists_t value to an attribute list.
* Will be NULL if list name couldn't be resolved.
*/
VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
-{
+{
if (!request) return NULL;
switch (list) {
break;
#endif
}
-
+
RWDEBUG2("List \"%s\" is not available",
fr_int2str(pair_lists, list, "<INVALID>"));
-
+
return NULL;
}
vp_cursor_t cursor;
VALUE_PAIR **list, *vp, *head = NULL;
char buffer[1024];
-
+
if (radius_request(&request, map->dst->request) < 0) {
REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
-
+
return -2;
}
-
+
list = radius_list(request, map->dst->list);
if (!list) {
REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
-
+
return -2;
}
-
-
- /*
+
+
+ /*
* The callback should either return -1 to signify operations error, -2 when it can't find the
* attribute or list being referenced, or 0 to signify success.
* It may return "sucess", but still have no VPs to work with.
rcode = func(&head, request, map, ctx);
if (rcode < 0) {
rad_assert(!head);
-
+
return rcode;
}
if (debug_flag) for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) {
char *value;
-
+
switch (map->src->type) {
/*
* Just print the value being assigned
RDEBUG("\t\t%s %s %s", map->dst->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), value);
-
+
if (value != buffer) talloc_free(value);
}
-
+
/*
* Use pairmove so the operator is respected
*/
*
* Evaluate maps which specify exec as a src. This may be used by various sorts of update sections, and so
* has been broken out into it's own function.
- *
+ *
* @param[out] out Where to write the VALUE_PAIR(s).
* @param[in] request structure (used only for talloc).
* @param[in] map the map. The LHS (dst) must be VPT_TYPE_ATTR or VPT_TYPE_LIST. The RHS (src) must be VPT_TYPE_EXEC.
char answer[1024];
VALUE_PAIR **input_pairs = NULL;
VALUE_PAIR **output_pairs = NULL;
-
+
*out = NULL;
-
+
rad_assert(map->src->type == VPT_TYPE_EXEC);
rad_assert((map->dst->type == VPT_TYPE_ATTR) || (map->dst->type == VPT_TYPE_LIST));
* We always put the request pairs into the environment
*/
input_pairs = radius_list(request, PAIR_LIST_REQUEST);
-
+
/*
* Automagically switch output type depending on our destination
* If dst is a list, then we create attributes from the output of the program
talloc_free(output_pairs);
return -1;
}
-
+
switch (map->dst->type) {
case VPT_TYPE_LIST:
if (!output_pairs) {
return -2;
}
*out = *output_pairs;
-
+
return 0;
case VPT_TYPE_ATTR:
{
VALUE_PAIR *vp;
-
+
vp = pairalloc(request, map->dst->da);
if (!vp) return -1;
vp->op = map->op;
return -2;
}
*out = vp;
-
+
return 0;
}
default:
}
/** Convert a map to a VALUE_PAIR.
- *
+ *
* @param[out] out Where to write the VALUE_PAIR(s).
* @param[in] request structure (used only for talloc)
* @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
rad_assert(request != NULL);
rad_assert(map != NULL);
-
+
*out = NULL;
-
+
/*
* List to list found, this is a special case because we don't need
* to allocate any attributes, just found the current list, and change
if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
from = radius_list(request, map->src->list);
if (!from) return -2;
-
+
found = paircopy(request, *from);
/*
* List to list copy is invalid if the src list has no attributes.
*/
if (!found) return -2;
-
+
for (vp = paircursor(&cursor, &found);
vp;
vp = pairnext(&cursor)) {
- vp->op = T_OP_ADD;
- }
-
+ vp->op = T_OP_ADD;
+ }
+
*out = found;
-
+
return 0;
}
-
+
/*
* Deal with all non-list founding operations.
*/
da = map->dst->da ? map->dst->da : map->src->da;
-
+
switch (map->src->type) {
case VPT_TYPE_XLAT:
case VPT_TYPE_LITERAL:
rcode = -1;
goto error;
}
-
+
break;
}
/* FALL-THROUGH */
rcode = -2;
goto error;
}
-
+
/*
* Special case, destination is a list, found all instance of an attribute.
*/
if (!found) {
REDEBUG("Attribute \"%s\" not found in request", map->src->name);
rcode = -2;
- goto error;
+ goto error;
}
-
+
for (vp = paircursor(&cursor, &found);
vp;
vp = pairnext(&cursor)) {
- vp->op = T_OP_ADD;
- }
-
+ vp->op = T_OP_ADD;
+ }
+
*out = found;
return 0;
}
-
+
/*
* FIXME: allow tag references?
*/
rcode = -2;
goto error;
}
-
+
/*
* Copy the data over verbatim, assuming it's
* actually data.
if (!vp) {
return -1;
}
- vp->op = map->op;
+ vp->op = map->op;
break;
memcpy(&vp->data, map->src->vpd, sizeof(vp->data));
vp->length = map->src->length;
break;
-
+
/*
* This essentially does the same as rlm_exec xlat, except it's non-configurable.
* It's only really here as a convenience for people who expect the contents of
size_t len;
request_refs_t req;
pair_lists_t list;
-
+
VALUE_PAIR *vp = NULL;
VALUE_PAIR **vps;
-
+
p = raw;
-
+
req = radius_request_name(&p, request_def);
len = p - raw;
if (req == REQUEST_UNKNOWN) {
REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw);
-
+
return -1;
}
raw += len;
-
+
list = radius_list_name(&p, list_def);
if (list == PAIR_LIST_UNKNOWN) {
len = p - raw;
-
+
REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw);
-
+
return -1;
}
raw += len;
if (radius_request(&request, req) < 0) {
return -1;
}
-
+
vps = radius_list(request, list);
if (!vps) {
return -1;
}
-
+
if (userparse(request, raw, &vp) == T_OP_INVALID) {
return -1;
}
-
+
pairmove(request, vps, &vp);
-
+
return 0;
}
if (radius_request(&request, vpt->request) < 0) {
return NULL;
}
-
+
vps = radius_list(request, vpt->list);
if (!vps) {
return NULL;
}
-
+
switch (vpt->type) {
/*
* May not may not be found, but it *is* a known name.
*/
case VPT_TYPE_ATTR:
return pairfind(*vps, vpt->da->attr, vpt->da->vendor, TAG_ANY);
-
+
case VPT_TYPE_LIST:
return *vps;
-
+
default:
break;
}
if (!fmt) {
return;
}
-
+
va_start(ap, fmt);
vp = paircreate(request->packet, PW_MODULE_FAILURE_MESSAGE, 0);
if (!vp) {
}
p = talloc_vasprintf(vp, fmt, ap);
-
+
if (request->module && *request->module) {
pairsprintf(vp, "%s: %s", request->module, p);
} else {
int ssl_check_version(void)
{
long ssl_linked;
-
+
ssl_linked = SSLeay();
-
+
if (ssl_linked != ssl_built) {
ERROR("libssl version mismatch."
" Built with: %lx\n Linked: %lx",
(unsigned long) ssl_built,
(unsigned long) ssl_linked);
-
+
return -1;
};
-
+
return 0;
}
void version(void)
{
INFO("%s: %s", progname, radiusd_version);
-
+
DEBUG3("Server was built with: ");
-
+
#ifdef WITH_ACCOUNTING
DEBUG3(" accounting");
#endif
INFO("You may redistribute copies of FreeRADIUS under the terms of the");
INFO("GNU General Public License.");
INFO("For more information about these matters, see the file named COPYRIGHT.");
-
+
fflush(NULL);
}
char const *fmt; //!< The format string.
size_t len; //!< Length of the format string.
- const DICT_ATTR *da; //!< the name of the dictionary attribute
+ const DICT_ATTR *da; //!< the name of the dictionary attribute
int num; //!< attribute number
int tag; //!< attribute tag
pair_lists_t list; //!< list of which attribute
xlat_state_t type; //!< type of this expansion
xlat_exp_t *next; //!< Next in the list.
-
+
xlat_exp_t *child; //!< Nested expansion.
- xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
-
+ xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
+
const xlat_t *xlat; //!< The xlat expansion to expand format with.
};
VALUE_PAIR *vp;
uint64_t integer;
-
+
while (isspace((int) *fmt)) fmt++;
if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
return 0;
}
- switch (vp->da->type) {
+ switch (vp->da->type) {
case PW_TYPE_OCTETS:
case PW_TYPE_STRING:
if (vp->length > 8) {
}
memcpy(&integer, &(vp->vp_octets), vp->length);
-
- return snprintf(out, outlen, "%" PRIu64, ntohll(integer));
-
+
+ return snprintf(out, outlen, "%" PRIu64, ntohll(integer));
+
case PW_TYPE_INTEGER64:
return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
-
+
case PW_TYPE_IPADDR:
case PW_TYPE_INTEGER:
case PW_TYPE_SHORT:
default:
break;
}
-
+
REDEBUG("Type \"%s\" cannot be converted to integer",
fr_int2str(dict_attr_types, vp->da->type, PW_TYPE_INVALID));
*out = '\0';
-
+
return -1;
}
*out = '\0';
return -1;
}
-
+
ret = rad_vp2data(vp, buffer, sizeof(buffer));
len = (size_t) ret;
-
+
/*
* Don't truncate the data.
*/
VALUE_PAIR *vp;
uint8_t buffer[MAX_STRING_LEN];
ssize_t ret;
-
+
while (isspace((int) *fmt)) fmt++;
if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
*out = '\0';
return 0;
}
-
+
ret = rad_vp2data(vp, buffer, sizeof(buffer));
if (ret < 0) {
*out = '\0';
char const *fmt, char *out, size_t outlen)
{
int level = 0;
-
+
/*
* Expand to previous (or current) level
*/
*/
if (!*fmt)
goto done;
-
+
level = atoi(fmt);
if (level == 0) {
request->options = RAD_REQUEST_OPTION_NONE;
request->options = level;
request->radlog = radlog_request;
}
-
+
done:
return strlen(out);
}
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) {
return slen - (p - fmt);
}
p += slen + 1;
-
+
*head = node;
rad_assert(node->next == NULL);
return p - fmt;
*/
p = strchr(attrname, ':');
if (p) *p = '\0';
-
+
} else {
brace = strchr(attrname, '}');
if (!brace) {
*brace = '\0';
node->ref = REQUEST_CURRENT;
- node->list = PAIR_LIST_REQUEST;
+ node->list = PAIR_LIST_REQUEST;
}
*brace = '\0';
*error = "Unknown attribute";
return -(attrname - fmt);
}
-
+
/*
* Parse the tag.
*/
tag = strtoul(p + 1, &end, 10);
p++;
-
+
if (tag == ULONG_MAX) {
talloc_free(node);
*error = "Invalid tag value";
*(q++) = *p;
p += 2;
node->len++;
- continue;
+ continue;
}
/*
if (node->len > 0) {
*head = node;
- } else {
+ } else {
(void) talloc_steal(ctx, node->next);
*head = node->next;
talloc_free(node);
p = buffer;
end = buffer + bufsize;
-
+
while (node) {
switch (node->type) {
case XLAT_LITERAL:
char const *error;
*head = NULL;
-
- /*
+
+ /*
* Copy the original format string to a buffer so that
* the later functions can mangle it in-place, which is
* much faster.
if (slen == 0) {
*head = talloc_zero(request, xlat_exp_t);
}
-
+
/*
* Output something like:
*
if (request->packet) {
when = request->packet->timestamp.tv_sec;
}
-
+
switch (*p) {
case '%':
str[0] = '%';
str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_asprintf */
*str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */
-
+
rcode = node->xlat->func(node->xlat->instance, request, child, str, 1024);
talloc_free(child);
if (rcode < 0) {
size_t total;
char **array, *answer;
const xlat_exp_t *node;
-
+
*out = NULL;
/*
char *buff;
ssize_t len;
xlat_exp_t *node;
-
+
rad_assert(fmt);
rad_assert(request);
} else {
*out = talloc_zero_array(request, char, 1);
}
- return 0;
+ return 0;
}
-
+
if (len < 0) {
if (*out) *out[0] = '\0';
return -1;
{
return xlat_expand(&out, outlen, request, fmt, escape, ctx);
}
-
+
ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
{
return xlat_expand(out, 0, request, fmt, escape, ctx);
if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
fr_strerror_printf("getsockname failed: %s", strerror(errno));
rad_free(&packet);
- return NULL;
+ return NULL;
}
#endif
*/
head = NULL;
paircursor(&cursor, &head);
-
+
p = data;
while (p < (data + data_len)) {
vp = paircreate(packet, tlv->da->attr | (p[0] << 8), DHCP_MAGIC_VENDOR);
memcpy(q, p , alen);
q[alen] = '\0';
break;
-
+
/*
* Value doesn't match up with attribute type, overwrite the
* vp's original DICT_ATTR with an unknown one.
*/
raw:
if (pair2unknown(vp) < 0) return -1;
-
+
case PW_TYPE_OCTETS:
if (alen > 253) return -1;
pairmemcpy(vp, p, alen);
while (next < (data + len)) {
int num_entries, alen;
const DICT_ATTR *da;
-
+
p = next;
if (*p == 0) break;
p[0], p[1]);
continue;
}
-
+
da = dict_attrbyvalue(p[0], DHCP_MAGIC_VENDOR);
if (!da) {
fr_strerror_printf("Attribute not in our dictionary: %u",
pairfree(head);
return -1;
}
-
+
/*
* Hack for ease of use.
*/
}
pairinsert(&cursor, vp);
-
+
for (vp = paircurrent(&cursor);
vp;
vp = pairnext(&cursor)) {
p += alen;
} /* loop over array entries */
} /* loop over the entire packet */
-
+
return next - data;
}
/*
* Loop over the options.
*/
-
+
/*
* Nothing uses tail after this call, if it does in the future
* it'll need to find the new tail...
*/
{
VALUE_PAIR *options = NULL;
-
+
if (fr_dhcp_decode_options(packet,
packet->data + 240, packet->data_len - 240,
&options) < 0) {
return -1;
}
-
+
if (options) {
pairinsert(&cursor, options);
}
} else {
name = "?Unknown?";
}
-
+
DEBUG(
#ifdef WITH_UDPFROMTO
"Encoding %s of id %08x from %s:%d to %s:%d\n",
} else {
*p++ = 1; /* client message */
}
-
+
/* DHCP-Hardware-Type */
if ((vp = pairfind(packet->vps, 257, DHCP_MAGIC_VENDOR, TAG_ANY))) {
*p++ = vp->vp_integer & 0xFF;
* instead of being placed verbatim in the filename field.
*/
- /* DHCP-Boot-Filename */
+ /* DHCP-Boot-Filename */
if ((vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY))) {
if (vp->length > DHCP_FILE_LEN) {
memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
return -1;
}
-
+
switch (vp->da->type) {
case PW_TYPE_BYTE:
vp->vp_integer = p[0];
switch (vp->da->attr) {
default:
break;
-
+
/*
* Allow it to set the packet type in
* the attributes read from the file.
case PW_PACKET_TYPE:
request->code = vp->vp_integer;
break;
-
+
case PW_PACKET_DST_PORT:
request->dst_port = (vp->vp_integer & 0xffff);
break;
-
+
case PW_PACKET_DST_IP_ADDRESS:
request->dst_ipaddr.af = AF_INET;
request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
break;
-
+
case PW_PACKET_DST_IPV6_ADDRESS:
request->dst_ipaddr.af = AF_INET6;
request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
break;
-
+
case PW_PACKET_SRC_PORT:
request->src_port = (vp->vp_integer & 0xffff);
break;
-
+
case PW_PACKET_SRC_IP_ADDRESS:
request->src_ipaddr.af = AF_INET;
request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
break;
-
+
case PW_PACKET_SRC_IPV6_ADDRESS:
request->src_ipaddr.af = AF_INET6;
request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
break;
} /* switch over the attribute */
-
+
} /* loop over the VP's we read in */
if (fp != stdin) fclose(fp);
printf("%s = 0x", dhcp_header_names[i]);
for (j = 0; j < dhcp_header_sizes[i]; j++) {
printf("%02x", p[j]);
-
+
}
printf("\n");
p += dhcp_header_sizes[i];
printf("%02x %02x ", p[0], p[1]);
a = p + 2;
-
+
for (i = 0; i < p[1]; i++) {
if ((i > 0) && ((i & 0x0f) == 0x00))
printf("\t\t");
printf("%02x ", a[i]);
if ((i & 0x0f) == 0x0f) printf("\n");
}
-
+
if ((p[1] & 0x0f) != 0x00) printf("\n");
-
+
p += p[1] + 2;
}
printf("\n----------------------------------------------------------------------\n");
exit(1);
}
if (fr_debug_flag) print_hex(request);
-
+
if (fr_dhcp_send(request) < 0) {
fprintf(stderr, "dhcpclient: failed sending: %s\n",
strerror(errno));
uint32_t attr = attrnums[i];
if (pairfind(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue;
-
+
vp = pairfind(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY);
if (vp) {
pairadd(&request->reply->vps, paircopyvp(request->reply, vp));
DEBUG("DHCP: Failed to find DHCP-Your-IP-Address for request.");
return -1;
}
-
+
RDEBUG("DHCP: Reply will be sent unicast to your-ip-address");
request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
-
+
/*
* When sending a DHCP_OFFER, make sure our ARP table
* contains an entry for the client IP address.
*/
if (request->reply->code == PW_DHCP_OFFER) {
VALUE_PAIR *hwvp = pairfind(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
-
+
if (!hwvp) return -1;
-
+
if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
return -1;
}
cf_item_parse(cs, "suppress_responses", PW_TYPE_BOOLEAN,
&sock->suppress_responses, NULL);
}
-
+
cp = cf_pair_find(cs, "src_interface");
if (cp) {
cf_item_parse(cs, "src_interface", PW_TYPE_STRING_PTR,
vp_cursor_t cursor;
VALUE_PAIR *vp, *head = NULL;
int decoded = 0;
-
+
while (isspace((int) *fmt)) fmt++;
-
-
+
+
if ((radius_get_vp(request, fmt, &vp) < 0) || !vp) {
*out = '\0';
return 0;
}
-
+
if ((fr_dhcp_decode_options(request->packet,
vp->vp_octets, vp->length, &head) < 0) || (!head)) {
RWDEBUG("DHCP option decoding failed");
*out = '\0';
return -1;
}
-
+
for (vp = paircursor(&cursor, &head);
vp;
}
pairmove(request->packet, &(request->packet->vps), &head);
-
+
/* Free any unmoved pairs */
pairfree(&head);
-
+
snprintf(out, freespace, "%i", decoded);
-
+
return strlen(out);
}
static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
{
rlm_dhcp_t *inst = instance;
-
+
xlat_register("dhcp_options", dhcp_options_xlat, NULL, inst);
return 0;
socklen_t sizeof_src;
if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &src, &sizeof_src)) {
- return -1; /* Unknown address family, Die Die Die! */
+ return -1; /* Unknown address family, Die Die Die! */
}
#endif
*/
if (data_len < 4) {
rad_recv_discard(sockfd);
-
+
return 0;
/*
(header[1] > 4) ||
(header[3] > VQP_MAX_ATTRIBUTES)) {
rad_recv_discard(sockfd);
-
+
return 0;
} else { /* we got 4 bytes of data. */
if ((header[1] == 1) || (header[1] == 3)) {
if (len != VQP_MAX_ATTRIBUTES) {
rad_recv_discard(sockfd);
-
+
return 0;
}
/*
} else {
if (len != 2) {
rad_recv_discard(sockfd);
-
+
return 0;
}
/*
fprintf(stderr, "%02x ", ptr[i]);
if ((i & 0x0f) == 0x0f) fprintf(stderr, "\n");
}
-
+
}
if (ptr[3] > VQP_MAX_ATTRIBUTES) {
vp->vp_integer = packet->data[2];
debug_pair(vp);
pairinsert(&cursor, vp);
-
+
vp = paircreate(packet, PW_VQP_SEQUENCE_NUMBER, 0);
if (!vp) {
fr_strerror_printf("No memory");
vp->length = 4;
break;
}
-
+
/*
* Value doesn't match the type we have for the
* valuepair so we must change it's da to an
}
return RLM_MODULE_UPDATED;
-
+
error:
pairfree(&output);
return RLM_MODULE_FAIL;
CONF_SECTION *cs;
rbtree_t *cache;
fr_heap_t *heap;
-
+
value_pair_map_t *maps; //!< Attribute map applied to users
//!< and profiles.
#ifdef HAVE_PTHREAD_H
rad_assert(request != NULL);
rad_assert(c != NULL);
-
+
vp = pairfind(request->config_items, PW_CACHE_MERGE, 0, TAG_ANY);
if (vp && (vp->vp_integer == 0)) {
RDEBUG2("Told not to merge entry into request");
if (c->packet && request->packet) {
RDEBUG2("Merging cached request list:");
rdebug_pair_list(2, request, c->packet);
-
+
pairadd(&request->packet->vps,
paircopy(request->packet, c->packet));
}
pairadd(&request->reply->vps,
paircopy(request->reply, c->reply));
}
-
+
if (inst->stats) {
vp = paircreate(request->packet, PW_CACHE_ENTRY_HITS, 0);
rad_assert(vp != NULL);
-
+
vp->vp_integer = c->hits;
pairadd(&request->packet->vps, vp);
fr_heap_extract(inst->heap, c);
rbtree_deletebydata(inst->cache, c);
-
+
return NULL;
}
vp = pairfind(request->config_items, PW_CACHE_TTL, 0, TAG_ANY);
if (vp) {
if (vp->vp_integer == 0) goto delete;
-
+
ttl = vp->vp_integer;
c->expires = request->timestamp + ttl;
RDEBUG("Adding %d to the TTL", ttl);
c->expires += ttl;
RDEBUG("Creating entry for \"%s\"", key);
-
+
/*
* Check to see if we need to merge the entry into the request
*/
merge = false;
RDEBUG2("Told not to merge new entry into request");
}
-
+
for (map = inst->maps; map != NULL; map = map->next) {
rad_assert(map->dst && map->src);
case PAIR_LIST_REQUEST:
to_cache = &c->packet;
break;
-
+
case PAIR_LIST_REPLY:
to_cache = &c->reply;
break;
-
+
case PAIR_LIST_CONTROL:
to_cache = &c->control;
break;
default:
rad_assert(0);
- return NULL;
+ return NULL;
}
-
+
/*
* Resolve the destination in the current request.
* We need to add the to_cache there too if any of these
to_req = radius_list(context, map->dst->list);
}
}
-
+
/*
* We infer that src was an attribute ref from the fact
* it contains a da.
RDEBUG4(":: dst is \"%s\" src is \"%s\"",
fr_int2str(vpt_types, map->dst->type, "<INVALID>"),
fr_int2str(vpt_types, map->src->type, "<INVALID>"));
-
+
switch (map->src->type) {
case VPT_TYPE_ATTR:
from = NULL;
if (radius_request(&context, map->src->request) == 0) {
from = radius_list(context, map->src->list);
}
-
+
/*
* Can't add the attribute if the list isn't
* valid.
map->src->name);
continue;
}
-
+
RDEBUG("\t%s %s %s", map->dst->name,
fr_int2str(fr_tokens, map->op, "<INVALID>"),
map->src->name);
-
+
switch (map->op) {
case T_OP_SET:
case T_OP_EQ:
vp = map->dst->type == VPT_TYPE_LIST ?
paircopyvp(c, found) :
paircopyvpdata(c, map->dst->da, found);
-
+
if (!vp) continue;
-
+
pairadd(to_cache, vp);
if (to_req) {
vp = paircopyvp(request, vp);
radius_pairmove(request, to_req, vp);
}
-
+
break;
case T_OP_ADD:
{
vp_cursor_t cursor;
-
+
for (found = paircursor(&cursor, &found);
found;
found = pairfindnext(&cursor, da->attr, da->vendor, TAG_ANY)) {
paircopyvp(c, found) :
paircopyvpdata(c, map->dst->da, found);
if (!vp) continue;
-
+
vp->op = map->op;
pairadd(to_cache, vp);
-
+
if (to_req) {
vp = paircopyvp(request, vp);
radius_pairmove(request, to_req, vp);
-
+
}
- }
+ }
break;
}
-
+
default:
rad_assert(0);
return NULL;
{
vp_cursor_t cursor;
VALUE_PAIR *i;
-
+
rad_assert(map->src->type == VPT_TYPE_LIST);
-
+
from = NULL;
context = request;
if (radius_request(&context, map->src->request) == 0) {
from = radius_list(context, map->src->list);
}
if (!from) continue;
-
+
found = paircopy(c, *from);
if (!found) continue;
-
+
for (i = paircursor(&cursor, &vp);
i != NULL;
i = pairnext(&cursor)) {
map->src->name, i->da->name);
i->op = map->op;
}
-
+
pairadd(to_cache, found);
-
+
if (to_req) {
vp = paircopy(request, found);
radius_pairmove(request, to_req, vp);
}
-
+
break;
}
/*
*/
case VPT_TYPE_XLAT:
if (radius_xlat(buffer, sizeof(buffer), request, map->src->name, NULL, NULL) <= 0) {
- continue;
+ continue;
}
RDEBUG("\t%s %s \"%s\"", map->dst->name,
vp = pairalloc(NULL, map->dst->da);
if (!vp) continue;
-
+
vp->op = map->op;
if (!pairparsevalue(vp, buffer)) {
pairfree(&vp);
continue;
}
-
+
pairadd(to_cache, vp);
-
+
if (to_req) {
vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
+ radius_pairmove(request, to_req, vp);
}
-
+
break;
/*
* Literal string.
RDEBUG("\t%s %s '%s'", map->dst->name,
fr_int2str(fr_tokens, map->op, "<INVALID>"),
map->src->name);
-
+
vp = pairalloc(NULL, map->dst->da);
if (!vp) continue;
-
+
vp->op = map->op;
if (!pairparsevalue(vp, map->src->name)) {
pairfree(&vp);
continue;
}
-
+
pairadd(to_cache, vp);
-
+
if (to_req) {
vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
+ radius_pairmove(request, to_req, vp);
}
-
+
break;
-
+
default:
rad_assert(0);
return NULL;
}
}
-
+
if (!rbtree_insert(inst->cache, c)) {
REDEBUG("FAILED adding entry for key %s", key);
cache_entry_free(c);
if (radius_attrmap(cf_section_sub_find(inst->cs, "update"),
head, PAIR_LIST_REQUEST,
PAIR_LIST_REQUEST, MAX_ATTRMAP) < 0) {
- return -1;
+ return -1;
}
-
+
if (!*head) {
cf_log_err_cs(inst->cs,
"Cache config must contain an update section, and "
(map->dst->type != VPT_TYPE_LIST)) {
cf_log_err(map->ci, "Left operand must be an attribute "
"ref or a list");
-
+
return -1;
}
-
+
switch (map->src->type) {
/*
* Only =, :=, += and -= operators are supported for
case T_OP_SUB:
case T_OP_ADD:
break;
-
+
default:
cf_log_err(map->ci, "Operator \"%s\" not "
"allowed for %s values",
int ret = 0;
list = radius_list_name(&p, PAIR_LIST_REQUEST);
-
+
target = dict_attrbyname(p);
if (!target) {
REDEBUG("Unknown attribute \"%s\"", p);
return -1;
}
-
+
PTHREAD_MUTEX_LOCK(&inst->cache_mutex);
c = cache_find(inst, request, fmt);
-
+
if (!c) {
RDEBUG("No cache entry for key \"%s\"", fmt);
*out = '\0';
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:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
REDEBUG("Unknown list qualifier in \"%s\"", fmt);
return -1;
-
+
default:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
REDEBUG("Unsupported list \"%s\"",
*out = '\0';
goto done;
}
-
+
ret = vp_prints_value(out, freespace, vp, 0);
done:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
-
+
return ret;
}
static int mod_detach(void *instance)
{
rlm_cache_t *inst = instance;
-
+
talloc_free(inst->maps);
fr_heap_delete(inst->heap);
cf_log_err_cs(conf, "Must set 'ttl' to non-zero");
return -1;
}
-
+
if (inst->epoch != 0) {
cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files");
return -1;
PTHREAD_MUTEX_LOCK(&inst->cache_mutex);
c = cache_find(inst, request, buffer);
-
+
/*
* If yes, only return whether we found a valid cache entry
*/
RLM_MODULE_NOTFOUND;
goto done;
}
-
+
if (c) {
cache_merge(inst, request, c);
-
+
rcode = RLM_MODULE_OK;
goto done;
}
}
rcode = RLM_MODULE_UPDATED;
-
+
done:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
return rcode;
char const *check_name; /* Daily-Max-Session */
char const *reply_name; /* Session-Timeout */
char const *service_type; /* Service-Type to search for */
-
+
int cache_size;
uint32_t service_val;
-
+
int key_attr;
int count_attr;
int check_attr;
int reply_attr;
int dict_attr; /* attribute number for the counter. */
-
+
time_t reset_time; /* The time of the next reset. */
time_t last_reset; /* The time of the last reset. */
offsetof(rlm_counter_t,key_name), NULL, NULL },
{ "reset", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
offsetof(rlm_counter_t,reset), NULL, NULL },
-
+
{ "count-attribute", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,count_attribute), NULL, NULL },
+ offsetof(rlm_counter_t,count_attribute), NULL, NULL },
{ "count_attribute", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
offsetof(rlm_counter_t,count_attribute), NULL, NULL },
offsetof(rlm_counter_t,reply_name), NULL, NULL },
{ "reply_name", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
offsetof(rlm_counter_t,reply_name), NULL, NULL},
-
+
{ "allowed-servicetype", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
offsetof(rlm_counter_t,service_type), NULL, NULL },
{ "allowed_service_type", PW_TYPE_STRING_PTR,
offsetof(rlm_counter_t,service_type), NULL, NULL },
-
+
{ "cache-size", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
offsetof(rlm_counter_t,cache_size), NULL, NULL },
{ "cache_size", PW_TYPE_INTEGER,
*/
{
char *filename;
-
+
memcpy(&filename, &inst->filename, sizeof(filename));
inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
}
sizeof(cache_size)) == -1) {
ERROR("rlm_counter: Failed to set cache size");
}
-
+
DEBUG2("rlm_counter: reset_db: Opened new database");
/*
ERROR("rlm_counter: find_next_reset() returned -1. Exiting.");
return -1;
}
-
+
{
char *filename;
-
+
memcpy(&filename, &inst->filename, sizeof(filename));
inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
}
} else {
inst->reset_time = next_reset;
}
-
+
memcpy(&key_datum.dptr, &default2, sizeof(key_datum.dptr));
key_datum.dsize = strlen(key_datum.dptr);
if (inst->gdbm) {
gdbm_close(inst->gdbm);
}
-
+
pthread_mutex_destroy(&inst->mutex);
return 0;
char *filename; //!< File/path to write to.
int perm; //!< Permissions to use for new files.
char *group; //!< Group to use for new files.
-
+
int dirperm; //!< Directory permissions to use for new files.
-
+
char *header; //!< Header format.
int locking; //!< Whether the file should be locked.
-
+
int log_srcdst; //!< Add IP src/dst attributes to entries.
fr_hash_table_t *ht; //!< Holds suppressed attributes.
CONF_ITEM *ci;
inst->ht = fr_hash_table_create(detail_hash, detail_cmp, NULL);
-
+
for (ci = cf_item_find_next(cs, NULL);
ci != NULL;
ci = cf_item_find_next(cs, ci)) {
RERROR("rlm_detail: Failed to create directory %s: %s", buffer, strerror(errno));
return RLM_MODULE_FAIL;
}
-
+
*p = '/';
} /* else there was no directory delimiter. */
{
VALUE_PAIR *first, *i;
vp_cursor_t cursor;
-
+
/*
* We need both of these attributes to do the authentication.
*/
* Check for proper format of the Digest-Attributes
*/
RDEBUG("Checking for correctly formatted Digest-Attributes");
-
+
first = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY);
if (!first) {
return RLM_MODULE_NOOP;
}
-
+
paircursor(&cursor, &first);
while ((i = pairfindnext(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
int length = i->length;
/*
* Double-check and fix the attributes.
- */
+ */
rcode = digest_fix(request);
if (rcode != RLM_MODULE_OK) return rcode;
inst = talloc_get_type_abort(ctx, eap_module_t);
/*
- * We have to check inst->type as it's only allocated
+ * We have to check inst->type as it's only allocated
* if we loaded the eap method.
*/
if (inst->type && inst->type->detach) (inst->type->detach)(inst->instance);
}
/** Load required EAP sub-modules (methods)
- *
+ *
*/
int eap_module_load(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t num, CONF_SECTION *cs)
{
/* fill in the structure */
method->cs = cs;
method->name = eap_type2name(num);
-
+
/*
* The name of the module were trying to load
*/
if (!method->type) {
ERROR("rlm_eap (%s): Failed linking to structure in %s: %s", inst->xlat_name,
method->name, dlerror());
-
+
return -1;
}
open_self:
#endif
cf_log_module(cs, "Linked to sub-module %s", mod_name);
-
+
/*
* Call the attach num in the EAP num module
*/
if ((method->type->attach) && ((method->type->attach)(method->cs, &(method->instance)) < 0)) {
ERROR("rlm_eap (%s): Failed to initialise %s", inst->xlat_name, mod_name);
-
+
if (method->instance) {
(void) talloc_steal(method, method->instance);
}
-
+
return -1;
}
if (method->instance) {
(void) talloc_steal(method, method->instance);
}
-
+
return 0;
}
{
int rcode = 1;
REQUEST *request = handler->request;
-
+
char const *caller = request->module;
RDEBUG2("Calling %s to process EAP data", module->type->name);
-
+
request->module = module->type->name;
rad_assert(module != NULL);
if (!module->type->initiate(module->instance, handler)) {
rcode = 0;
}
-
+
break;
case AUTHORIZE:
!module->type->authorize(module->instance, handler)) {
rcode = 0;
}
-
+
break;
case AUTHENTICATE:
!module->type->authenticate(module->instance, handler)) {
rcode = 0;
}
-
+
break;
default:
unsigned int i;
VALUE_PAIR *vp;
eap_type_t method = PW_EAP_INVALID;
-
+
/*
* The NAK data is the preferred EAP type(s) of
* the client.
if (nak->data[i] == 0) {
RDEBUG("Peer NAK'd indicating it is not willing to "
"continue ");
-
+
return PW_EAP_INVALID;
}
-
+
/*
* It is invalid to request identity,
* notification & nak in nak.
"type %s (%d)",
eap_type2name(nak->data[i]),
nak->data[i]);
-
+
return PW_EAP_INVALID;
}
"unsupported type %s (%d), skipping...",
eap_type2name(nak->data[i]),
nak->data[i]);
-
+
continue;
}
nak->data[i],
eap_type2name(nak->data[i]),
nak->data[i]);
-
+
continue;
}
continue;
}
-
+
RDEBUG("Found mutually acceptable type %s (%d)",
eap_type2name(nak->data[i]), nak->data[i]);
-
+
method = nak->data[i];
break;
}
-
+
if (method == PW_EAP_INVALID) {
REDEBUG("No mutually acceptable types found");
}
-
+
return method;
}
{
eap_type_data_t *type = &handler->eap_ds->response->type;
REQUEST *request = handler->request;
-
+
eap_type_t next = inst->default_method;
VALUE_PAIR *vp;
-
+
/*
* Don't trust anyone.
*/
if ((type->num == 0) || (type->num >= PW_EAP_MAX_TYPES)) {
REDEBUG("Peer sent type (%d), which is outside known range", type->num);
-
+
return EAP_INVALID;
}
vp = pairfind(handler->request->config_items, PW_EAP_TYPE, 0,
TAG_ANY);
if (vp) next = vp->vp_integer;
-
+
/*
* Ensure it's valid.
*/
(!inst->methods[next])) {
REDEBUG2("Tried to start unsupported method (%d)",
next);
-
+
return EAP_INVALID;
}
REDEBUG2("Failed starting EAP %s (%d) session. "
"EAP sub-module failed",
eap_type2name(next),
- next);
-
+ next);
+
return EAP_INVALID;
}
break;
handler->free_opaque = NULL;
handler->opaque = NULL;
}
-
+
next = eap_process_nak(inst, handler->request,
handler->type, type);
"type %s (%d)",
eap_type2name(type->num),
type->num);
-
+
return EAP_INVALID;
}
struct _eap_handler *prev, *next;
uint8_t state[EAP_STATE_LEN];
fr_ipaddr_t src_ipaddr;
-
+
uint8_t eap_id; //!< EAP Identifier used to match
//!< requests and responses.
eap_type_t type; //!< EAP type number.
eaptls_request(handler->eap_ds, tls_session);
return FR_TLS_HANDLED;
}
-
+
/*
* If there is no data to send i.e
* dirty_out.used <=0 and if the SSL
* handshake is finished, then return a
* EPTLS_SUCCESS
*/
-
+
if (SSL_is_init_finished(tls_session->ssl)) {
/*
* Init is finished. The rest is
tls_session->info.content_type = application_data;
return FR_TLS_SUCCESS;
}
-
+
/*
* Who knows what happened...
*/
* there more fragments coming, then send ACK,
* and get the caller to continue the
* conversation.
- */
+ */
if ((status == FR_TLS_MORE_FRAGMENTS) ||
(status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) ||
(status == FR_TLS_FIRST_FRAGMENT)) {
PW_EAP_TTLS, /* 21 */
PW_EAP_REMOTE_ACCESS_SERVICE, /* 22 */
PW_EAP_AKA, /* 23 */
- PW_EAP_3COM, /* 24 - should this be EAP-HP now? */
+ PW_EAP_3COM, /* 24 - should this be EAP-HP now? */
PW_EAP_PEAP, /* 25 */
PW_EAP_MSCHAPV2, /* 26 */
PW_EAP_MAKE, /* 27 */
if (dv) {
return dv->value;
}
-
+
return PW_EAP_INVALID;
}
if (dv) {
return dv->name;
}
-
+
return "unknown";
}
header->code = (reply->code & 0xFF);
header->id = (reply->id & 0xFF);
-
+
total_length = htons(total_length);
memcpy(header->length, &total_length, sizeof(total_length));
*/
subtype = (vp = pairfind(r->vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0, TAG_ANY)) ?
vp->vp_integer : eapsim_start;
-
+
id = (vp = pairfind(r->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) ?
vp->vp_integer : ((int)getpid() & 0xff);
-
+
eapcode = (vp = pairfind(r->vps, ATTRIBUTE_EAP_CODE, 0, TAG_ANY)) ?
vp->vp_integer : PW_EAP_REQUEST;
if (ep->code != PW_EAP_SUCCESS) {
ep->code = eapcode;
}
-
+
ep->id = (id & 0xff);
ep->type.num = PW_EAP_SIM;
if (encodedmsg != NULL) {
talloc_free(encodedmsg);
}
-
+
return 0;
}
if (!newvp) {
return 0;
}
-
+
newvp->vp_integer = attr[0];
newvp->length = 1;
pairadd(&(r->vps), newvp);
if (!e) {
return 0;
}
-
+
/* make copy big enough for everything */
elen = (e->length[0] * 256) + e->length[1];
len = elen + extralen;
snprintf(statenamebuf, statenamebuflen, "eapstate:%d", state);
return statenamebuf;
}
-
+
return simstates[state];
}
{
if (subtype >= eapsim_max_subtype) {
snprintf(subtypenamebuf, subtypenamebuflen, "illegal-subtype:%d", subtype);
-
+
return subtypenamebuf;
}
-
+
return subtypes[subtype];
}
* Delete old handler from the tree.
*/
rbtree_delete(inst->session_tree, node);
-
+
/*
* And unsplice it from the linked list.
*/
for (i = 0; i < 3; i++) {
handler = inst->session_head;
if (!handler) break;
-
+
RDEBUG("Expiring EAP session with state "
"0x%02x%02x%02x%02x%02x%02x%02x%02x",
handler->state[0], handler->state[1],
memcpy(handler->state + i * 4, &lvalue,
sizeof(lvalue));
- }
+ }
}
/*
last_logged = handler->timestamp;
ERROR("rlm_eap (%s): Too many open sessions. Try increasing \"max_sessions\" "
"in the EAP module configuration", inst->xlat_name);
- }
+ }
} else {
ERROR("rlm_eap (%s): Failed to store handler", inst->xlat_name);
}
state->vp_octets[2], state->vp_octets[3],
state->vp_octets[4], state->vp_octets[5],
state->vp_octets[6], state->vp_octets[7]);
-
-
+
+
eap_handler_free(inst, handler);
return NULL;
}
cf_log_err_cs(cs, "Unknown EAP method %s", name);
return -1;
}
-
+
if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) {
cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name);
return -1;
* Load the type.
*/
ret = eap_module_load(inst, &inst->methods[method], method, scs);
-
+
(void) talloc_get_type_abort(inst->methods[method], eap_module_t);
-
+
if (ret < 0) {
(void) talloc_steal(inst, inst->methods[method]);
return -1;
eap_handler_free(inst, handler);
return RLM_MODULE_FAIL;
}
-
+
} else { /* couldn't have been LEAP, there's no tunnel */
RDEBUG2("Freeing handler");
/* handler is not required any more, free it now */
VALUE_PAIR *vp;
eap_handler_t *handler;
eap_packet_raw_t *eap_packet;
-
+
/*
* Only build a failure message if something previously rejected the request
*/
vp = pairfind(request->config_items, PW_POSTAUTHTYPE, 0, TAG_ANY);
if (!vp || (vp->vp_integer != PW_POSTAUTHTYPE_REJECT)) return RLM_MODULE_NOOP;
-
+
if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
RDEBUG2("Request didn't contain an EAP-Message, not inserting EAP-Failure");
return RLM_MODULE_NOOP;
}
-
+
if (pairfind(request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
RDEBUG2("Reply already contained an EAP-Message, not inserting EAP-Failure");
return RLM_MODULE_NOOP;
}
-
+
eap_packet = eap_vp2packet(request, request->packet->vps);
if (!eap_packet) {
RERROR("Malformed EAP Message");
RDEBUG2("Request was previously rejected, inserting EAP-Failure");
eap_fail(handler);
eap_handler_free(inst, handler);
-
+
/*
* Make sure there's a message authenticator attribute in the response
* RADIUS protocol code will calculate the correct value later...
* Configuration items.
*/
int timer_limit;
-
+
char const *default_method_name;
eap_type_t default_method;
-
+
int ignore_unknown_types;
int mod_accounting_username_bug;
-
+
int max_sessions;
#ifdef HAVE_PTHREAD_H
OPT_ENCRYPTION = 0x04,
OPT_DHGROUP = 0x08,
OPT_NEEDED = OPT_INTEGRITY | OPT_PRF | OPT_ENCRYPTION | OPT_DHGROUP
-
+
};
-
+
static struct config_transform config_transforms[] =
CONF_PAIR *cp;
int option_exists = 0;
int i = 0;
-
+
rad_assert(prot);
rad_assert(cf);
-
+
DEBUG(IKEv2_LOG_PREFIX "Begin load transforms");
-
+
while(config_transforms[i].name)
{
uint8_t id;
uint16_t keylen;
-
+
for(cp = cf_pair_find(cf,config_transforms[i].name);
cp;
cp = cf_pair_find_next(cf,cp,config_transforms[i].name)) {
config_transforms[i].name,cf_pair_value(cp));
return -1;
}
-
+
if (!AddTransform(prot,config_transforms[i].type,id,keylen)) {
ERROR(IKEv2_LOG_PREFIX "Problem with transform %s:%s",
config_transforms[i].name,cf_pair_value(cp));
}
-void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
+void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
int default_client_authtype)
{
rad_assert(list && id);
VALUE_PAIR *vp;
memcpy(&ike_id, &id, sizeof(id));
-
+
if (!items) {
AddSharedSec(list, 0, ike_id, NULL, default_client_authtype);
-
+
return;
}
DEBUG(IKEv2_LOG_PREFIX "[%s] -- Not valid id type", id);
}
}
-
+
//secret
vp = pairfind(items, RAD_EAP_IKEV2_SECRET, 0, TAG_ANY);
if (!vp || !vp->length) {
} else {
secret = vp->vp_strvalue;
}
-
+
//authtype
vp = pairfind(items, RAD_EAP_IKEV2_AUTHTYPE, 0, TAG_ANY);
if (vp && vp->length) {
authtype = AuthtypeFromName(vp->vp_strvalue);
-
+
if (authtype == -1) {
- ERROR(IKEv2_LOG_PREFIX "Unsupported 'EAP-IKEv2-AuthType' value (%s),using 'both'",
+ ERROR(IKEv2_LOG_PREFIX "Unsupported 'EAP-IKEv2-AuthType' value (%s),using 'both'",
vp->vp_strvalue);
authtype = IKEv2_AUTH_BOTH;
}
}
-
+
AddSharedSec(list, id_type, ike_id, secret, authtype);
}
int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf);
int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name);
int getusersfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list,char const *compat_mode_str);
-void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
+void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
int default_client_authtype);
int rad_get_authtype(char *authtype_name);
int rad_get_client_authtype(char const *authtype);
ERROR(IKEv2_LOG_PREFIX "Can not open 'private_key_file' %s",i2->pkfile);
return -1;
}
-
+
break;
}
if(!i2->trusted) {
GenEapKeys(session,EAP_IKEv2_KEY_LEN);
set_mppe_keys(handler);
}
-
+
// keep sessions in memory, only reference cleared
ikev2_data->session=NULL;
}
if (!name) {
return 0;
}
-
+
/*
* MS-Length - MS-Value - 5.
*/
tlv_packet[17] = 2;
tlv_packet[18] = 0;
tlv_packet[19] = 0;
-
+
(tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 20);
tls_handshake_send(handler->request, tls_session);
return 1;
}
pairmemcpy(vp, data + total, (data_len - total));
-
+
total += vp->length;
pairinsert(&cursor, vp);
for (i = start; i < vp->length; i++) {
if ((total & 0x0f) == 0) {
fprintf(fr_log_fp, " PEAP tunnel data out %04x: ", (int) total);
- }
+ }
fprintf(fr_log_fp, "%02x ", vp->vp_octets[i]);
-
+
if ((total & 0x0f) == 0x0f) {
fprintf(fr_log_fp, "\n");
}
-
+
total++;
}
-
+
start = 0;
}
-
+
if ((total & 0x0f) != 0) {
fprintf(fr_log_fp, "\n");
}
* Send the EAP data, WITHOUT the header.
*/
(tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets + EAP_HEADER_LEN, vp->length - EAP_HEADER_LEN);
-
+
/*
* Send the rest of the EAP data.
*/
if ((debug_flag > 0) && fr_log_fp) {
fprintf(fr_log_fp, "} # server %s\n", fake->server);
-
+
RDEBUG("Final reply from tunneled session code %d",
fake->reply->code);
-
+
debug_pair_list(fake->reply->vps);
}
if ((debug_flag > 2) && fr_log_fp) {
for (i = 0; i < data_len; i++) {
if ((i & 0x0f) == 0) fprintf(fr_log_fp, " PEAP tunnel data in %02x: ", (int) i);
-
+
fprintf(fr_log_fp, "%02x ", data[i]);
-
+
if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
}
if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
switch (t->status) {
case PEAP_STATUS_TUNNEL_ESTABLISHED:
/* FIXME: should be no data in the buffer here, check & assert? */
-
+
if (SSL_session_reused(tls_session->ssl)) {
RDEBUG2("Skipping Phase2 because of session resumption");
t->session_resumption_state = PEAP_RESUMPTION_YES;
/* we're good, send success TLV */
t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
eappeap_success(handler, tls_session);
-
+
} else {
/* send an identity request */
t->session_resumption_state = PEAP_RESUMPTION_NO;
*/
t->username = pairmake(t, NULL, "User-Name", NULL, T_OP_EQ);
rad_assert(t->username != NULL);
-
+
t->username->vp_strvalue = p = talloc_array(t->username, char, data_len);
memcpy(p, data + 1, data_len - 1);
t->username->length = data_len - 1;
*/
if (t->session_resumption_state == PEAP_RESUMPTION_YES) {
RDEBUG2("Client rejected session resumption. Re-starting full authentication");
-
+
/*
* Mark session resumption status.
*/
t->status = PEAP_STATUS_INNER_IDENTITY_REQ_SENT;
t->session_resumption_state = PEAP_RESUMPTION_NO;
-
+
eappeap_identity(handler, tls_session);
return RLM_MODULE_HANDLED;
}
* sent an Identity packet yet; do so from the stored
* username and this will kick off the phase2 eap method
*/
-
+
case PEAP_STATUS_PHASE2_INIT: {
size_t len = t->username->length + EAP_HEADER_LEN + 1;
uint8_t *q;
if ((debug_flag > 0) && fr_log_fp) {
RDEBUG("Got tunneled request");
-
+
debug_pair_list(fake->packet->vps);
fprintf(fr_log_fp, "server %s {\n",
(!fake->server) ? "" : fake->server);
RDEBUG("Got tunneled reply code %d", fake->reply->code);
-
+
debug_pair_list(fake->reply->vps);
}
if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
fake->server = vp->vp_strvalue;
-
+
} else if (inst->conf->virtual_server) {
fake->server = inst->conf->virtual_server;
-
+
} /* else fake->server == request->server */
-
+
if ((debug_flag > 0) && fr_log_fp) {
RDEBUG("Sending tunneled request");
-
+
debug_pair_list(fake->packet->vps);
-
+
fprintf(fr_log_fp, "server %s {\n",
(!fake->server) ? "" : fake->server);
}
-
+
/*
* Call authorization recursively, which will
* get the password.
*/
process_authorize(0, fake);
-
+
/*
* Note that we don't do *anything* with the reply
* attributes.
if ((debug_flag > 0) && fr_log_fp) {
fprintf(fr_log_fp, "} # server %s\n",
(!fake->server) ? "" : fake->server);
-
+
RDEBUG("Got tunneled reply code %d", fake->reply->code);
-
+
debug_pair_list(fake->reply->vps);
}
{
rlm_eap_tnc_t *inst;
TNC_Result result;
-
+
*instance = inst = talloc_zero(cs, rlm_eap_tnc_t);
if (!inst) return -1;
if (cf_section_parse(cs, inst, module_config) < 0) {
return -1;
}
-
+
result = initializeDefault();
if (result != TNC_RESULT_SUCCESS) {
ERROR("rlm_eap_tnc: NAA-EAP initializeDefault returned an "
"error code");
-
+
return -1;
}
static int mod_detach(void *instance)
{
TNC_Result result;
-
+
talloc_free(instance);
-
+
result = terminate();
if (result != TNC_RESULT_SUCCESS) {
ERROR("rlm_eap_tnc: NAA-EAP terminate returned an "
{
rlm_eap_tnc_t *inst = instance;
REQUEST *request = NULL;
-
+
char buff[71];
ssize_t len = 0;
-
+
TNC_Result result;
TNC_ConnectionID conn_id;
TNC_BufferReference eap_tnc_request;
TNC_BufferReference eap_tnc_user;
-
+
VALUE_PAIR *username;
/*
ERROR("rlm_eap_tnc: EAP_TNC must only be used as an "
"inner method within a protected tunneled EAP created "
"by an outer EAP method");
-
+
return 0;
}
-
+
request = handler->request->parent;
/*
* so not safe to use talloc.
*/
MEM(eap_tnc_user = (TNC_BufferReference) strdup(username->vp_strvalue));
-
+
result = storeUsername(conn_id, eap_tnc_user, username->length);
if (result != TNC_RESULT_SUCCESS) {
ERROR("rlm_eap_tnc: NAA-EAP storeUsername returned an "
handler->eap_ds->request->code = PW_EAP_REQUEST;
handler->eap_ds->request->type.num = PW_EAP_TNC;
-
+
handler->eap_ds->request->type.length = 1;
-
+
talloc_free(handler->eap_ds->request->type.data);
handler->eap_ds->request->type.data = eap_tnc_request;
-
+
/*
* We don't need to authorize the user at this point.
*
{
TNC_ConnectionID conn_id;
TNC_Result result;
-
+
TNC_BufferReference data = NULL;
TNC_UInt32 datalen = 0;
-
+
TNC_ConnectionState connection_state;
uint8_t code = 0;
REQUEST *request = handler->request;
-
+
if (handler->eap_ds->response->type.num != PW_EAP_TNC) {
ERROR("rlm_eap_tnc: Incorrect response type");
switch (connection_state) {
case TNC_CONNECTION_STATE_HANDSHAKE:
code = PW_EAP_REQUEST;
-
+
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
code = PW_EAP_FAILURE;
pairmake_config("TNC-Status", "None", T_OP_SET);
-
+
break;
-
+
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
code = PW_EAP_SUCCESS;
pairmake_config("TNC-Status", "Access", T_OP_SET);
break;
-
+
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
code = PW_EAP_SUCCESS;
pairmake_config("TNC-Status", "Isolate", T_OP_SET);
-
+
break;
default:
ERROR("rlm_eap_tnc: Invalid connection state");
-
+
return 0;
}
*/
handler->eap_ds->request->code = code;
handler->eap_ds->request->type.num = PW_EAP_TNC;
-
+
handler->eap_ds->request->type.length = datalen;
-
+
talloc_free(handler->eap_ds->request->type.data);
/*
VALUE_PAIR *vp;
RADIUS_PACKET *packet = fake->packet; /* FIXME: api issues */
vp_cursor_t out;
-
+
paircursor(&out, &first);
-
+
while (data_left > 0) {
rad_assert(data_left <= data_len);
memcpy(&attr, data, sizeof(attr));
* some other module takes care of any attribute
* with the M bit set.
*/
-
+
/*
* Get the length.
*/
eapttls_gen_challenge(ssl, challenge,
sizeof(challenge));
-
+
if (memcmp(challenge, vp->vp_octets,
vp->length) != 0) {
RDEBUG("Tunneled challenge is incorrect");
if ((debug_flag > 0) && fr_log_fp) {
fprintf(fr_log_fp, "} # server %s\n",
(!fake->server) ? "" : fake->server);
-
+
RDEBUG("Final reply from tunneled session code %d",
fake->reply->code);
debug_pair_list(fake->reply->vps);
if (t->copy_request_to_tunnel) {
VALUE_PAIR *copy;
vp_cursor_t cursor;
-
+
for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) {
/*
* The attribute is a server-side thingy,
(!fake->server) ? "" : fake->server);
RDEBUG("Got tunneled reply code %d", fake->reply->code);
-
+
debug_pair_list(fake->reply->vps);
}
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
rlm_example_t *inst = instance;
-
+
/*
* Do more work here
*/
{ "output_pairs", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,output), NULL, NULL },
{ "packet_type", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,packet_type), NULL, NULL },
{ "shell_escape", PW_TYPE_BOOLEAN, offsetof(rlm_exec_t,shell_escape), NULL, "yes" },
-
+
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
if (status < 0) {
return RLM_MODULE_FAIL;
}
-
+
/*
- * Exec'd programs are meant to return exit statuses that correspond
- * to the standard RLM_MODULE_* + 1.
+ * Exec'd programs are meant to return exit statuses that correspond
+ * to the standard RLM_MODULE_* + 1.
*
* This frees up 0, for success where it'd normally be reject.
- */
+ */
if (status == 0) {
RDEBUG("Program executed successfully");
- return RLM_MODULE_OK;
+ return RLM_MODULE_OK;
}
if (status > RLM_MODULE_NUMCODES) {
if (status == RLM_MODULE_FAIL) {
fail:
-
+
if (len > 0) {
char *p = &answer[len - 1];
-
+
/*
* Trim off trailing returns
*/
while((p > answer) && ((*p == '\r') || (*p == '\n'))) {
*p-- = '\0';
}
-
+
module_failure_msg(request, "%s", answer);
}
return RLM_MODULE_FAIL;
}
- return status;
+ return status;
}
/*
return -1;
}
}
-
+
/*
* FIXME: Do xlat of program name?
*/
out[0] = '\0';
return -1;
}
-
+
for (p = out; *p != '\0'; p++) {
if (*p < ' ') *p = ' ';
}
}
xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);
-
+
/*
* Check whether program actually exists
*/
-
+
if (inst->input) {
p = inst->input;
inst->input_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
#endif
)) {
RDEBUG2("Packet type is not %s. Not executing.", inst->packet_type);
-
+
return RLM_MODULE_NOOP;
}
return RLM_MODULE_INVALID;
}
}
-
+
if (inst->output) {
output_pairs = radius_list(request, inst->output_list);
if (!output_pairs) {
pairmove(request, output_pairs, &answer);
}
pairfree(&answer);
-
+
return rcode;
}
if (!inst->program) {
return RLM_MODULE_NOOP;
}
-
+
rcode = exec_dispatch(instance, request);
goto finish;
}
*/
pairmove(request->reply, &request->reply->vps, &tmp);
pairfree(&tmp);
-
+
finish:
switch (rcode) {
case RLM_MODULE_FAIL:
{
rlm_exec_t *inst = (rlm_exec_t *) instance;
int status;
-
+
char out[1024];
bool we_wait = false;
VALUE_PAIR *vp;
if (!inst->bare) {
return exec_dispatch(instance, request);
}
-
+
vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
if (vp) {
we_wait = true;
if (!vp) {
return RLM_MODULE_NOOP;
}
-
+
status = radius_exec_program(request, vp->vp_strvalue, we_wait, inst->shell_escape,
out, sizeof(out),
request->packet->vps, NULL);
RDEBUG("Checking Expiration time: '%s'",check_item->vp_strvalue);
if (((time_t) check_item->vp_date) <= request->timestamp) {
REDEBUG("Account has expired [Expiration %s]", check_item->vp_strvalue);
-
+
return RLM_MODULE_USERLOCK;
}
/*
} else {
return RLM_MODULE_NOOP;
}
-
+
return RLM_MODULE_OK;
}
if (!request) {
return -1;
}
-
+
name = request->vp_strvalue;
#if 0 /* DEBUG */
if (ret != 0) {
return ret;
}
-
+
/*
* If Strip-User-Name == No, then don't do any more.
*/
char const *p;
unsigned int result;
size_t freespace = outlen;
-
+
if (outlen <= 1) return 0;
*out = '\0';
case 'c':
*out++ = 'a' + (result % 26);
break;
-
+
/*
* Uppercase letters
*/
case 'C':
*out++ = 'A' + (result % 26);
break;
-
+
/*
* Numbers
*/
case 'n':
*out++ = '0' + (result % 10);
break;
-
+
/*
* Alpha numeric
*/
case 'a':
*out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
break;
-
+
/*
* Punctuation
*/
case '!':
*out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
break;
-
+
/*
* Alpa numeric + punctuation
*/
case '.':
*out++ = '!' + (result % 95);
break;
-
+
/*
* Alpha numeric + salt chars './'
- */
+ */
case 's':
*out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
break;
-
+
/*
* Binary data as hexits (we don't really support
* non printable chars).
if (freespace < 2) {
break;
}
-
+
snprintf(out, 3, "%02x", result % 256);
-
+
/* Already decremented */
freespace -= 1;
out += 2;
break;
-
+
default:
ERROR("rlm_expr: invalid character class '%c'", *p);
-
+
return -1;
}
-
+
p++;
}
-
+
*out++ = '\0';
-
+
return outlen - freespace;
}
{
char const *p;
size_t freespace = outlen;
-
+
if (outlen <= 1) return 0;
p = fmt;
default:
if (freespace < 3)
break;
-
+
snprintf(out, 4, "%%%02x", *p++); /* %xx */
-
+
/* Already decremented */
freespace -= 2;
out += 3;
rlm_expr_t *inst = instance;
char const *p;
size_t freespace = outlen;
-
+
if (outlen <= 1) return 0;
p = fmt;
*out++ = *p++;
continue;
}
-
+
if (freespace < 3)
break;
snprintf(out, 4, "=%02X", *p++);
-
+
/* Already decremented */
freespace -= 2;
out += 3;
}
-
+
*out = '\0';
-
+
return outlen - freespace;
}
char const *p;
if (outlen <= 1) return 0;
-
+
for (p = fmt, q = out; *p != '\0'; p++, outlen--) {
if (outlen <= 1) break;
uint8_t digest[16];
int i, len;
FR_MD5_CTX ctx;
-
+
/*
* We need room for at least one octet of output.
*/
ssize_t len;
len = strlen(fmt);
-
+
/*
* We can accurately calculate the length of the output string
* if it's larger than outlen, the output would be useless so abort.
*out = '\0';
return -1;
}
-
+
return fr_base64_encode((const uint8_t *) fmt, len, out, outlen);
}
*/
static ssize_t base64_to_hex_xlat(UNUSED void *instance, UNUSED REQUEST *request,
char const *fmt, char *out, size_t outlen)
-{
+{
uint8_t decbuf[1024], *p;
-
+
ssize_t declen;
size_t freespace = outlen;
ssize_t len = strlen(fmt);
*out = '\0';
-
+
declen = fr_base64_decode(fmt, len, decbuf, sizeof(decbuf));
if (declen < 0) {
REDEBUG("Base64 string invalid");
return -1;
}
-
+
p = decbuf;
while ((declen-- > 0) && (--freespace > 0)) {
if (freespace < 3) {
}
snprintf(out, 3, "%02x", *p++);
-
+
/* Already decremented */
freespace -= 1;
out += 2;
(vp->da->attr != PW_HINT) &&
(vp->da->attr != PW_HUNTGROUP_NAME)) {
DEBUG("\tChanging '%s =' to '%s +='", vp->da->name, vp->da->name);
-
+
vp->op = T_OP_ADD;
} else {
DEBUG("\tChanging '%s =' to '%s =='", vp->da->name, vp->da->name);
-
+
vp->op = T_OP_CMP_EQ;
}
}
if (len < 0) {
return RLM_MODULE_FAIL;
}
-
+
name = len ? buffer : "NONE";
}
{
rlm_files_t *inst = instance;
- return file_common(inst, request, "users",
+ return file_common(inst, request, "users",
inst->users ? inst->users : inst->common,
request->packet->vps, &request->reply->vps);
}
{
rlm_files_t *inst = instance;
- return file_common(inst, request, "acct_users",
+ return file_common(inst, request, "acct_users",
inst->acctusers ? inst->acctusers : inst->common,
request->packet->vps, &request->reply->vps);
}
int allow_unassigned;
} rlm_idn_t;
-/*
+/*
* The primary use case for this module is DNS-safe encoding of realms
* appearing in requests for a DDDS scheme. Some notes on that usage
* scenario:
* A mapping of configuration file names to internal variables.
*/
static const CONF_PARSER mod_config[] = {
- /*
+ /*
* If a STRINGPREP profile other than NAMEPREP is ever desired,
* we can implement an option, and it will default to NAMEPREP settings.
* ...and if we want raw punycode or to tweak Bootstring parameters,
{"allow_unassigned", PW_TYPE_BOOLEAN, offsetof(rlm_idn_t, allow_unassigned), NULL, "no" },
{"use_std3_ascii_rules", PW_TYPE_BOOLEAN, offsetof(rlm_idn_t, use_std3_ascii_rules), NULL, "yes" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
if (inst->allow_unassigned) {
flags |= IDNA_ALLOW_UNASSIGNED;
}
-
+
res = idna_to_ascii_8z(fmt, &idna, flags);
if (res) {
- if (idna) {
+ if (idna) {
free (idna); /* Docs unclear, be safe. */
}
if (!((len < (freespace - 1)) && (len <= 253))) {
/* Never provide a truncated result, as it may be queried. */
REDEBUG("Conversion was truncated");
-
+
free(idna);
return -1;
strlcpy(out, idna, freespace);
free(idna);
-
+
return len;
}
{ "range-start", PW_TYPE_IPADDR | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,range_start), NULL, NULL },
{ "range_start", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_start), NULL, "0" },
-
+
{ "range-stop", PW_TYPE_IPADDR | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,range_stop), NULL, NULL },
{ "range_stop", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_stop), NULL, "0" },
{ "maximum-timeout", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,max_timeout), NULL, NULL },
{ "maximum_timeout", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,max_timeout), NULL, "0" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
int attr_ipaddr = PW_FRAMED_IP_ADDRESS;
int attr_ipmask = PW_FRAMED_IP_NETMASK;
int vendor_ipaddr = 0;
-
+
/* Check if Pool-Name attribute exists. If it exists check our name and
* run only if they match
*/
if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
return RLM_MODULE_NOOP;
}
-
+
fr_MD5Init(&md5_context);
fr_MD5Update(&md5_context, (uint8_t *)xlat_str, strlen(xlat_str));
fr_MD5Final(key_str, &md5_context);
void addip(char *sessiondbname, char *indexdbname, char *ipaddress,
char *NASname, char *NASport, int old);
-
+
void viewdb(char *sessiondbname, char *indexdbname, char *ipaddress, int old);
void tonewformat(char *sessiondbname, char *newsessiondbname);
GDBM_FILE indexdb;
datum key_datum, data_datum, save_datum;
datum nextkey;
-
+
ippool_key key;
old_ippool_key old_key;
-
+
ippool_info entry;
struct in_addr ipaddr;
uint8_t key_str[17];
FR_MD5_CTX md5_context;
snprintf(md5_input_str, MAX_STRING_LEN, "%s %s", NASname, NASport);
-
+
fr_MD5Init(&md5_context);
fr_MD5Update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str));
fr_MD5Final(key_str, &md5_context);
-
+
memcpy(key.key, key_str, 16);
fr_bin2hex(key_str, hex_str, 16);
hex_str[32] = '\0';
if (data_datum.dptr != NULL){
found = 1;
memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
-
+
if (entry.active){
if (old) {
printf("rlm_ippool_tool: Deleting stale entry for ip/port %s/%u",
} else {
printf("rlm_ippool_tool: Deleting stale entry for key: '%s'", hex_str);
}
-
+
entry.active = 0;
save_datum.dptr = key_datum.dptr;
save_datum.dsize = key_datum.dsize;
key_datum.dptr = (char *) &entry.ipaddr;
key_datum.dsize = sizeof(uint32_t);
data_datum = gdbm_fetch(indexdb, key_datum);
-
+
if (data_datum.dptr != NULL) {
memcpy(&num, data_datum.dptr, sizeof(int));
-
+
if (num > 0) {
num--;
data_datum.dptr = (char *) #
data_datum.dsize = sizeof(int);
rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
-
+
if (rcode < 0) {
printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
indexdbname, gdbm_strerror(gdbm_errno));
goto close;
}
-
+
if (num > 0 && entry.extra == 1) {
gdbm_delete(sessiondb, save_datum);
}
if (!key_datum.dptr) {
key_datum = gdbm_firstkey(sessiondb);
-
+
while (key_datum.dptr) {
data_datum = gdbm_fetch(sessiondb, key_datum);
if (data_datum.dptr != NULL) {
datum key_datum_tmp, data_datum_tmp;
old_ippool_key old_key_tmp;
ippool_key key_tmp;
-
+
if (old){
strlcpy(old_key_tmp.nas, NASname,
sizeof(old_key_tmp.nas));
key_datum_tmp.dptr = (char *) &key_tmp;
key_datum_tmp.dsize = sizeof(ippool_key);
}
-
+
data_datum_tmp = gdbm_fetch(sessiondb, key_datum_tmp);
if (data_datum_tmp.dptr != NULL) {
rcode = gdbm_store(sessiondb, key_datum, data_datum_tmp, GDBM_REPLACE);
gdbm_delete(sessiondb, key_datum);
}
}
-
+
free(key_datum.dptr);
entry.active = 1;
-
+
data_datum.dptr = (char *) &entry;
data_datum.dsize = sizeof(ippool_info);
key_datum.dsize = sizeof(ippool_key);
printf("rlm_ippool_tool: Allocating ip to key: '%s'\n", hex_str);
}
-
+
rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
} else {
num = 0;
}
-
+
num++;
printf("rlm_ippool_tool: num: %d\n", num);
data_datum.dptr = (char *) #
data_datum.dsize = sizeof(int);
-
+
rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
indexdbname, gdbm_strerror(gdbm_errno));
-
+
goto close;
}
printf("rlm_ippool_tool: Allocated ip %s to key '%s'\n", ipaddress, hex_str);
}
}
-
+
close:
gdbm_close(indexdb);
gdbm_close(sessiondb);
key_datum = gdbm_firstkey(sessiondb);
while (key_datum.dptr) {
keynext_datum = gdbm_nextkey(sessiondb, key_datum);
-
+
if (key_datum.dsize != sizeof(struct old_ippool_key)) {
goto next;
}
-
+
char md5_input_str[MAX_STRING_LEN];
FR_MD5_CTX md5_context;
memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key));
-
+
snprintf(md5_input_str, MAX_STRING_LEN, "%s %d", old_key.nas, old_key.port);
-
+
fr_MD5Init(&md5_context);
fr_MD5Update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str));
fr_MD5Final(key_str, &md5_context);
-
+
memcpy(key.key, key_str, 16);
fr_bin2hex(key_str, hex_str, 16);
hex_str[32] = '\0';
-
+
printf("rlm_ippool_tool: Transforming pair nas/port (%s/%d) to md5 '%s'\n",
old_key.nas, old_key.port, hex_str);
-
+
newkey_datum.dptr = (char *) &key;
newkey_datum.dsize = sizeof(ippool_key);
data_datum = gdbm_fetch(sessiondb, key_datum);
-
+
if (!data_datum.dptr) {
goto next;
}
-
+
rcode = gdbm_store(newsessiondb, newkey_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
printf("Failed to update new file %s: %s\n", newsessiondbname, gdbm_strerror(gdbm_errno));
next:
key_datum = keynext_datum;
}
-
+
gdbm_close(newsessiondb);
gdbm_close(sessiondb);
}
if ((!sessiondb) || (!indexdb)) {
return;
}
-
+
memset(key_str, 0,17);
key_datum = gdbm_firstkey(sessiondb);
while (key_datum.dptr) {
keynext_datum = gdbm_nextkey(sessiondb, key_datum);
-
+
if ((key_datum.dsize != sizeof(struct ippool_key)) &&
(key_datum.dsize != sizeof(struct old_ippool_key))) {
goto next;
}
-
+
if (old) {
memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key));
} else {
memcpy(&key, key_datum.dptr, sizeof(struct ippool_key));
}
-
+
data_datum = gdbm_fetch(sessiondb, key_datum);
if (!data_datum.dptr) {
goto next;
}
-
+
memcpy(&info, data_datum.dptr, sizeof(struct ippool_info));
memcpy(&ipaddr, &info.ipaddr, 4);
ip = inet_ntoa(ipaddr);
if (info.active) active++;
-
+
if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
if (old) {
printf("NAS:%s port:0x%x - ", old_key.nas, old_key.port);
printf("KEY: '%s' - ", hex_str);
}
}
-
+
if (!vflag && aflag && info.active && MATCH_IP(ipaddress, ip)) {
printf("%s\n", ip);
} else if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
save_datum.dsize = key_datum.dsize;
data_datum.dptr = (char *) &info;
data_datum.dsize = sizeof(ippool_info);
-
+
rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno));
gdbm_close(sessiondb);
return;
}
-
+
key_datum.dptr = (char *)&info.ipaddr;
key_datum.dsize = sizeof(uint32_t);
data_datum = gdbm_fetch(indexdb, key_datum);
-
+
if (data_datum.dptr != NULL) {
memcpy(&num, data_datum.dptr, sizeof(int));
if (num > 0) {
data_datum.dptr = (char *) #
data_datum.dsize = sizeof(int);
rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
-
+
if (rcode < 0) {
printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno));
gdbm_close(indexdb);
gdbm_close(sessiondb);
return;
}
-
+
if (num > 0 && info.extra == 1) {
gdbm_delete(sessiondb, save_datum);
}
key_datum.dptr = (char *)&info.ipaddr;
key_datum.dsize = sizeof(uint32_t);
data_datum = gdbm_fetch(indexdb, key_datum);
-
+
if (data_datum.dptr!= NULL) {
memcpy(&num, data_datum.dptr, sizeof(int));
-
+
if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
printf(" num:%d", num);
}
}
-
+
if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
printf("\n");
} else if (vflag && !ipaddress){
printf("KEY: '%s' - ", hex_str);
}
}
-
+
next:
- key_datum = keynext_datum;
+ key_datum = keynext_datum;
}
-
+
gdbm_close(indexdb);
gdbm_close(sessiondb);
}
usage(argv0);
}
}
-
+
return 0;
}
char const *keytabname; //!< The keytab to resolve the service in.
char const *service_princ; //!< The service name provided by the
//!< config parser.
-
+
char *hostname; //!< The hostname component of
//!< service_princ, or NULL.
char *service; //!< The service component of service_princ, or NULL.
-
+
krb5_context context; //!< The kerberos context (cloned once per request).
-
+
#ifndef HEIMDAL_KRB5
krb5_get_init_creds_opt *gic_options; //!< Options to pass to the get_initial_credentials
//!< function.
krb5_principal server; //!< A structure representing the parsed
//!< service_princ.
#endif
-
+
} rlm_krb5_t;
static const CONF_PARSER module_config[] = {
static int krb5_detach(void *instance)
{
rlm_krb5_t *inst = instance;
-
+
#ifndef HEIMDAL_KRB5
talloc_free(inst->vic_options);
/* Don't free hostname, it's just a pointer into service_princ */
talloc_free(inst->service);
-
+
if (inst->context) {
krb5_free_context(inst->context);
}
if (!inst->xlat_name) {
inst->xlat_name = cf_section_name1(conf);
}
-
+
ret = krb5_init_context(&inst->context);
if (ret) {
EDEBUG("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name, error_message(ret));
return -1;
}
-
+
DEBUG("rlm_krb5 (%s): Context initialised successfully", inst->xlat_name);
/*
size_t len;
/* Service principal appears to contain a host component */
inst->hostname = strchr(inst->service_princ, '/');
- if (inst->hostname) {
- len = (inst->hostname - inst->service_princ);
+ if (inst->hostname) {
+ len = (inst->hostname - inst->service_princ);
inst->hostname++;
} else {
len = strlen(inst->service_princ);
}
-
+
if (len) {
inst->service = talloc_array(inst, char, (len + 1));
strlcpy(inst->service, inst->service_princ, len + 1);
}
}
-
+
#ifdef HEIMDAL_KRB5
if (inst->hostname) {
DEBUG("rlm_krb5 (%s): Ignoring hostname component of service principal \"%s\", not "
return -1;
}
-
+
ret = krb5_unparse_name(inst->context, inst->server, &princ_name);
if (ret) {
/* Uh? */
return -1;
}
-
+
/*
* Not necessarily the same as the config item
*/
DEBUG("rlm_krb5 (%s): Using service principal \"%s\"", inst->xlat_name, princ_name);
-
+
krb5_free_unparsed_name(inst->context, princ_name);
-
+
/*
* Setup options for getting credentials and verifying them
*/
-
+
/* For some reason the 'init' version of this function is deprecated */
ret = krb5_get_init_creds_opt_alloc(inst->context, &(inst->gic_options));
if (ret) {
EDEBUG("rlm_krb5 (%s): Couldn't allocated inital credential options: %s", inst->xlat_name,
error_message(ret));
-
+
return -1;
}
krb5_kt_default(inst->context, &keytab);
if (ret) {
EDEBUG("rlm_krb5 (%s): Resolving keytab failed: %s", inst->xlat_name, error_message(ret));
-
+
return -1;
}
ret = krb5_kt_get_name(inst->context, keytab, keytab_name, sizeof(keytab_name));
krb5_kt_close(inst->context, keytab);
if (ret) {
- EDEBUG("rlm_krb5 (%s): Can't retrieve keytab name: %s", inst->xlat_name, error_message(ret));
-
+ EDEBUG("rlm_krb5 (%s): Can't retrieve keytab name: %s", inst->xlat_name, error_message(ret));
+
return -1;
}
-
+
DEBUG("rlm_krb5 (%s): Using keytab \"%s\"", inst->xlat_name, keytab_name);
-
+
MEM(inst->vic_options = talloc_zero(inst, krb5_verify_init_creds_opt));
-
+
krb5_verify_init_creds_opt_init(inst->vic_options);
krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, true);
-
+
#endif
-
+
return 0;
}
{
krb5_error_code ret;
char *princ_name;
-
+
/*
* We can only authenticate user requests which HAVE
* a User-Name attribute.
*/
if (!request->username) {
REDEBUG("Attribute \"User-Name\" is required for authentication");
-
+
return RLM_MODULE_INVALID;
}
*/
if (!request->password) {
REDEBUG("Attribute \"User-Password\" is required for authentication");
-
+
return RLM_MODULE_INVALID;
}
if (request->password->da->attr != PW_USER_PASSWORD) {
REDEBUG("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".",
request->password->da->name);
-
+
return RLM_MODULE_INVALID;
}
-
+
ret = krb5_parse_name(context, request->username->vp_strvalue, client);
if (ret) {
REDEBUG("Failed parsing username as principal: %s", error_message(ret));
-
+
return RLM_MODULE_FAIL;
}
{
rlm_krb5_t *inst = instance;
rlm_rcode_t rcode;
-
+
krb5_error_code ret;
-
+
krb5_principal client;
krb5_ccache ccache;
krb5_keytab keytab;
krb5_verify_opt options;
krb5_context context;
-
+
rad_assert(inst->context);
#ifdef KRB5_IS_THREAD_SAFE
ret = krb5_copy_context(inst->context, &context);
if (ret) {
REDEBUG("Error cloning krb5 context: %s", error_message(ret));
-
+
return RLM_MODULE_FAIL;
}
#else
memset(&keytab, 0, sizeof(keytab));
memset(&client, 0, sizeof(client));
memset(&init_creds, 0, sizeof(init_creds));
-
+
/*
* Setup krb5_verify_user options
*
* the cloned context.
*/
krb5_cc_default(context, &ccache);
-
+
krb5_verify_opt_init(&options);
krb5_verify_opt_set_ccache(&options, ccache);
ret = inst->keytabname ?
krb5_kt_default(context, &keytab);
if (ret) {
REDEBUG("Resolving keytab failed: %s", error_message(ret));
-
+
goto cleanup;
}
-
+
krb5_verify_opt_set_keytab(&options, keytab);
krb5_verify_opt_set_secure(&options, true);
if (inst->service) {
krb5_verify_opt_set_service(&options, inst->service);
}
-
+
rcode = krb5_parse_user(request, context, &client);
if (rcode != RLM_MODULE_OK) goto cleanup;
case KRB5KRB_AP_ERR_BAD_INTEGRITY:
REDEBUG("Provided password was incorrect (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_REJECT;
-
+
break;
case KRB5KDC_ERR_KEY_EXP:
case KRB5KDC_ERR_CLIENT_REVOKED:
case KRB5KDC_ERR_SERVICE_REVOKED:
REDEBUG("Account has been locked out (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_USERLOCK;
-
+
break;
case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
RDEBUG("User not found: %s (%i)", ret, error_message(ret));
rcode = RLM_MODULE_NOTFOUND;
-
+
default:
REDEBUG("Error verifying credentials (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_FAIL;
-
+
break;
}
goto cleanup;
}
-
+
cleanup:
if (client) {
krb5_free_principal(context, client);
static rlm_rcode_t krb5_auth(void *instance, REQUEST *request)
{
rlm_krb5_t *inst = instance;
- rlm_rcode_t rcode;
+ rlm_rcode_t rcode;
krb5_error_code ret;
krb5_principal client;
krb5_keytab keytab; /* ktid */
krb5_context context;
char *password; /* compiler warnings */
-
+
rad_assert(inst->context);
-#ifdef KRB5_IS_THREAD_SAFE
+#ifdef KRB5_IS_THREAD_SAFE
/*
* All the snippets on threadsafety say that individual threads
* must each use their own copy of context.
ret = krb5_copy_context(inst->context, &context);
if (ret) {
REDEBUG("Error cloning krb5 context: %s", error_message(ret));
-
+
return RLM_MODULE_FAIL;
}
rad_assert(context != NULL); /* tell coverity copy context copies it */
krb5_kt_default(context, &keytab);
if (ret) {
REDEBUG("Resolving keytab failed: %s", error_message(ret));
-
+
goto cleanup;
}
-
+
/*
* Retrieve the TGT from the TGS/KDC and check we can decrypt it.
*/
REDEBUG("Provided password was incorrect (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_REJECT;
break;
-
+
case KRB5KDC_ERR_KEY_EXP:
case KRB5KDC_ERR_CLIENT_REVOKED:
case KRB5KDC_ERR_SERVICE_REVOKED:
REDEBUG("Account has been locked out (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_USERLOCK;
break;
-
+
case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
RDEBUG("User not found (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_NOTFOUND;
break;
-
+
default:
REDEBUG("Error retrieving or verifying credentials (%i): %s", ret, error_message(ret));
rcode = RLM_MODULE_FAIL;
goto cleanup;
}
-
+
RDEBUG("Successfully retrieved and decrypted TGT");
ret = krb5_verify_init_creds(context, &init_creds, inst->server, keytab, NULL, inst->vic_options);
if (keytab) {
krb5_kt_close(context, keytab);
}
-
+
krb5_free_cred_contents(context, &init_creds);
#ifdef KRB5_IS_THREAD_SAFE
krb5_free_context(context);
#endif
}
-
+
return rcode;
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file ldap.c
VALUE_PAIR *head = NULL, *vp;
vp_cursor_t cursor;
int i;
-
+
paircursor(&cursor, &head);
-
+
/*
* Iterate over all the retrieved values,
* don't try and be clever about changing operators
- * just use whatever was set in the attribute map.
+ * just use whatever was set in the attribute map.
*/
for (i = 0; i < self->count; i++) {
vp = pairalloc(request, map->dst->da);
if (!pairparsevalue(vp, self->values[i])) {
RDEBUG("Failed parsing value for \"%s\"", map->dst->da->name);
-
+
pairbasicfree(vp);
continue;
}
-
+
vp->op = map->op;
pairinsert(&cursor, vp);
}
-
+
*out = head;
-
- return 0;
+
+ return 0;
}
int rlm_ldap_map_verify(ldap_instance_t *inst, value_pair_map_t **head)
{
value_pair_map_t *map;
-
+
if (radius_attrmap(cf_section_sub_find(inst->cs, "update"),
head, PAIR_LIST_REPLY,
PAIR_LIST_REQUEST, LDAP_MAX_ATTRMAP) < 0) {
for (map = *head; map != NULL; map = map->next) {
if (map->dst->type != VPT_TYPE_ATTR) {
cf_log_err(map->ci, "Left operand must be an attribute ref");
-
+
return -1;
}
-
+
if (map->src->type == VPT_TYPE_LIST) {
cf_log_err(map->ci, "Right operand must not be a list");
-
+
return -1;
}
-
+
/*
* Be smart about whether we warn the user about missing passwords.
* If there are no password attributes in the mapping, then the user's either an idiot
fr_int2str(pair_lists, map->dst->list, "<invalid>"),
map->dst->da->name);
}
-
+
inst->expect_password = true;
default:
- break;
+ break;
}
}
-
+
switch (map->src->type) {
/*
* Only =, :=, += and -= operators are supported for
case T_OP_SUB:
case T_OP_ADD:
break;
-
+
default:
cf_log_err(map->ci, "Operator \"%s\" not allowed for %s values",
fr_int2str(fr_tokens, map->op, "<INVALID>"),
{
const value_pair_map_t *map;
unsigned int total = 0;
-
+
char const *name;
-
+
for (map = expanded->maps; map != NULL; map = map->next) {
name = expanded->attrs[total++];
if (!name) return;
-
+
switch (map->src->type) {
- case VPT_TYPE_XLAT:
+ case VPT_TYPE_XLAT:
case VPT_TYPE_ATTR:
rad_const_free(name);
break;
const value_pair_map_t *map;
unsigned int total = 0;
size_t len;
-
+
VALUE_PAIR *found, **from = NULL;
REQUEST *context;
case VPT_TYPE_XLAT:
{
char *exp = NULL;
-
- len = radius_xlat(exp, 0, request, map->src->name, NULL, NULL);
+
+ len = radius_xlat(exp, 0, request, map->src->name, NULL, NULL);
if (len <= 0) {
RDEBUG("Expansion of LDAP attribute \"%s\" failed", map->src->name);
-
+
goto error;
}
-
+
expanded->attrs[total++] = exp;
break;
}
case VPT_TYPE_ATTR:
context = request;
-
+
if (radius_request(&context, map->src->request) == 0) {
from = radius_list(context, map->src->list);
}
if (!from) continue;
-
+
found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
if (!found) continue;
-
+
expanded->attrs[total++] = talloc_strdup(request, found->vp_strvalue);
break;
-
+
case VPT_TYPE_LITERAL:
expanded->attrs[total++] = map->src->name;
break;
rad_assert(0);
error:
expanded->attrs[total] = NULL;
-
+
rlm_ldap_map_xlat_free(expanded);
-
+
return -1;
}
-
+
}
-
+
rad_assert(total < LDAP_MAX_ATTRMAP);
-
+
expanded->attrs[total] = NULL;
expanded->count = total;
expanded->maps = maps;
-
+
return 0;
}
/** Convert attribute map into valuepairs
*
- * Use the attribute map built earlier to convert LDAP values into valuepairs and insert them into whichever
+ * Use the attribute map built earlier to convert LDAP values into valuepairs and insert them into whichever
* list they need to go into.
*
* This is *NOT* atomic, but there's no condition for which we should error out...
{
const value_pair_map_t *map;
unsigned int total = 0;
-
+
rlm_ldap_result_t result;
char const *name;
for (map = expanded->maps; map != NULL; map = map->next) {
name = expanded->attrs[total++];
-
+
result.values = ldap_get_values(handle, entry, name);
if (!result.values) {
RDEBUG2("Attribute \"%s\" not found in LDAP object", name);
-
+
goto next;
}
-
+
/*
* Find out how many values there are for the
* attribute and extract all of them.
*/
result.count = ldap_count_values(result.values);
-
+
/*
* If something bad happened, just skip, this is probably
* a case of the dst being incorrect for the current
if (radius_map2request(request, map, name, rlm_ldap_map_getvalue, &result) == -1) {
return; /* Fail */
}
-
+
next:
-
+
ldap_value_free(result.values);
}
-
+
/*
* Retrieve any valuepair attributes from the result, these are generic values specifying
* a radius list, operator and value.
if (inst->valuepair_attr) {
char **values;
int count, i;
-
+
values = ldap_get_values(handle, entry, inst->valuepair_attr);
count = ldap_count_values(values);
-
+
for (i = 0; i < count; i++) {
if (radius_str2vp(request, values[i], REQUEST_CURRENT, PAIR_LIST_REPLY) < 0) {
RWDEBUG("Failed parsing '%s' value \"%s\" as valuepair, skipping...",
inst->valuepair_attr, values[i]);
}
}
-
+
ldap_value_free(values);
}
}
/** Search for and apply an LDAP profile
- *
+ *
* LDAP profiles are mapped using the same attribute map as user objects, they're used to add common sets of attributes
* to the request.
*
int ldap_errno;
LDAP *handle = (*pconn)->handle;
char filter[LDAP_MAX_FILTER_STR_LEN];
-
+
rad_assert(inst->profile_filter); /* We always have a default filter set */
if (!dn || !*dn) {
default:
return RLM_MODULE_FAIL;
}
-
+
rad_assert(*pconn);
rad_assert(result);
-
+
entry = ldap_first_entry(handle, result);
if (!entry) {
ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
+
rcode = RLM_MODULE_NOTFOUND;
-
+
goto free_result;
}
-
+
rlm_ldap_map_do(inst, request, handle, expanded, entry);
free_result:
ldap_msgfree(result);
-
+
return rcode;
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file clients.c
int ret = 0;
ldap_rcode_t status;
ldap_handle_t *conn = NULL;
-
+
/* This needs to be updated if additional attributes need to be retrieved */
char const *attrs[7];
char const **attrs_p;
-
+
LDAPMessage *result = NULL;
LDAPMessage *entry;
-
+
RADCLIENT *c;
LDAP_DBG("Loading dynamic clients");
*/
if (!inst->clientobj_identifier) {
LDAP_ERR("Told to load clients but 'client.identifier_attribute' not specified");
-
+
return -1;
}
-
+
if (!inst->clientobj_secret) {
LDAP_ERR("Told to load clients but 'client.secret_attribute' not specified");
-
+
return -1;
}
-
+
if (!inst->clientobj_base_dn) {
LDAP_ERR("Told to load clients but 'client.base_dn' not specified");
-
+
return -1;
}
-
+
if (!inst->clientobj_filter) {
LDAP_ERR("Told to load clients but 'client.filter' not specified");
-
+
return -1;
}
attrs[0] = inst->clientobj_identifier;
attrs[1] = inst->clientobj_secret;
attrs_p = attrs + 2;
-
+
if (inst->clientobj_shortname) { /* 2 */
*attrs_p++ = inst->clientobj_shortname;
}
-
+
if (inst->clientobj_type) { /* 3 */
*attrs_p++ = inst->clientobj_type;
}
-
+
if (inst->clientobj_server) { /* 4 */
*attrs_p++ = inst->clientobj_server;
}
-
+
if (inst->clientobj_require_ma) { /* 5 */
*attrs_p++ = inst->clientobj_require_ma;
}
-
+
*attrs_p = NULL; /* 6 - array needs to be NULL terminated */
conn = rlm_ldap_get_socket(inst, NULL);
if (!conn) return -1;
-
+
/*
* Perform all searches as the admin user.
*/
}
rad_assert(conn);
-
+
conn->rebound = false;
}
default:
return -1;
}
-
+
rad_assert(conn);
entry = ldap_first_entry(conn->handle, result);
if (!entry) {
int ldap_errno;
-
+
ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
- ret = -1;
+
+ ret = -1;
goto finish;
}
-
+
do {
char *dn;
char **identifier = NULL;
char **type = NULL;
char **server = NULL;
char **require_ma = NULL;
-
+
dn = ldap_get_dn(conn->handle, entry);
-
+
/*
* Check for the required attributes first
*/
LDAP_WARN("Client \"%s\" missing required attribute 'identifier', skipping...", dn);
goto next;
}
-
+
secret = ldap_get_values(conn->handle, entry, inst->clientobj_secret);
if (!secret) {
LDAP_WARN("Client \"%s\" missing required attribute 'secret', skipping...", dn);
goto next;
}
-
+
if (inst->clientobj_shortname) {
shortname = ldap_get_values(conn->handle, entry, inst->clientobj_shortname);
if (!shortname) {
LDAP_DBG("Client \"%s\" missing optional attribute 'shortname'", dn);
}
}
-
+
if (inst->clientobj_type) {
type = ldap_get_values(conn->handle, entry, inst->clientobj_type);
if (!type) {
LDAP_DBG("Client \"%s\" missing optional attribute 'type'", dn);
}
}
-
+
if (inst->clientobj_server) {
server = ldap_get_values(conn->handle, entry, inst->clientobj_server);
if (!server) {
LDAP_DBG("Client \"%s\" missing optional attribute 'server'", dn);
}
}
-
+
if (inst->clientobj_require_ma) {
require_ma = ldap_get_values(conn->handle, entry, inst->clientobj_require_ma);
if (!require_ma) {
LDAP_DBG("Client \"%s\" missing optional attribute 'require_ma'", dn);
}
}
-
+
/* FIXME: We should really pass a proper ctx */
c = client_from_query(NULL,
identifier[0],
if (!c) {
goto next;
}
-
+
if (!client_add(NULL, c)) {
WARN("Failed to add client, possible duplicate?");
client_free(c);
goto next;
}
-
+
LDAP_DBG("Client \"%s\" added", dn);
-
+
next:
ldap_memfree(dn);
if (identifier) ldap_value_free(identifier);
if (type) ldap_value_free(type);
if (server) ldap_value_free(server);
} while((entry = ldap_next_entry(conn->handle, entry)));
-
+
finish:
if (result) {
ldap_msgfree(result);
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file edir.c
#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
#define NMAS_LDAP_EXT_VERSION 1
-
+
/** Takes the object DN and BER encodes the data into the BER value which is used as part of the request
*
@verbatim
err = NMAS_E_FRAG_FAILURE;
goto finish;
}
-
+
finish:
if(reply_ber) ber_free(reply_ber, 1);
if (reply_bv) {
ber_bvfree(reply_bv);
}
-
+
/* Free the return OID string if one was returned. */
if (reply_oid) {
ldap_memfree(reply_oid);
}
-
+
/* Free memory allocated while building the request ber and berval. */
if (request_bv) {
ber_bvfree(request_bv);
}
-
+
return err;
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file groups.c
#include "ldap.h"
/** Convert multiple group names into a DNs
- *
+ *
* Given an array of group names, builds a filter matching all names, then retrieves all group objects
* and stores the DN associated with each group object.
*
rlm_rcode_t rcode = RLM_MODULE_OK;
ldap_rcode_t status;
int ldap_errno;
-
+
unsigned int name_cnt = 0;
unsigned int entry_cnt;
char const *attrs[] = { NULL };
char **name = names;
char **dn = out;
char buffer[LDAP_MAX_GROUP_NAME_LEN + 1];
-
+
char *filter;
-
+
*dn = NULL;
-
+
if (!*names) {
return RLM_MODULE_OK;
}
-
+
if (!inst->groupobj_name_attr) {
REDEBUG("Told to convert group names to DNs but missing 'group.name_attribute' directive");
-
+
return RLM_MODULE_INVALID;
}
while (*name) {
rlm_ldap_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);
-
+
name_cnt++;
}
filter = talloc_asprintf_append_buffer(filter, "%s%s",
inst->groupobj_filter ? ")" : "",
names[0] && names[1] ? ")" : "");
-
+
status = rlm_ldap_search(inst, request, pconn, inst->groupobj_base_dn, inst->groupobj_scope,
filter, attrs, &result);
switch (status) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
-
+
entry_cnt = ldap_count_entries((*pconn)->handle, result);
if (entry_cnt > name_cnt) {
REDEBUG("Number of DNs exceeds number of names, group and/or dn should be more restrictive");
rcode = RLM_MODULE_INVALID;
-
+
goto finish;
}
-
+
if (entry_cnt > (outlen - 1)) {
REDEBUG("Number of DNs exceeds limit (%zu)", outlen - 1);
rcode = RLM_MODULE_INVALID;
-
+
goto finish;
}
-
+
if (entry_cnt < name_cnt) {
RWDEBUG("Got partial mapping of group names (%i) to DNs (%i), membership information may be incomplete",
name_cnt, entry_cnt);
}
-
+
entry = ldap_first_entry((*pconn)->handle, result);
if (!entry) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
- rcode = RLM_MODULE_FAIL;
+
+ rcode = RLM_MODULE_FAIL;
goto finish;
}
-
+
do {
- *dn++ = ldap_get_dn((*pconn)->handle, entry);
+ *dn++ = ldap_get_dn((*pconn)->handle, entry);
} while((entry = ldap_next_entry((*pconn)->handle, entry)));
-
+
*dn = NULL;
-
+
finish:
talloc_free(filter);
if (result) {
ldap_msgfree(result);
}
-
+
/*
* Be nice and cleanup the output array if we error out.
*/
while(*dn) ldap_memfree(*dn++);
*dn = NULL;
}
-
+
return rcode;
}
rlm_rcode_t rcode = RLM_MODULE_OK;
ldap_rcode_t status;
int ldap_errno;
-
+
char **vals = NULL;
char const *attrs[] = { inst->groupobj_name_attr, NULL };
LDAPMessage *result = NULL, *entry;
-
+
*out = NULL;
-
+
if (!inst->groupobj_name_attr) {
REDEBUG("Told to convert group DN to name but missing 'group.name_attribute' directive");
-
+
return RLM_MODULE_INVALID;
}
-
+
RDEBUG("Converting group DN to group Name");
-
+
status = rlm_ldap_search(inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs,
- &result);
+ &result);
switch (status) {
case LDAP_PROC_SUCCESS:
break;
case LDAP_PROC_NO_RESULT:
REDEBUG("DN \"%s\" did not resolve to an object", dn);
-
+
return RLM_MODULE_INVALID;
default:
return RLM_MODULE_FAIL;
}
-
+
entry = ldap_first_entry((*pconn)->handle, result);
if (!entry) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
- rcode = RLM_MODULE_INVALID;
+
+ rcode = RLM_MODULE_INVALID;
goto finish;
}
vals = ldap_get_values((*pconn)->handle, entry, inst->groupobj_name_attr);
if (!vals) {
REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);
-
+
rcode = RLM_MODULE_INVALID;
-
+
goto finish;
}
-
+
*out = talloc_strdup(request, vals[0]);
-
+
finish:
if (result) {
ldap_msgfree(result);
}
-
+
if (vals) {
- ldap_value_free(vals);
+ ldap_value_free(vals);
}
-
+
return rcode;
}
LDAPMessage *entry)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
-
+
char **vals;
char *group_name[LDAP_MAX_CACHEABLE + 1];
char *group_dn[LDAP_MAX_CACHEABLE + 1];
char **dn_p;
-
+
char *name;
int is_dn, i;
vals = ldap_get_values((*pconn)->handle, entry, inst->userobj_membership_attr);
if (!vals) {
RDEBUG2("No cacheable group memberships found in user object");
-
+
return RLM_MODULE_OK;
}
for (i = 0; (vals[i] != NULL) && (i < LDAP_MAX_CACHEABLE); i++) {
is_dn = rlm_ldap_is_dn(vals[i]);
-
+
if (inst->cacheable_group_dn) {
/*
* The easy case, were caching DNs and we got a DN.
if (is_dn) {
pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
-
+
/*
- * We were told to cache DNs but we got a name, we now need to resolve
+ * We were told to cache DNs but we got a name, we now need to resolve
* this to a DN. Store all the group names in an array so we can do one query.
*/
} else {
*name_p++ = vals[i];
}
}
-
+
if (inst->cacheable_group_name) {
/*
* The easy case, were caching names and we got a name.
pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
/*
- * We were told to cache names but we got a DN, we now need to resolve
+ * We were told to cache names but we got a DN, we now need to resolve
* this to a name.
- * Only Active Directory supports filtering on DN, so we have to search
+ * Only Active Directory supports filtering on DN, so we have to search
* for each individual group.
*/
} else {
rcode = rlm_ldap_group_dn2name(inst, request, pconn, vals[i], &name);
if (rcode != RLM_MODULE_OK) {
ldap_value_free(vals);
-
+
return rcode;
}
-
+
pairmake(request, &request->config_items, inst->group_da->name, name, T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, name);
talloc_free(name);
pairmake(request, &request->config_items, inst->group_da->name, *dn_p, T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, *dn_p);
ldap_memfree(*dn_p);
-
+
dn_p++;
}
-
+
return rcode;
}
rlm_rcode_t rcode = RLM_MODULE_OK;
ldap_rcode_t status;
int ldap_errno;
-
+
char **vals;
-
+
LDAPMessage *result = NULL;
LDAPMessage *entry;
char base_dn[LDAP_MAX_DN_STR_LEN];
-
+
char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
char filter[LDAP_MAX_FILTER_STR_LEN + 1];
-
+
char const *attrs[] = { inst->groupobj_name_attr, NULL };
-
+
char *dn;
if (!inst->groupobj_membership_filter) {
RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set");
-
+
return RLM_MODULE_OK;
}
-
+
if (rlm_ldap_xlat_filter(request,
filters, sizeof(filters) / sizeof(*filters),
filter, sizeof(filter)) < 0) {
if (radius_xlat(base_dn, sizeof(base_dn), request, inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
REDEBUG("Failed creating base_dn");
-
+
return RLM_MODULE_INVALID;
}
if (!entry) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
+
goto finish;
}
-
+
do {
if (inst->cacheable_group_dn) {
dn = ldap_get_dn((*pconn)->handle, entry);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, dn);
ldap_memfree(dn);
}
-
- if (inst->cacheable_group_name) {
+
+ if (inst->cacheable_group_name) {
vals = ldap_get_values((*pconn)->handle, entry, inst->groupobj_name_attr);
if (!vals) {
continue;
}
-
+
pairmake(request, &request->config_items, inst->group_da->name, *vals, T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, *vals);
-
+
ldap_value_free(vals);
- }
+ }
} while((entry = ldap_next_entry((*pconn)->handle, entry)));
-
+
finish:
if (result) {
ldap_msgfree(result);
}
-
+
return rcode;
}
*/
rlm_rcode_t rlm_ldap_check_groupobj_dynamic(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
VALUE_PAIR *check)
-
+
{
ldap_rcode_t status;
char base_dn[LDAP_MAX_DN_STR_LEN + 1];
char filter[LDAP_MAX_FILTER_STR_LEN + 1];
char const *dn = base_dn;
-
+
char const *name = check->vp_strvalue;
RDEBUG2("Checking for user in group objects");
-
+
if (rlm_ldap_is_dn(name)) {
- char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
-
+ char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
+
if (rlm_ldap_xlat_filter(request,
filters, sizeof(filters) / sizeof(*filters),
filter, sizeof(filter)) < 0) {
return RLM_MODULE_INVALID;
}
- dn = name;
+ dn = name;
} else {
char name_filter[LDAP_MAX_FILTER_STR_LEN];
char const *filters[] = { name_filter, inst->groupobj_filter, inst->groupobj_membership_filter };
-
+
if (!inst->groupobj_name_attr) {
REDEBUG("Told to search for group by name, but missing 'group.name_attribute' "
"directive");
-
+
return RLM_MODULE_INVALID;
}
filter, sizeof(filter)) < 0) {
return RLM_MODULE_INVALID;
}
-
+
/*
* rlm_ldap_find_user does this, too. Oh well.
*/
- if (radius_xlat(base_dn, sizeof(base_dn), request, inst->groupobj_base_dn,
- rlm_ldap_escape_func, NULL) < 0) {
+ if (radius_xlat(base_dn, sizeof(base_dn), request, inst->groupobj_base_dn,
+ rlm_ldap_escape_func, NULL) < 0) {
REDEBUG("Failed creating base_dn");
-
+
return RLM_MODULE_INVALID;
}
}
switch (status) {
case LDAP_PROC_SUCCESS:
RDEBUG("User found in group object");
-
+
break;
case LDAP_PROC_NO_RESULT:
RDEBUG("Search returned not found");
-
+
return RLM_MODULE_NOTFOUND;
default:
return RLM_MODULE_FAIL;
}
-
+
return RLM_MODULE_OK;
}
rlm_rcode_t rcode = RLM_MODULE_NOTFOUND;
ldap_rcode_t status;
int name_is_dn = false, value_is_dn = false;
-
+
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
char **vals = NULL;
-
+
char const *name = check->vp_strvalue;
-
+
char const *attrs[] = { inst->userobj_membership_attr, NULL };
- int i, count, ldap_errno;
-
+ int i, count, ldap_errno;
+
RDEBUG2("Checking user object membership (%s) attributes", inst->userobj_membership_attr);
status = rlm_ldap_search(inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, &result);
break;
case LDAP_PROC_NO_RESULT:
RDEBUG("Can't check membership attributes, user object not found");
-
+
rcode = RLM_MODULE_NOTFOUND;
-
+
/* FALL-THROUGH */
default:
goto finish;
if (!entry) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
+
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
vals = ldap_get_values((*pconn)->handle, entry, inst->userobj_membership_attr);
if (!vals) {
RDEBUG("No group membership attribute(s) found in user object");
-
+
goto finish;
}
count = ldap_count_values(vals);
for (i = 0; i < count; i++) {
value_is_dn = rlm_ldap_is_dn(vals[i]);
-
+
RDEBUG2("Processing group membership value \"%s\"", vals[i]);
/*
if (strcmp(vals[i], name) == 0){
RDEBUG("User found. Comparison between membership: name, check: name]");
rcode = RLM_MODULE_OK;
-
+
goto finish;
}
-
+
continue;
}
if (strcasecmp(vals[i], name) == 0){
RDEBUG("User found. Comparison between membership: dn, check: dn");
rcode = RLM_MODULE_OK;
-
+
goto finish;
}
-
+
continue;
}
-
+
/*
* If the value is not a DN, and the name we were given is a dn
* convert the value to a DN and do a comparison.
if (!value_is_dn && name_is_dn) {
char *name_dn;
int eq;
-
+
rcode = rlm_ldap_group_dn2name(inst, request, pconn, name, &name_dn);
if (rcode != RLM_MODULE_OK) {
goto finish;
}
-
+
eq = strcmp(vals[i], name_dn);
ldap_memfree(name_dn);
if (eq == 0){
RDEBUG("User found. Comparison between membership: name, check: name "
"(resolved from DN)");
rcode = RLM_MODULE_OK;
-
+
goto finish;
- }
+ }
continue;
}
if (value_is_dn && !name_is_dn) {
char *value_dn;
int eq;
-
+
rcode = rlm_ldap_group_dn2name(inst, request, pconn, vals[i], &value_dn);
if (rcode != RLM_MODULE_OK) {
goto finish;
}
-
+
eq = strcmp(vals[i], value_dn);
ldap_memfree(value_dn);
if (eq == 0){
RDEBUG("User found. Comparison between membership: name (resolved from DN), "
"check: name");
rcode = RLM_MODULE_OK;
-
+
goto finish;
- }
+ }
continue;
}
-
+
rad_assert(0);
}
if (vals) {
ldap_value_free(vals);
}
-
+
if (result) {
ldap_msgfree(result);
}
-
+
return rcode;
}
RDEBUG2("User found. Matched cached membership");
return RLM_MODULE_OK;
}
-
+
if (ret < 0) {
return RLM_MODULE_FAIL;
}
}
-
+
RDEBUG2("Membership not found");
return RLM_MODULE_NOTFOUND;
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file ldap.c
static char const encode[] = ",+\"\\<>;*=()";
static char const hextab[] = "0123456789abcdef";
size_t left = outlen;
-
+
if (*in && ((*in == ' ') || (*in == '#'))) {
goto encode;
}
-
+
while (*in) {
/*
* Encode unsafe characters.
*out++ = *in++;
left--;
}
-
+
*out = '\0';
-
+
return outlen - left;
}
}
/** Find the place at which the two DN strings diverge
- *
+ *
* Returns the length of the non matching string in full.
*
* @param full DN.
static size_t rlm_ldap_common_dn(char const *full, char const *part)
{
size_t f_len, p_len, i;
-
+
if (!full) {
return -1;
}
-
+
f_len = strlen(full);
-
+
if (!part) {
return -1;
}
-
+
p_len = strlen(part);
if (!p_len) {
return f_len;
}
-
+
if ((f_len < p_len) || !f_len) {
- return -1;
+ return -1;
}
for (i = 0; i < p_len; i++) {
if (part[p_len - i] != full[f_len - i]) {
- return -1;
+ return -1;
}
}
char buffer[LDAP_MAX_FILTER_STR_LEN + 1];
char const *in = NULL;
char *p = buffer;
-
+
ssize_t len = 0;
-
+
unsigned int i;
int cnt = 0;
-
+
/*
* Figure out how many filter elements we need to integrate
*/
if (sub[i] && *sub[i]) {
in = sub[i];
cnt++;
- }
+ }
}
if (!cnt) {
if (outlen < 3) {
goto oob;
}
-
+
p[len++] = '(';
p[len++] = '&';
-
+
for (i = 0; i < sublen; i++) {
if (sub[i] && (*sub[i] != '\0')) {
len += strlcpy(p + len, sub[i], outlen - len);
-
+
if ((size_t) len >= outlen) {
oob:
REDEBUG("Out of buffer space creating filter");
-
+
return -1;
}
- }
+ }
}
-
+
if ((outlen - len) < 2) {
goto oob;
}
-
+
p[len++] = ')';
p[len] = '\0';
-
+
in = buffer;
}
len = radius_xlat(out, outlen, request, in, rlm_ldap_escape_func, NULL);
if (len < 0) {
REDEBUG("Failed creating filter");
-
+
return -1;
}
-
+
return len;
}
/** Parse response from LDAP server dealing with any errors
*
- * Should be called after an LDAP operation. Will check result of operation and if it was successful, then attempt
+ * Should be called after an LDAP operation. Will check result of operation and if it was successful, then attempt
* to retrieve and parse the result.
*
- * Will also produce extended error output including any messages the server sent, and information about partial
+ * Will also produce extended error output including any messages the server sent, and information about partial
* DN matches.
*
* @param[in] inst of LDAP module.
* @param[in] dn Last search or bind DN.
* @param[out] result Where to write result, if NULL result will be freed.
* @param[out] error Where to write the error string, may be NULL, must not be freed.
- * @param[out] extra Where to write additional error string to, may be NULL (faster) or must be freed
+ * @param[out] extra Where to write additional error string to, may be NULL (faster) or must be freed
* (with talloc_free).
* @return One of the LDAP_PROC_* codes.
*/
int lib_errno = LDAP_SUCCESS; // errno returned by the library.
int srv_errno = LDAP_SUCCESS; // errno in the result message.
-
+
char *part_dn = NULL; // Partial DN match.
char *our_err = NULL; // Our extended error message.
char *srv_err = NULL; // Server's extended error message.
int freeit = false; // Whether the message should be freed after being processed.
int len;
-
+
struct timeval tv; // Holds timeout values.
-
+
LDAPMessage *tmp_msg; // Temporary message pointer storage if we weren't provided with one.
-
+
char const *tmp_err; // Temporary error pointer storage if we weren't provided with one.
-
+
if (!error) {
error = &tmp_err;
}
*error = NULL;
-
+
if (extra) {
*extra = NULL;
}
-
+
/*
* We always need the result, but our caller may not
*/
result = &tmp_msg;
freeit = true;
}
-
+
*result = NULL;
-
+
/*
* Check if there was an error sending the request
*/
if (lib_errno != LDAP_SUCCESS) {
goto process_error;
}
-
+
memset(&tv, 0, sizeof(tv));
tv.tv_sec = inst->res_timeout;
-
+
/*
* Now retrieve the result and check for errors
* ldap_result returns -1 on error, and 0 on timeout
lib_errno = ldap_result(conn->handle, msgid, 1, &tv, result);
if (lib_errno == 0) {
lib_errno = LDAP_TIMEOUT;
-
+
goto process_error;
}
-
+
if (lib_errno == -1) {
ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
&lib_errno);
goto process_error;
}
-
+
/*
* Parse the result and check for errors sent by the server
*/
if (freeit) {
*result = NULL;
}
-
+
if (lib_errno != LDAP_SUCCESS) {
ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
&lib_errno);
goto process_error;
}
-
+
process_error:
-
+
if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
lib_errno = srv_errno;
} else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
srv_errno = lib_errno;
}
-
+
switch (lib_errno) {
case LDAP_SUCCESS:
*error = "Success";
-
+
break;
case LDAP_NO_SUCH_OBJECT:
*error = "The specified DN wasn't found, check base_dn and identity";
-
+
status = LDAP_PROC_BAD_DN;
-
+
if (!extra) break;
-
- /*
+
+ /*
* Build our own internal diagnostic string
*/
len = rlm_ldap_common_dn(dn, part_dn);
if (len < 0) break;
-
+
our_err = talloc_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
goto error_string;
case LDAP_INSUFFICIENT_ACCESS:
*error = "Insufficient access. Check the identity and password configuration directives";
-
+
status = LDAP_PROC_NOT_PERMITTED;
break;
-
+
case LDAP_UNWILLING_TO_PERFORM:
*error = "Server was unwilling to perform";
-
+
status = LDAP_PROC_NOT_PERMITTED;
break;
-
+
case LDAP_TIMEOUT:
exec_trigger(NULL, inst->cs, "modules.ldap.timeout", true);
-
+
*error = "Timed out while waiting for server to respond";
-
+
status = LDAP_PROC_ERROR;
break;
-
+
case LDAP_FILTER_ERROR:
*error = "Bad search filter";
status = LDAP_PROC_ERROR;
break;
-
+
case LDAP_TIMELIMIT_EXCEEDED:
exec_trigger(NULL, inst->cs, "modules.ldap.timeout", true);
-
+
*error = "Time limit exceeded";
/* FALL-THROUGH */
case LDAP_UNAVAILABLE:
case LDAP_SERVER_DOWN:
status = LDAP_PROC_RETRY;
-
+
goto error_string;
-
+
case LDAP_INVALID_CREDENTIALS:
case LDAP_CONSTRAINT_VIOLATION:
status = LDAP_PROC_REJECT;
-
+
goto error_string;
-
+
case LDAP_OPERATIONS_ERROR:
*error = "Please set 'chase_referrals=yes' and 'rebind=yes'. See the ldap module configuration "
"for details.";
-
+
/* FALL-THROUGH */
default:
status = LDAP_PROC_ERROR;
-
+
error_string:
-
+
if (!*error) {
*error = ldap_err2string(lib_errno);
}
-
+
if (!extra || ((lib_errno == srv_errno) && !our_err && !srv_err)) {
break;
}
-
+
/*
* Output the error codes from the library and server
*/
if (!p) break;
if (lib_errno != srv_errno) {
- a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u). ",
+ a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u). ",
ldap_err2string(lib_errno), lib_errno,
ldap_err2string(srv_errno), srv_errno);
if (!a) {
talloc_free(p);
break;
}
-
+
p = a;
}
talloc_free(p);
break;
}
-
+
p = a;
}
-
+
if (srv_err) {
a = talloc_asprintf_append_buffer(p, "Server said: %s. ", srv_err);
if (!a) {
talloc_free(p);
break;
}
-
+
p = a;
}
-
+
*extra = p;
-
+
break;
}
-
+
/*
* Cleanup memory
*/
if (srv_err) {
ldap_memfree(srv_err);
}
-
+
if (part_dn) {
ldap_memfree(part_dn);
}
-
+
if (our_err) {
talloc_free(our_err);
}
-
+
if ((lib_errno || srv_errno) && *result) {
ldap_msgfree(*result);
*result = NULL;
}
-
+
return status;
}
char const *password, int retry)
{
ldap_rcode_t status;
-
+
int msgid;
-
+
char const *error = NULL;
char *extra = NULL;
rad_assert(*pconn && (*pconn)->handle);
-
+
/*
* Bind as anonymous user
*/
case LDAP_PROC_NOT_PERMITTED:
LDAP_ERR_REQ("Bind was not permitted: %s", error);
LDAP_EXT_REQ();
-
+
break;
case LDAP_PROC_REJECT:
if (*pconn) {
LDAP_DBGW_REQ("Bind with %s to %s:%d failed: %s. Got new socket, retrying...",
dn, inst->server, inst->port, error);
-
+
talloc_free(extra); /* don't leak debug info */
-
+
goto retry;
}
};
-
+
status = LDAP_PROC_ERROR;
-
+
/*
* Were not allowed to retry, or there are no more
* sockets, treat this as a hard failure.
inst->port, error);
}
LDAP_EXT_REQ();
-
+
break;
}
if (extra) {
talloc_free(extra);
}
-
+
return status; /* caller closes the connection */
}
LDAPMessage **result)
{
ldap_rcode_t status;
-
+
int msgid; // Message id returned by
// ldap_search_ext.
-
+
int count = 0; // Number of results we got.
-
+
struct timeval tv; // Holds timeout values.
-
+
char const *error = NULL;
char *extra = NULL;
rad_assert(*pconn && (*pconn)->handle);
-
+
/*
* OpenLDAP library doesn't declare attrs array as const, but
* it really should be *sigh*.
}
rad_assert(*pconn);
-
+
(*pconn)->rebound = false;
}
*/
memset(&tv, 0, sizeof(tv));
tv.tv_sec = inst->res_timeout;
-retry:
+retry:
(void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs, 0, NULL, NULL, &tv, 0, &msgid);
- LDAP_DBG_REQ("Waiting for search result...");
- status = rlm_ldap_result(inst, *pconn, msgid, dn, result, &error, &extra);
+ LDAP_DBG_REQ("Waiting for search result...");
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, result, &error, &extra);
switch (status) {
case LDAP_PROC_SUCCESS:
break;
*pconn = fr_connection_reconnect(inst->pool, *pconn);
if (*pconn) {
LDAP_DBGW_REQ("Search failed: %s. Got new socket, retrying...", error);
-
+
talloc_free(extra); /* don't leak debug info */
-
+
goto retry;
}
-
+
status = LDAP_PROC_ERROR;
-
+
/* FALL-THROUGH */
default:
LDAP_ERR_REQ("Failed performing search: %s", error);
goto finish;
}
-
- if (result) {
+
+ if (result) {
count = ldap_count_entries((*pconn)->handle, *result);
if (count == 0) {
ldap_msgfree(*result);
*result = NULL;
-
+
LDAP_DBG_REQ("Search returned no results");
-
+
status = LDAP_PROC_NO_RESULT;
}
}
-
+
finish:
if (extra) {
talloc_free(extra);
}
-
+
return status;
}
char const *dn, LDAPMod *mods[])
{
ldap_rcode_t status;
-
+
int msgid; // Message id returned by ldap_search_ext.
-
+
char const *error = NULL;
- char *extra = NULL;
+ char *extra = NULL;
rad_assert(*pconn && (*pconn)->handle);
-
+
/*
* Perform all modifications as the admin user.
*/
}
rad_assert(*pconn);
-
+
(*pconn)->rebound = false;
}
-
+
RDEBUG2("Modifying object with DN \"%s\"", dn);
retry:
(void) ldap_modify_ext((*pconn)->handle, dn, mods, NULL, NULL, &msgid);
-
+
RDEBUG2("Waiting for modify result...");
status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
switch (status) {
*pconn = fr_connection_reconnect(inst->pool, *pconn);
if (*pconn) {
RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
-
+
talloc_free(extra); /* don't leak debug info */
-
+
goto retry;
}
-
+
status = LDAP_PROC_ERROR;
-
+
/* FALL-THROUGH */
default:
REDEBUG("Failed modifying object: %s", error);
REDEBUG("%s", extra);
-
+
goto finish;
- }
-
+ }
+
finish:
if (extra) {
talloc_free(extra);
}
-
+
return status;
}
*
* This potentially allows for all authorization and authentication checks to be performed in one ldap search
* operation, which is a big bonus given the number of crappy, slow *cough*AD*cough* LDAP directory servers out there.
- *
+ *
* @param[in] inst rlm_ldap configuration.
* @param[in] request Current request.
* @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
char const *attrs[], int force, LDAPMessage **result, rlm_rcode_t *rcode)
{
static char const *tmp_attrs[] = { NULL };
-
+
ldap_rcode_t status;
VALUE_PAIR *vp = NULL;
LDAPMessage *tmp_msg = NULL, *entry = NULL;
int ldap_errno;
char *dn = NULL;
- char filter[LDAP_MAX_FILTER_STR_LEN];
+ char filter[LDAP_MAX_FILTER_STR_LEN];
char base_dn[LDAP_MAX_DN_STR_LEN];
-
+
int freeit = false; //!< Whether the message should
//!< be freed after being processed.
freeit = true;
}
*result = NULL;
-
+
if (!attrs) {
memset(&attrs, 0, sizeof(tmp_attrs));
}
-
+
/*
* If the caller isn't looking for the result we can just return the current userdn value.
*/
return vp->vp_strvalue;
}
}
-
+
/*
* Perform all searches as the admin user.
*/
}
rad_assert(*pconn);
-
+
(*pconn)->rebound = false;
}
-
+
if (radius_xlat(filter, sizeof(filter), request, inst->userobj_filter, rlm_ldap_escape_func, NULL) < 0) {
REDEBUG("Unable to create filter");
-
+
*rcode = RLM_MODULE_INVALID;
return NULL;
}
if (radius_xlat(base_dn, sizeof(base_dn), request, inst->userobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
REDEBUG("Unable to create base_dn");
-
+
*rcode = RLM_MODULE_INVALID;
return NULL;
}
*rcode = RLM_MODULE_FAIL;
return NULL;
}
-
+
rad_assert(*pconn);
entry = ldap_first_entry((*pconn)->handle, *result);
if (!entry) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
- REDEBUG("Failed retrieving entry: %s",
+ REDEBUG("Failed retrieving entry: %s",
ldap_err2string(ldap_errno));
-
+
goto finish;
}
dn = ldap_get_dn((*pconn)->handle, entry);
if (!dn) {
ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
-
+
REDEBUG("Retrieving object DN from entry failed: %s",
ldap_err2string(ldap_errno));
-
+
goto finish;
}
-
+
RDEBUG("User object found at DN \"%s\"", dn);
vp = pairmake(request, &request->config_items, "LDAP-UserDN", dn, T_OP_EQ);
- if (vp) {
+ if (vp) {
*rcode = RLM_MODULE_OK;
}
-
+
finish:
ldap_memfree(dn);
-
+
if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
ldap_msgfree(*result);
*result = NULL;
{
ldap_rcode_t status;
ldap_handle_t *conn = ctx;
-
+
int ldap_errno;
conn->referred = true;
status = rlm_ldap_bind(conn->inst, NULL, &conn, conn->inst->admin_dn, conn->inst->password, false);
if (status != LDAP_PROC_SUCCESS) {
ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
-
+
return ldap_errno;
}
-
+
return LDAP_SUCCESS;
}
void *mod_conn_create(void *instance)
{
ldap_rcode_t status;
-
+
int ldap_errno, ldap_version;
struct timeval tv;
-
+
ldap_instance_t *inst = instance;
LDAP *handle = NULL;
ldap_handle_t *conn = NULL;
#ifdef HAVE_LDAP_INITIALIZE
if (inst->is_url) {
DEBUG("rlm_ldap (%s): Connecting to %s", inst->xlat_name, inst->server);
-
+
ldap_errno = ldap_initialize(&handle, inst->server);
if (ldap_errno != LDAP_SUCCESS) {
LDAP_ERR("ldap_initialize failed: %s", ldap_err2string(ldap_errno));
ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
LDAP_ERR("Could not set %s: %s", _name, ldap_err2string(ldap_errno)); \
}
-
+
if (inst->ldap_debug) {
do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
}
if (inst->chase_referrals != 2) {
if (inst->chase_referrals) {
do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
-
+
if (inst->rebind == true) {
#if LDAP_SET_REBIND_PROC_ARGS == 3
ldap_set_rebind_proc(handle, rlm_ldap_rebind, inst);
WDEBUG("Told to Start TLS on LDAPS port this will probably fail, please correct the "
"configuration");
}
-
+
if (ldap_start_tls_s(handle, NULL, NULL) != LDAP_SUCCESS) {
ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
}
return conn;
-
+
error:
if (handle) ldap_unbind_s(handle);
if (conn) talloc_free(conn);
-
+
return NULL;
}
/** Close and delete a connection
*
- * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
+ * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
* connection handle.
*
* @param instance rlm_ldap instance.
conn = fr_connection_get(inst->pool);
if (!conn) {
REDEBUG("All ldap connections are in use");
-
+
return NULL;
}
#include <freeradius-devel/modules.h>
#include <ldap.h>
-#define LDAP_MAX_ATTRMAP 128 //!< Maximum number of mappings between LDAP and
+#define LDAP_MAX_ATTRMAP 128 //!< Maximum number of mappings between LDAP and
//!< FreeRADIUS attributes.
-#define LDAP_MAP_RESERVED 4 //!< Number of additional items to allocate in expanded
- //!< attribute name arrays. Currently for enable attribute,
- //!< group membership attribute, valuepair attribute,
+#define LDAP_MAP_RESERVED 4 //!< Number of additional items to allocate in expanded
+ //!< attribute name arrays. Currently for enable attribute,
+ //!< group membership attribute, valuepair attribute,
//!< and profile attribute.
-
+
#define LDAP_MAX_CACHEABLE 64 //!< Maximum number of groups we retrieve from the server for
- //!< a given user. If more than this number are retrieve the
+ //!< a given user. If more than this number are retrieve the
//!< module returns invalid.
-
+
#define LDAP_MAX_GROUP_NAME_LEN 128 //!< Maximum name of a group name.
#define LDAP_MAX_ATTR_STR_LEN 256 //!< Maximum length of an xlat expanded LDAP attribute.
#define LDAP_MAX_FILTER_STR_LEN 1024 //!< Maximum length of an xlat expanded filter.
typedef struct ldap_acct_section {
CONF_SECTION *cs; //!< Section configuration.
-
+
char const *reference; //!< Configuration reference string.
} ldap_acct_section_t;
fr_connection_pool_t *pool; //!< Connection pool instance.
char const *server; //!< Initial server to bind to.
- int is_url; //!< Whether ldap_is_ldap_url says 'server' is an
+ int is_url; //!< Whether ldap_is_ldap_url says 'server' is an
//!< ldap[s]:// url.
int port; //!< Port to use when binding to the server.
int expect_password; //!< True if the user_map included a mapping between an LDAP
//!< attribute and one of our password reference attributes.
-
+
/*
* RADIUS attribute to LDAP attribute maps
*/
value_pair_map_t *user_map; //!< Attribute map applied to users and profiles.
-
+
/*
* User object attributes and filters
*/
char const *userobj_base_dn; //!< DN to search for users under.
char const *userobj_scope_str; //!< Scope (sub, one, base).
int userobj_scope; //!< Search scope.
-
+
char const *userobj_membership_attr; //!< Attribute that describes groups the user is a member of.
char *userobj_access_attr; //!< Attribute to check to see if the user should be locked out.
- int access_positive; //!< If true the presence of the attribute will allow access,
+ int access_positive; //!< If true the presence of the attribute will allow access,
//!< else it will deny access.
-
+
char const *valuepair_attr; //!< Generic dynamic mapping attribute, contains a RADIUS
//!< attribute and value.
/*
* Group object attributes and filters
*/
-
+
char const *groupobj_filter; //!< Filter to retrieve only group objects.
char const *groupobj_base_dn; //!< DN to search for users under.
char const *groupobj_scope_str; //!< Scope (sub, one, base).
char const *groupobj_name_attr; //!< The name of the group.
char const *groupobj_membership_filter; //!< Filter to only retrieve groups which contain
//!< the user as a member.
-
+
int cacheable_group_name; //!< If true the server will determine complete set of group
//!< memberships for the current user object, and perform any
//!< resolution necessary to determine the names of those
//!< groups, then right them to the control list (LDAP-Group).
-
+
int cacheable_group_dn; //!< If true the server will determine complete set of group
//!< memberships for the current user object, and perform any
//!< resolution necessary to determine the DNs of those groups,
//!< then right them to the control list (LDAP-GroupDN).
-
+
const DICT_ATTR *group_da; //!< The DA associated with this specific version of the
//!< rlm_ldap module.
-
+
/*
* Dynamic clients
*/
char const *clientobj_base_dn; //!< DN to search for clients under.
char const *clientobj_scope_str; //!< Scope (sub, one, base).
int clientobj_scope; //!< Search scope.
-
+
char const *clientobj_identifier; //!< IP/FQDN/IP Prefix for the NAS.
char const *clientobj_shortname; //!< Short/Friendly name to assign.
char const *clientobj_type; //!< Type of NAS (not usually used).
char const *clientobj_secret; //!< RADIUS secret.
char const *clientobj_server; //!< Virtual server to associate the client with.
char const *clientobj_require_ma; //!< Require message-authenticator.
-
+
bool do_clients; //!< If true, attempt to load clients on instantiation.
/*
char const *profile_attr; //!< Attribute that identifies profiles to apply. May appear
//!< in userobj or groupobj.
char const *profile_filter; //!< Filter to retrieve only retrieve group objects.
-
+
/*
* Accounting
*/
char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate
//!< the certificate the server presents).
-
+
char const *tls_ca_path; //!< Sets the path to a directory containing CA certificates.
-
+
char const *tls_certificate_file; //!< Sets the path to the public certificate file we present
//!< to the servers.
-
- char const *tls_private_key_file; //!< Sets the path to the private key for our public
+
+ char const *tls_private_key_file; //!< Sets the path to the private key for our public
//!< certificate.
-
+
char const *tls_random_file; //!< Path to the random file if /dev/random and /dev/urandom
//!< are unavailable.
-
- char const *tls_require_cert_str; //!< Sets requirements for validating the certificate the
+
+ char const *tls_require_cert_str; //!< Sets requirements for validating the certificate the
//!< server presents.
-
+
int tls_require_cert; //!< OpenLDAP constant representing the require cert string.
/*
* Options
*/
-
+
int net_timeout; //!< How long we wait for new connections to the LDAP server
//!< to be established.
int res_timeout; //!< How long we wait for a result from the server.
typedef struct ldap_handle {
LDAP *handle; //!< LDAP LD handle.
- int rebound; //!< Whether the connection has been rebound to something
+ int rebound; //!< Whether the connection has been rebound to something
//!< other than the admin user.
- int referred; //!< Whether the connection is now established a server
+ int referred; //!< Whether the connection is now established a server
//!< other than the configured one.
ldap_instance_t *inst; //!< rlm_ldap configuration.
} ldap_handle_t;
typedef enum {
LDAP_PROC_SUCCESS = 0, //!< Operation was successfull.
-
+
LDAP_PROC_ERROR = -1, //!< Unrecoverable library/server error.
-
- LDAP_PROC_RETRY = -2, //!< Transitory error, caller should retry the operation
+
+ LDAP_PROC_RETRY = -2, //!< Transitory error, caller should retry the operation
//!< with a new connection.
-
- LDAP_PROC_NOT_PERMITTED = -3, //!< Operation was not permitted, either current user was
- //!< locked out in the case of binds, or has insufficient
+
+ LDAP_PROC_NOT_PERMITTED = -3, //!< Operation was not permitted, either current user was
+ //!< locked out in the case of binds, or has insufficient
//!< access.
-
+
LDAP_PROC_REJECT = -4, //!< Bind failed, user was rejected.
-
+
LDAP_PROC_BAD_DN = -5, //!< Specified an invalid object in a bind or search DN.
-
+
LDAP_PROC_NO_RESULT = -6 //!< Got no results.
} ldap_rcode_t;
ldap_rcode_t rlm_ldap_bind(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
char const *password, int retry);
-
+
ldap_rcode_t rlm_ldap_search(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
char const *dn, int scope, char const *filter, char const * const *attrs,
LDAPMessage **result);
-
+
ldap_rcode_t rlm_ldap_modify(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
char const *dn, LDAPMod *mods[]);
-
+
char const *rlm_ldap_find_user(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
char const *attrs[], int force, LDAPMessage **result, rlm_rcode_t *rcode);
-
+
rlm_rcode_t rlm_ldap_check_access(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t const *conn,
LDAPMessage *entry);
-
+
void rlm_ldap_check_reply(ldap_instance_t const *inst, REQUEST *request);
/*
rlm_rcode_t rlm_ldap_cacheable_userobj(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
LDAPMessage *entry);
-
+
rlm_rcode_t rlm_ldap_cacheable_groupobj(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn);
rlm_rcode_t rlm_ldap_check_groupobj_dynamic(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
VALUE_PAIR *check);
-
+
rlm_rcode_t rlm_ldap_check_userobj_dynamic(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
char const *dn, VALUE_PAIR *check);
rlm_rcode_t rlm_ldap_map_profile(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
char const *profile, rlm_ldap_map_xlat_t const *expanded);
-
+
/*
* clients.c - Dynamic clients (bulk load).
*/
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
/**
* $Id$
* @file rlm_ldap.c
{ "one", LDAP_SCOPE_ONE },
{ "base", LDAP_SCOPE_BASE },
{ "children", LDAP_SCOPE_CHILDREN },
-
+
{ NULL , -1 }
};
{ "allow", LDAP_OPT_X_TLS_ALLOW },
{ "try", LDAP_OPT_X_TLS_TRY },
{ "hard", LDAP_OPT_X_TLS_HARD }, /* oh yes, just like that */
-
+
{ NULL , -1 }
};
#endif
*/
{"cacertfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
{"ca_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
-
+
{"cacertdir", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
{"ca_path", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
-
+
{"certfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
{"certificate_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
-
+
{"keyfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
{"private_key_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
-
+
{"randfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
- {"random_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
-
+ {"random_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
+
/*
* LDAP Specific TLS attributes
*/
{"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, start_tls), NULL, "no"},
{"require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, tls_require_cert_str), NULL, NULL},
-
+
{ NULL, -1, 0, NULL, NULL }
};
static CONF_PARSER profile_config[] = {
{"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_filter), NULL, "(&)"}, //!< Correct filter for
- //!< when the DN is
+ //!< when the DN is
//!< known.
{"attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_attr), NULL, NULL},
{"default", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, default_profile), NULL, NULL},
{"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_filter), NULL, "(uid=%u)"},
{"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_scope_str), NULL, "sub"},
{"base_dn", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(ldap_instance_t,userobj_base_dn), NULL, NULL},
-
+
{"access_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_access_attr), NULL, NULL},
{"access_positive", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, access_positive), NULL, "yes"},
{"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_filter), NULL, NULL},
{"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_scope_str), NULL, "sub"},
{"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_base_dn), NULL, NULL},
-
+
{"name_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_name_attr), NULL, "cn"},
{"membership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_membership_attr), NULL, NULL},
{"membership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_membership_filter), NULL, NULL},
/*
* Client configuration
- */
+ */
static CONF_PARSER client_attribute[] = {
{"identifier", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_identifier), NULL, "host"},
{"shortname", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_shortname), NULL, "cn"},
{"virtual_server", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_server), NULL, NULL},
{"require_message_authenticator", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_require_ma),
NULL, NULL},
-
+
{ NULL, -1, 0, NULL, NULL }
};
{ "user", PW_TYPE_SUBSECTION, 0, NULL, (void const *) user_config },
{ "group", PW_TYPE_SUBSECTION, 0, NULL, (void const *) group_config },
-
+
{ "client", PW_TYPE_SUBSECTION, 0, NULL, (void const *) client_config },
-
+
{ "profile", PW_TYPE_SUBSECTION, 0, NULL, (void const *) profile_config },
{ "options", PW_TYPE_SUBSECTION, 0, NULL, (void const *) option_config },
(strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
ldap_url->lud_attrs[1]) {
REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");
-
+
goto free_urldesc;
}
- if (ldap_url->lud_host &&
+ if (ldap_url->lud_host &&
((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
(ldap_url->lud_port != inst->port))) {
RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host, inst->port);
-
+
goto free_urldesc;
}
if (!conn) goto free_urldesc;
memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
-
+
status = rlm_ldap_search(inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter,
attrs, &result);
switch (status) {
{
ldap_instance_t *inst = instance;
rlm_rcode_t rcode;
-
+
int found = false;
int check_is_dn;
if (!inst->groupobj_base_dn) {
REDEBUG("Directive 'group.base_dn' must be set'");
-
+
return 1;
}
-
+
RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
if (check->length == 0) {
goto finish;
}
}
-
+
rad_assert(conn);
/*
goto finish;
}
}
-
+
rad_assert(conn);
-
+
finish:
if (conn) {
rlm_ldap_release_socket(inst, conn);
}
-
+
if (!found) {
RDEBUG("User is not a member of specified group");
-
+
return 1;
}
static int mod_detach(void *instance)
{
ldap_instance_t *inst = instance;
-
+
fr_connection_pool_delete(inst->pool);
if (inst->user_map) {
CONF_SECTION *cs;
char const *name = section_type_value[comp].section;
-
+
cs = cf_section_sub_find(parent, name);
if (!cs) {
INFO("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls "
"from this section", inst->xlat_name, name);
-
+
return 0;
}
-
+
*config = talloc_zero(inst, ldap_acct_section_t);
if (cf_section_parse(cs, *config, acct_section_config) < 0) {
LDAP_ERR("Failed parsing configuration for section %s", name);
-
+
return -1;
}
-
+
(*config)->cs = cs;
return 0;
}
/** Instantiate the module
- *
+ *
* Creates a new instance of the module reading parameters from a configuration section.
*
* @param conf to parse.
inst->chase_referrals = 2; /* use OpenLDAP defaults */
inst->rebind = 2;
-
+
inst->xlat_name = cf_section_name2(conf);
if (!inst->xlat_name) {
inst->xlat_name = cf_section_name1(conf);
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;
}
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;
}
if (!inst->groupobj_base_dn) {
LDAP_ERR("Directive 'group.base_dn' 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.
*/
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
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->group_da = dict_attrbyname(buffer);
if (!inst->group_da) {
LDAP_ERR("Failed creating attribute %s", buffer);
-
+
goto error;
}
-
+
paircompare_register(inst->group_da->attr, PW_USER_NAME, rlm_ldap_groupcmp, inst);
/*
* Were the default instance
} else {
inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, rlm_ldap_groupcmp, inst);
- }
+ }
xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);
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;
}
/** Check the user's password against ldap directory
- *
+ *
* @param instance rlm_ldap configuration.
* @param request Current request.
* @return one of the RLM_MODULE_* values.
RWDEBUG("* THAT CONFIGURATION IS WRONG. DELETE IT. ");
RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING.");
RWDEBUG("*********************************************");
-
+
REDEBUG("Attribute \"User-Password\" is required for authentication.");
-
+
return RLM_MODULE_INVALID;
}
if (request->password->length == 0) {
REDEBUG("Empty password supplied");
-
+
return RLM_MODULE_INVALID;
}
dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
if (!dn) {
rlm_ldap_release_socket(inst, conn);
-
+
return rcode;
}
case LDAP_PROC_SUCCESS:
rcode = RLM_MODULE_OK;
RDEBUG("Bind as user \"%s\" was successful", dn);
-
+
break;
case LDAP_PROC_NOT_PERMITTED:
rcode = RLM_MODULE_USERLOCK;
-
+
break;
case LDAP_PROC_REJECT:
rcode = RLM_MODULE_REJECT;
-
+
break;
case LDAP_PROC_BAD_DN:
rcode = RLM_MODULE_INVALID;
-
+
break;
case LDAP_PROC_NO_RESULT:
rcode = RLM_MODULE_NOTFOUND;
-
+
break;
default:
rcode = RLM_MODULE_FAIL;
};
rlm_ldap_release_socket(inst, conn);
-
+
return rcode;
}
LDAPMessage *result, *entry;
char const *dn = NULL;
rlm_ldap_map_xlat_t expanded; /* faster than mallocing every time */
-
+
if (!request->username) {
RDEBUG2("Attribute \"User-Name\" is required for authorization.");
-
+
return RLM_MODULE_NOOP;
}
*/
if (request->username->length == 0) {
RDEBUG2("Zero length username not permitted");
-
+
return RLM_MODULE_INVALID;
}
if (rlm_ldap_map_xlat(request, inst->user_map, &expanded) < 0) {
return RLM_MODULE_FAIL;
}
-
+
conn = rlm_ldap_get_socket(inst, request);
if (!conn) return RLM_MODULE_FAIL;
-
+
/*
* Add any additional attributes we need for checking access, memberships, and profiles
*/
if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
expanded.attrs[expanded.count++] = inst->userobj_membership_attr;
}
-
+
if (inst->profile_attr) {
expanded.attrs[expanded.count++] = inst->profile_attr;
}
-
+
if (inst->valuepair_attr) {
expanded.attrs[expanded.count++] = inst->valuepair_attr;
}
-
+
expanded.attrs[expanded.count] = NULL;
-
+
dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
if (!dn) {
- goto finish;
+ goto finish;
}
entry = ldap_first_entry(conn->handle, result);
if (!entry) {
ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
+
goto finish;
}
goto finish;
}
}
-
+
/*
* Check if we need to cache group memberships
*/
if (rcode != RLM_MODULE_OK) {
goto finish;
}
-
+
rcode = rlm_ldap_cacheable_groupobj(inst, request, &conn);
if (rcode != RLM_MODULE_OK) {
goto finish;
vp = radius_paircreate(request, &request->config_items, PW_CLEARTEXT_PASSWORD, 0);
pairstrcpy(vp, password);
vp->length = pass_size;
-
+
RDEBUG2("Added eDirectory password in check items as %s = %s", vp->da->name, vp->vp_strvalue);
-
+
if (inst->edir_autz) {
RDEBUG2("Binding as user for eDirectory authorization checks");
/*
case LDAP_PROC_SUCCESS:
rcode = RLM_MODULE_OK;
RDEBUG("Bind as user \"%s\" was successful", dn);
-
+
break;
case LDAP_PROC_NOT_PERMITTED:
rcode = RLM_MODULE_USERLOCK;
-
+
goto finish;
case LDAP_PROC_REJECT:
rcode = RLM_MODULE_REJECT;
-
+
goto finish;
case LDAP_PROC_BAD_DN:
rcode = RLM_MODULE_INVALID;
-
+
goto finish;
case LDAP_PROC_NO_RESULT:
rcode = RLM_MODULE_NOTFOUND;
-
+
goto finish;
default:
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
};
}
for (i = 0; vals[i] != NULL; i++) {
rlm_ldap_map_profile(inst, request, &conn, vals[i], &expanded);
}
-
+
ldap_value_free(vals);
}
}
rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry);
rlm_ldap_check_reply(inst, request);
}
-
+
finish:
rlm_ldap_map_xlat_free(&expanded);
if (result) {
static rlm_rcode_t user_modify(ldap_instance_t *inst, REQUEST *request, ldap_acct_section_t *section)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
-
+
ldap_handle_t *conn = NULL;
-
+
LDAPMod *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP];
LDAPMod **modify = mod_p;
-
+
char *passed[LDAP_MAX_ATTRMAP * 2];
int i, total = 0, last_pass = 0;
-
+
char *expanded[LDAP_MAX_ATTRMAP];
int last_exp = 0;
-
+
char const *attr;
char const *value;
-
+
char const *dn;
/*
* Build our set of modifications using the update sections in
CONF_SECTION *cs;
FR_TOKEN op;
char path[MAX_STRING_LEN];
-
+
char *p = path;
rad_assert(section);
-
+
/*
* Locate the update section were going to be using
*/
if (section->reference[0] != '.') {
*p++ = '.';
}
-
+
if (radius_xlat(p, (sizeof(path) - (p - path)) - 1, request, section->reference, NULL, NULL) < 0) {
- goto error;
+ goto error;
}
ci = cf_reference_item(NULL, section->cs, path);
if (!ci) {
- goto error;
+ goto error;
}
-
+
if (!cf_item_is_section(ci)){
REDEBUG("Reference must resolve to a section");
-
- goto error;
+
+ goto error;
}
-
+
cs = cf_section_sub_find(cf_itemtosection(ci), "update");
if (!cs) {
REDEBUG("Section must contain 'update' subsection");
-
+
goto error;
}
-
+
/*
* Iterate over all the pairs, building our mods array
*/
for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
int do_xlat = false;
-
+
if (total == LDAP_MAX_ATTRMAP) {
REDEBUG("Modify map size exceeded");
-
+
goto error;
}
-
+
if (!cf_item_is_pair(ci)) {
REDEBUG("Entry is not in \"ldap-attribute = value\" format");
-
+
goto error;
}
-
+
/*
* Retrieve all the information we need about the pair
*/
value = cf_pair_value(cp);
attr = cf_pair_attr(cp);
op = cf_pair_operator(cp);
-
+
if (!value || (*value == '\0')) {
RDEBUG("Empty value string, skipping attribute \"%s\"", attr);
-
+
continue;
}
break;
case T_BACK_QUOTED_STRING:
case T_DOUBLE_QUOTED_STRING:
- do_xlat = true;
+ do_xlat = true;
break;
default:
rad_assert(0);
goto error;
}
-
+
if (op == T_OP_CMP_FALSE) {
passed[last_pass] = NULL;
} else if (do_xlat) {
char *exp = NULL;
-
+
if (radius_xlat(exp, 0, request, value, NULL, NULL) <= 0) {
RDEBUG("Skipping attribute \"%s\"", attr);
-
+
talloc_free(exp);
-
+
continue;
}
-
+
expanded[last_exp++] = exp;
passed[last_pass] = exp;
- /*
+ /*
* Static strings
*/
} else {
memcpy(&(passed[last_pass]), &value, sizeof(passed[last_pass]));
}
-
+
passed[last_pass + 1] = NULL;
-
+
mod_s[total].mod_values = &(passed[last_pass]);
-
+
last_pass += 2;
-
+
switch (op)
{
/*
default:
REDEBUG("Operator '%s' is not supported for LDAP modify operations",
fr_int2str(fr_tokens, op, "<INVALID>"));
-
+
goto error;
}
-
+
/*
* Now we know the value is ok, copy the pointers into
* the ldapmod struct.
*/
memcpy(&(mod_s[total].mod_type), &(attr), sizeof(mod_s[total].mod_type));
-
+
mod_p[total] = &(mod_s[total]);
total++;
}
-
+
if (total == 0) {
rcode = RLM_MODULE_NOOP;
goto release;
}
-
+
mod_p[total] = NULL;
-
+
conn = rlm_ldap_get_socket(inst, request);
if (!conn) return RLM_MODULE_FAIL;
if (!dn || (rcode != RLM_MODULE_OK)) {
goto error;
}
-
+
rcode = rlm_ldap_modify(inst, request, &conn, dn, modify);
-
+
release:
error:
/*
* Free up any buffers we allocated for xlat expansion
- */
+ */
for (i = 0; i < last_exp; i++) {
talloc_free(expanded[i]);
}
rlm_ldap_release_socket(inst, conn);
-
+
return rcode;
}
static rlm_rcode_t mod_accounting(void *instance, REQUEST * request) {
- ldap_instance_t *inst = instance;
+ ldap_instance_t *inst = instance;
if (inst->accounting) {
- return user_modify(inst, request, inst->accounting);
+ return user_modify(inst, request, inst->accounting);
}
-
+
return RLM_MODULE_NOOP;
}
ldap_instance_t *inst = instance;
if (inst->postauth) {
- return user_modify(inst, request, inst->postauth);
+ return user_modify(inst, request, inst->postauth);
}
return RLM_MODULE_NOOP;
CONF_PAIR *cp;
p = line + 1;
-
+
if (radius_xlat(p, sizeof(line) - 2, request, inst->reference, linelog_escape_func,
NULL) < 0) {
return RLM_MODULE_FAIL;
}
-
+
line[0] = '.'; /* force to be in current section */
/*
if (radius_xlat(buffer, sizeof(buffer), request, inst->filename, NULL, NULL) < 0) {
return RLM_MODULE_FAIL;
}
-
+
/* check path and eventually create subdirs */
p = strrchr(buffer,'/');
if (p) {
}
gid = grp->gr_gid;
}
-
+
if (chown(buffer, -1, gid) == -1) {
RDEBUG2("Unable to change system group of \"%s\"", buffer);
}
if (fd > -1) {
close(fd);
}
-
+
return RLM_MODULE_FAIL;
}
if (fd >= 0) {
strcat(line, "\n");
-
+
if (write(fd, line, strlen(line)) < 0) {
EDEBUG("rlm_linelog: Failed writing: %s", strerror(errno));
close(fd);
return RLM_MODULE_FAIL;
}
-
+
close(fd);
#ifdef HAVE_SYSLOG_H
static const CONF_PARSER module_config[] = {
{ "minimum-timeout", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_logintime_t,min_time), NULL, NULL},
{ "minimum_timeout", PW_TYPE_INTEGER, offsetof(rlm_logintime_t,min_time), NULL, "60" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
if (!ends) {
return RLM_MODULE_NOOP;
}
-
+
/*
* Authentication is OK. Now see if this user may login at this time of the day.
*/
- RDEBUG("Checking Login-Time");
+ RDEBUG("Checking Login-Time");
- /*
+ /*
* Compare the time the request was received with the current Login-Time value
*/
left = timestr_match(ends->vp_strvalue, request->timestamp);
if (left == 0) {
return RLM_MODULE_OK;
}
-
+
/*
* The min_time setting is to deal with NAS that won't allow Session-Timeout values below a certain value
* For example some Alcatel Lucent products won't allow a Session-Timeout < 300 (5 minutes).
*
* We don't know were going to get another chance to lock out the user, so we need to do it now.
- */
+ */
if (left < inst->min_time) {
REDEBUG("Login outside of allowed time-slot (session end %s, with lockout %i seconds before)",
ends->vp_strvalue, inst->min_time);
-
+
return RLM_MODULE_USERLOCK;
}
-
+
/* else left > inst->min_time */
-
+
/*
- * There's time left in the users session, inform the NAS by including a Session-Timeout
+ * There's time left in the users session, inform the NAS by including a Session-Timeout
* attribute in the reply, or modifying the existing one.
*/
RDEBUG("Login within allowed time-slot, %i seconds left in this session", left);
-
+
timeout = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
if (timeout) { /* just update... */
if (timeout->vp_integer > (unsigned int) left) {
timeout->vp_integer = left;
}
- } else {
+ } else {
timeout = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
timeout->vp_integer = left;
}
-
+
RDEBUG("reply:Session-Timeout set to %i", left);
-
+
return RLM_MODULE_OK;
}
tAttributeValueEntry *pValueEntry = NULL;
tDataList *pUserNode = NULL;
rlm_rcode_t result = RLM_MODULE_FAIL;
-
+
if (!inUserName) {
ERROR("rlm_mschap: getUserNodeRef(): no username");
return RLM_MODULE_FAIL;
ERROR("rlm_mschap: getUserNodeRef(): dsDataBufferAllocate() status = %ld", status);
return RLM_MODULE_FAIL;
}
-
+
do {
/* find on search node */
status = dsFindDirNodes(dsRef, tDataBuff, NULL,
result = RLM_MODULE_FAIL;
break;
}
-
+
status = dsGetDirNodeName(dsRef, tDataBuff, 1, &nodeName);
if (status != eDSNoErr) {
ERROR("rlm_mschap: getUserNodeRef(): dsGetDirNodeName() status = %ld", status);
result = RLM_MODULE_FAIL;
break;
}
-
+
status = dsOpenDirNode(dsRef, nodeName, &nodeRef);
dsDataListDeallocate(dsRef, nodeName);
free(nodeName);
nodeName = NULL;
-
+
if (status != eDSNoErr) {
ERROR("rlm_mschap: getUserNodeRef(): dsOpenDirNode() status = %ld", status);
result = RLM_MODULE_FAIL;
break;
}
-
+
pRecName = dsBuildListFromStrings(dsRef, inUserName, NULL);
pRecType = dsBuildListFromStrings(dsRef, kDSStdRecordTypeUsers,
NULL);
pAttrType = dsBuildListFromStrings(dsRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName, NULL);
-
+
recCount = 1;
status = dsGetRecordList(nodeRef, tDataBuff, pRecName,
eDSExact, pRecType, pAttrType, 0,
result = RLM_MODULE_FAIL;
break;
}
-
+
status = dsGetRecordEntry(nodeRef, tDataBuff, 1,
&attrListRef, &pRecEntry);
if (status != eDSNoErr) {
ERROR("rlm_mschap: getUserNodeRef(): dsGetRecordEntry() status = %ld", status);
result = RLM_MODULE_FAIL;
- break;
+ break;
}
-
+
for (attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++) {
status = dsGetAttributeEntry(nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry);
if (status == eDSNoErr && pAttrEntry != NULL) {
memcpy(*outUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
}
}
-
+
if (pValueEntry != NULL) {
dsDeallocAttributeValueEntry(dsRef, pValueEntry);
pValueEntry = NULL;
}
-
+
dsDeallocAttributeEntry(dsRef, pAttrEntry);
pAttrEntry = NULL;
dsCloseAttributeValueList(valueRef);
valueRef = 0;
}
}
-
+
/* OpenDirectory doesn't support mschapv2 authentication against
* Active Directory. AD users need to be authenticated using the
* normal freeradius AD path (i.e. ntlm_auth).
result = RLM_MODULE_FAIL;
break;
}
-
+
status = dsOpenDirNode(dsRef, pUserNode, userNodeRef);
dsDataListDeallocate(dsRef, pUserNode);
free(pUserNode);
result = RLM_MODULE_FAIL;
break;
}
-
+
result = RLM_MODULE_OK;
}
while (0);
-
+
if (pRecEntry != NULL)
dsDeallocRecordEntry(dsRef, pRecEntry);
if (tDataBuff != NULL)
dsDataBufferDeAllocate(dsRef, tDataBuff);
-
+
if (pUserLocation != NULL)
free(pUserLocation);
-
+
if (pRecName != NULL) {
dsDataListDeallocate(dsRef, pRecName);
free(pRecName);
}
if (nodeRef != 0)
dsCloseDirNode(nodeRef);
-
+
return result;
}
#ifndef NDEBUG
unsigned int t;
#endif
-
+
username_string = talloc_array(request, char, usernamepair->length + 1);
if (!username_string)
return RLM_MODULE_FAIL;
-
+
strlcpy(username_string, usernamepair->vp_strvalue,
usernamepair->length + 1);
-
+
status = dsOpenDirService(&dsRef);
if (status != eDSNoErr) {
talloc_free(username_string);
dsCloseDirService(dsRef);
return rcode;
}
-
+
/* We got a node; fill the stepBuffer
kDSStdAuthMSCHAP2
MS-CHAPv2 authentication method. The Open Directory plug-in generates the reply data for the client.
strlen(peerchal), peerchal, // client challenge
strlen(p24), p24, // P24 NT-Response
4, "User"); // must match the username that was used for the hash
-
+
inName = username_string
schal = challenge->vp_strvalue
peerchal = response->vp_strvalue + 2 (16 octets)
tDataBuff = dsDataBufferAllocate(dsRef, 4096);
pAuthType = dsDataNodeAllocateString(dsRef, kDSStdAuthMSCHAP2);
uiCurr = 0;
-
+
RDEBUG2("OD username_string = %s, OD shortUserName=%s (length = %lu)\n", username_string, shortUserName, strlen(shortUserName));
-
+
/* User name length + username */
uiLen = (uint32_t)strlen(shortUserName);
memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
}
fprintf(stderr, "\n");
#endif
-
+
/* server challenge (ie. my (freeRADIUS) challenge) */
uiLen = 16;
memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
memcpy(&(tDataBuff->fBufferData[uiCurr]), &(challenge->vp_strvalue[0]),
uiLen);
uiCurr += uiLen;
-
+
#ifndef NDEBUG
RDEBUG2(" stepbuf peer challenge:\t\t");
for (t = 2; t < 18; t++) {
}
fprintf(stderr, "\n");
#endif
-
+
/* peer challenge (ie. the client-generated response) */
uiLen = 16;
memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
uiCurr += sizeof(uiLen);
memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[2]),
uiLen);
- uiCurr += uiLen;
-
+ uiCurr += uiLen;
+
#ifndef NDEBUG
RDEBUG2(" stepbuf p24:\t\t");
for (t = 26; t < 50; t++) {
}
fprintf(stderr, "\n");
#endif
-
+
/* p24 (ie. second part of client-generated response) */
uiLen = 24; /* strlen(&(response->vp_strvalue[26])); may contain NULL byte in the middle. */
memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[26]),
uiLen);
uiCurr += uiLen;
-
+
/* Client generated use name (short name?) */
uiLen = (uint32_t)strlen(username_string);
memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
uiCurr += uiLen;
tDataBuff->fBufferLength = uiCurr;
-
+
status = dsDoDirNodeAuth(userNodeRef, pAuthType, 1, tDataBuff,
pStepBuff, NULL);
if (status == eDSNoErr) {
if (pStepBuff->fBufferLength > 4) {
uint32_t len;
-
+
memcpy(&len, pStepBuff->fBufferData, sizeof(len));
if (len == 40) {
char mschap_reply[42] = { '\0' };
dsCloseDirNode(userNodeRef);
if (dsRef != 0)
dsCloseDirService(dsRef);
-
+
if (status != eDSNoErr) {
errno = EACCES;
ERROR("rlm_mschap: authentication failed %d", status); /* <-- returns -14091 (eDSAuthMethodNotSupported) -14090 */
return RLM_MODULE_REJECT;
}
-
+
return RLM_MODULE_OK;
}
if (len < 0) {
goto ntlm_auth_err;
}
-
+
buf[len++] = '\n';
buf[len] = '\0';
if (len < 0) {
goto ntlm_auth_err;
}
-
+
buf[len++] = '\n';
buf[len] = '\0';
for (seq = 1; seq < 4; seq++) {
vp_cursor_t cursor;
int found = 0;
-
+
for (nt_enc = paircursor(&cursor, &request->packet->vps);
nt_enc;
nt_enc = pairnext(&cursor)) {
} else {
name_attr = username;
}
-
+
/*
* with_ntdomain_hack moved here, too.
*/
} else {
username_string = name_attr->vp_strvalue;
}
-
+
if (response_name &&
((username->length != response_name->length) ||
(strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
uint32_t uiCurr = 0;
uint32_t uiLen = 0;
uint32_t pwLen = 0;
-
+
if (!uname || !password)
return result;
-
+
do
- {
+ {
status = dsOpenDirService( &dsRef );
if ( status != eDSNoErr )
return result;
-
+
tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
if (!tDataBuff)
break;
-
+
/* find user on search node */
status = dsFindDirNodes( dsRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &context );
if (status != eDSNoErr || nodeCount < 1)
break;
-
+
status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
if (status != eDSNoErr)
break;
-
+
status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
dsDataListDeallocate( dsRef, nodeName );
free( nodeName );
pRecName = dsBuildListFromStrings( dsRef, uname, NULL );
pRecType = dsBuildListFromStrings( dsRef, kDSStdRecordTypeUsers, kDSStdRecordTypeComputers, kDSStdRecordTypeMachines, NULL );
pAttrType = dsBuildListFromStrings( dsRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, kDSNAttrRecordType, NULL );
-
+
recCount = 1;
status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType,
pAttrType, 0, &recCount, &context );
if ( status != eDSNoErr || recCount == 0 )
break;
-
+
status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
if ( status != eDSNoErr )
break;
-
+
for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
{
status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
pValueEntry = NULL;
}
}
-
+
if ( pValueEntry != NULL ) {
dsDeallocAttributeValueEntry( dsRef, pValueEntry );
pValueEntry = NULL;
valueRef = 0;
}
}
-
+
pUserNode = dsBuildFromPath( dsRef, pUserLocation, "/" );
status = dsOpenDirNode( dsRef, pUserNode, &userNodeRef );
dsDataListDeallocate( dsRef, pUserNode );
pUserNode = NULL;
if ( status != eDSNoErr )
break;
-
+
pStepBuff = dsDataBufferAllocate( dsRef, 128 );
-
+
pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthNodeNativeClearTextOK );
uiCurr = 0;
-
+
/* User name */
uiLen = (uint32_t)strlen( pUserName );
memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof(uiLen) );
uiCurr += (uint32_t)sizeof( uiLen );
memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
uiCurr += uiLen;
-
+
/* pw */
pwLen = (uint32_t)strlen( password );
memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &pwLen, sizeof(pwLen) );
uiCurr += (uint32_t)sizeof( pwLen );
memcpy( &(tDataBuff->fBufferData[ uiCurr ]), password, pwLen );
uiCurr += pwLen;
-
+
tDataBuff->fBufferLength = uiCurr;
-
+
result = dsDoDirNodeAuthOnRecordType( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL, &pRecordType->fAttributeValueData );
}
while ( 0 );
-
+
/* clean up */
if (pAuthType != NULL) {
dsDataNodeDeAllocate( dsRef, pAuthType );
dsCloseDirService(dsRef);
dsRef = 0;
}
-
+
return result;
}
{
int ret;
long odResult = eDSAuthFailed;
-
+
/*
* We can only authenticate user requests which HAVE
* a User-Name attribute.
REDEBUG("You set 'Auth-Type = OpenDirectory' for a request that does not contain a User-Password attribute!");
return RLM_MODULE_INVALID;
}
-
+
odResult = od_check_passwd(request->username->vp_strvalue,
request->password->vp_strvalue);
switch(odResult) {
case eDSNoErr:
ret = RLM_MODULE_OK;
break;
-
+
case eDSAuthUnknownUser:
case eDSAuthInvalidUserName:
case eDSAuthNewPasswordRequired:
case eDSAuthInvalidComputer:
ret = RLM_MODULE_USERLOCK;
break;
-
+
default:
ret = RLM_MODULE_REJECT;
break;
}
-
+
if (ret != RLM_MODULE_OK) {
RDEBUG("[%s]: Invalid password", request->username->vp_strvalue);
return ret;
}
-
+
return RLM_MODULE_OK;
}
uuid_t guid_nasgroup;
int err;
char host_ipaddr[128] = {0};
-
+
if (!request || !request->username) {
RDEBUG("OpenDirectory requires a User-Name attribute.");
return RLM_MODULE_NOOP;
}
-
+
/* resolve SACL */
uuid_clear(guid_sacl);
groupdata = getgrnam(kRadiusSACLName);
if (err != 0) {
ERROR("rlm_opendirectory: The group \"%s\" does not have a GUID.", kRadiusSACLName);
return RLM_MODULE_FAIL;
- }
+ }
}
else {
RDEBUG("The SACL group \"%s\" does not exist on this system.", kRadiusSACLName);
}
-
+
/* resolve client access list */
uuid_clear(guid_nasgroup);
host_ipaddr, sizeof(host_ipaddr)));
}
}
-
+
if (uuid_is_null(guid_sacl) && uuid_is_null(guid_nasgroup)) {
RDEBUG("no access control groups, all users allowed.");
if (pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) {
if (err != 0)
uuid_clear(uuid);
}
-
+
if (uuid_is_null(uuid)) {
REDEBUG("Could not get the user's uuid");
return RLM_MODULE_NOTFOUND;
}
-
+
if (!uuid_is_null(guid_sacl)) {
err = mbr_check_service_membership(uuid, kRadiusServiceName, &ismember);
if (err != 0) {
REDEBUG("Failed to check group membership");
return RLM_MODULE_FAIL;
}
-
+
if (ismember == 0) {
REDEBUG("User is not authorized");
return RLM_MODULE_USERLOCK;
}
}
-
+
if (!uuid_is_null(guid_nasgroup)) {
err = mbr_check_membership_refresh(uuid, guid_nasgroup, &ismember);
if (err != 0) {
REDEBUG("Failed to check group membership");
return RLM_MODULE_FAIL;
}
-
+
if (ismember == 0) {
REDEBUG("User is not authorized");
return RLM_MODULE_USERLOCK;
}
}
-
+
if (pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) {
pairmake_config("Auth-Type", kAuthType, T_OP_EQ);
RDEBUG("Setting Auth-Type = %s", kAuthType);
//!< must have %s.
uint8_t hmac_key[16]; //!< because it doesn't track State
-
+
int challenge_len; //!< Challenge length, min 5 digits.
int challenge_delay; //!< Max delay time for response, in seconds.
int allow_sync; //!< Useful to override pwdfile
if (!opt->mschap_mppe_policy) {
return;
}
-
+
/*
* Generate the MS-CHAP-MPPE-Keys attribute. This is not specified
* anywhere -- RFC 2548, par. 2.4.1 is the authority but it has
uint8_t password_unicode[2 * OTP_MAX_PASSCODE_LEN];
uint8_t password_md[MD4_DIGEST_LENGTH];
uint8_t mppe_keys[32];
-
+
/* 0x ASCII(mppe_keys) '\0' */
char mppe_keys_string[2 + (2 * sizeof(mppe_keys)) + 1];
password_unicode[i * 2] = *passcode++;
password_unicode[i * 2 + 1] = 0;
}
-
+
/* first md4 */
(void) MD4(password_unicode, 2 * passcode_len, password_md);
/* second md4 */
/* Whew. Now stringify it for pairmake(). */
mppe_keys_string[0] = '0';
mppe_keys_string[1] = 'x';
-
+
for (i = 0; i < 32; ++i) {
(void) sprintf(&mppe_keys_string[i*2+2], "%02X", mppe_keys[i]);
}
-
+
pairmake_reply("MS-CHAP-MPPE-Keys", mppe_keys_string, T_OP_EQ);
} /* (doing mppe) */
break; /* PWE_MSCHAP */
for (i = 0; i < sizeof(auth_md_string) - 1; ++i) {
(void) sprintf(&auth_octet_string[i * 2 +4], "%02X", auth_md_string[i]);
}
-
+
pairmake_reply("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
} /* Generate mutual auth info. */
if (!opt->mschapv2_mppe_policy) {
return;
}
-
+
/*
* Generate the MPPE initial session key, per RFC 3079.
* (Although, RFC 2548 leaves us guessing at how to generate this.)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-
+
uint8_t SHSpad2[40] = {
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
for (i = 0; i < sizeof(MasterSendKey); ++i) {
(void) sprintf(&mppe_key_string[i*2+2], "%02X", MasterSendKey[i]);
}
-
+
pairmake_reply("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
/*
}
pairmake_reply("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
} /* (doing mppe) */
-
+
break; /* PWE_MSCHAP2 */
} /* PWE_MSCHAP2 */
AUTH("rlm_otp: username [%s] too long", username);
return RLM_MODULE_REJECT;
}
-
+
/* we already know challenge is short enough */
otp_request.version = 2;
-
+
strcpy(otp_request.username, username);
strcpy(otp_request.challenge, challenge);
-
+
otp_request.pwe.pwe = pwe;
/*
rvp = pairfind(request->packet->vps, pwattr[pwe]->attr,
pwattr[pwe]->vendor, TAG_ANY);
-
+
/* this is just to quiet Coverity */
if (!rvp || !cvp) {
return RLM_MODULE_REJECT;
if (rvp->length >= sizeof(otp_request.pwe.u.pap.passcode)) {
AUTH("rlm_otp: passcode for [%s] too long",
username);
-
+
return RLM_MODULE_REJECT;
}
if (cvp->length > 16) {
AUTH("rlm_otp: CHAP challenge for [%s] "
"too long", username);
-
+
return RLM_MODULE_INVALID;
}
-
+
if (rvp->length != 17) {
AUTH("rlm_otp: CHAP response for [%s] "
"wrong size", username);
-
+
return RLM_MODULE_INVALID;
}
-
+
(void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_octets,
cvp->length);
-
+
otp_request.pwe.u.chap.clen = cvp->length;
(void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_octets,
rvp->length);
-
+
otp_request.pwe.u.chap.rlen = rvp->length;
break;
if (cvp->length != 8) {
AUTH("rlm_otp: MS-CHAP challenge for "
"[%s] wrong size", username);
-
+
return RLM_MODULE_INVALID;
}
-
+
if (rvp->length != 50) {
AUTH("rlm_otp: MS-CHAP response for [%s] "
"wrong size", username);
-
+
return RLM_MODULE_INVALID;
}
(void) memcpy(otp_request.pwe.u.chap.challenge,
if (cvp->length != 16) {
AUTH("rlm_otp: MS-CHAP2 challenge for "
"[%s] wrong size", username);
-
+
return RLM_MODULE_INVALID;
}
-
+
if (rvp->length != 50) {
AUTH("rlm_otp: MS-CHAP2 response for [%s] "
"wrong size", username);
-
+
return RLM_MODULE_INVALID;
}
-
+
(void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_octets,
cvp->length);
otp_request.pwe.u.chap.clen = cvp->length;
-
+
(void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_octets,
rvp->length);
otp_request.pwe.u.chap.rlen = rvp->length;
if (rc == OTP_RC_OK) {
(void) strcpy(passcode, otp_reply.passcode);
}
-
+
return otprc2rlmrc(rc);
}
if (!tryagain--) {
return -1;
}
-
+
fdp = otp_getfd(opt);
if (!fdp || fdp->fd == -1) {
return -1;
if (reply->version != 1) {
AUTH("rlm_otp: otpd reply for [%s] invalid "
"(version %d != 1)", request->username, reply->version);
-
+
otp_putfd(fdp, 1);
return -1;
}
if (reply->passcode[OTP_MAX_PASSCODE_LEN] != '\0') {
AUTH("rlm_otp: otpd reply for [%s] invalid "
"(passcode)", request->username);
-
+
otp_putfd(fdp, 1);
return -1;
}
return -1;
}
}
-
+
if (!n) {
ERROR("rlm_otp: %s: otpd disconnect", __func__);
otp_putfd(fdp, 1);
return 0;
}
-
+
nread += n;
} /* while (more to read) */
} else {
ERROR("rlm_otp: %s: write to otpd: %s",
__func__, strerror(errno));
-
+
otp_putfd(fdp, 1);
return errno;
-
+
}
}
-
+
nleft -= nwrote;
}
-
+
return 0;
}
if (sp_len > sizeof(sa.sun_path) - 1) {
ERROR("rlm_otp: %s: rendezvous point name too long",
__func__);
-
+
return -1;
}
sa.sun_family = AF_UNIX;
if (fd == -1) {
ERROR("rlm_otp: %s: socket: %s", __func__,
strerror(errno));
-
+
return -1;
}
if (connect(fd, (struct sockaddr *) &sa,
sizeof(sa.sun_family) + sp_len) == -1) {
-
+
ERROR("rlm_otp: %s: connect(%s): %s",
__func__, path, strerror(errno));
-
+
(void) close(fd);
-
+
return -1;
}
-
+
return fd;
}
fdp = rad_malloc(sizeof(*fdp));
otp_pthread_mutex_init(&fdp->mutex, NULL);
otp_pthread_mutex_lock(&fdp->mutex);
-
+
/* insert new fd at head */
otp_pthread_mutex_lock(&otp_fd_head_mutex);
fdp->next = otp_fd_head;
otp_fd_head = fdp;
otp_pthread_mutex_unlock(&otp_fd_head_mutex);
-
+
/* initialize */
fdp->path = opt->otpd_rp;
fdp->fd = -1;
if (fdp->fd == -1) {
fdp->fd = otp_connect(fdp->path);
}
-
+
return fdp;
}
da = dict_attrbyname("CHAP-Challenge");
if (da) {
pwattr[2] = da;
-
+
da = dict_attrbyname("CHAP-Password");
if (da) {
pwattr[3] = da;
da = dict_attrbyname("MS-CHAP-Challenge");
if (da) {
pwattr[4] = da;
-
+
da = dict_attrbyname("MS-CHAP-Response");
if (da) {
pwattr[5] = da;
da = dict_attrbyname("MS-CHAP-Challenge");
if (da) {
pwattr[6] = da;
-
+
da = dict_attrbyname("MS-CHAP2-Response");
if (da) {
pwattr[7] = da;
if (!pwattr[i]) {
continue;
}
-
+
if (pairfind(request->packet->vps, pwattr[i]->attr,
pwattr[i]->vendor, TAG_ANY) &&
pairfind(request->packet->vps, pwattr[i + 1]->attr,
pwattr[i + 1]->vendor, TAG_ANY)) {
DEBUG("rlm_otp: %s: password attributes %s, %s",
__func__, pwattr[i]->name, pwattr[i + 1]->name);
-
+
return i + 1; /* Can't return 0 (indicates failure) */
}
}
* Generate the state.
*/
p = state;
-
+
/*
* Add the challenge (which is already ASCII encoded)
*/
p += fr_bin2hex((uint8_t const *) challenge, p, clen);
-
+
/* Add the flags and time. */
p += fr_bin2hex((uint8_t *) &flags, p, 4);
p += fr_bin2hex((uint8_t *) &when, p, 4);
-
+
/* Add the hmac. */
p += fr_bin2hex(hmac, p, 16);
size_t bytes_read = 0;
size_t bytes_left;
int n;
-
+
while (bytes_read < len) {
bytes_left = len - bytes_read;
uint32_t r = fr_rand();
n = sizeof(r) < bytes_left ? sizeof(r) : bytes_left;
-
+
memcpy(rnd_data + bytes_read, &r, n);
-
+
bytes_read += n;
}
}
if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_init: %s",
caller, strerror(rc));
-
+
exit(1);
}
}
if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_lock: %s",
caller, strerror(rc));
-
+
exit(1);
}
}
if (rc && rc != EBUSY) {
ERROR("rlm_otp: %s: pthread_mutex_trylock: %s",
caller, strerror(rc));
-
+
exit(1);
}
if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_unlock: %s",
caller, strerror(rc));
-
+
exit(1);
}
}
/* set the instance name (for use with authorize()) */
inst->name = cf_section_name2(conf);
if (!inst->name) inst->name = cf_section_name1(conf);
-
+
return 0;
}
auth_type_found = 1;
if (strcmp(vp->vp_strvalue, inst->name)) {
return RLM_MODULE_NOOP;
- }
+ }
}
}
/* The State attribute will be present if this is a response. */
if (pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY) != NULL) {
DEBUG("rlm_otp: autz: Found response to Access-Challenge");
-
+
return RLM_MODULE_OK;
}
if (!request->username) {
RWDEBUG("Attribute \"User-Name\" "
"required for authentication.");
-
+
return RLM_MODULE_INVALID;
}
RWDEBUG("Attribute "
"\"User-Password\" or equivalent required "
"for authentication.");
-
+
return RLM_MODULE_INVALID;
}
len = otp_gen_state(gen_state, challenge, inst->challenge_len,
0, now, inst->hmac_key);
-
+
vp = paircreate(request->reply, PW_STATE, 0);
if (!vp) {
return RLM_MODULE_FAIL;
if (!vp) {
return RLM_MODULE_FAIL;
}
-
+
pairstrcpy(vp, challenge);
vp->op = T_OP_SET;
-
+
pairadd(&request->reply->vps, vp);
-
+
/*
* Then add the message to the user to they known
* what the challenge value is.
*/
-
+
len = radius_axlat(&expanded, request, inst->chal_prompt, NULL, NULL);
if (len < 0) {
return RLM_MODULE_FAIL;
}
-
+
vp = paircreate(request->reply, PW_REPLY_MESSAGE, 0);
if (!vp) {
talloc_free(expanded);
return RLM_MODULE_FAIL;
}
-
+
(void) talloc_steal(vp, expanded);
vp->vp_strvalue = expanded;
vp->length = len;
vp->op = T_OP_SET;
vp->type = VT_DATA;
-
+
pairadd(&request->reply->vps, vp);
}
* The server will take care of sending it to the user.
*/
request->reply->code = PW_ACCESS_CHALLENGE;
-
+
DEBUG("rlm_otp: Sending Access-Challenge.");
if (!auth_type_found) {
pairmake_config("Auth-Type", inst->name, T_OP_EQ);
}
-
+
return RLM_MODULE_HANDLED;
}
int rc;
otp_pwe_t pwe;
VALUE_PAIR *vp;
-
+
char challenge[OTP_MAX_CHALLENGE_LEN]; /* cf. authorize() */
char passcode[OTP_MAX_PASSCODE_LEN + 1];
if (!request->username) {
RWDEBUG("Attribute \"User-Name\" required "
"for authentication.");
-
+
return RLM_MODULE_INVALID;
}
-
+
username = request->username->vp_strvalue;
-
+
pwe = otp_pwe_present(request);
if (pwe == 0) {
RWDEBUG("Attribute \"User-Password\" "
"or equivalent required for authentication.");
-
+
return RLM_MODULE_INVALID;
}
if (vp) {
char gen_state[OTP_MAX_RADSTATE_LEN]; //!< State as hexits
uint8_t bin_state[OTP_MAX_RADSTATE_LEN];
-
+
int32_t then; //!< State timestamp.
size_t elen; //!< Expected State length.
size_t len;
len = fr_hex2bin(vp->vp_strvalue, bin_state, vp->length);
if (len != (vp->length / 2)) {
REDEBUG("bad radstate for [%s]: not hex", username);
-
+
return RLM_MODULE_INVALID;
}
*/
if (memcmp(gen_state, vp->vp_octets, vp->length)) {
REDEBUG("bad radstate for [%s]: hmac", username);
-
+
return RLM_MODULE_REJECT;
}
return RLM_MODULE_REJECT;
}
}
-
+
/* do it */
rc = otp_pw_valid(request, pwe, challenge, inst, passcode);
int found_pw = false;
VALUE_PAIR *vp;
vp_cursor_t cursor;
-
+
for (vp = paircursor(&cursor, &request->config_items);
vp;
vp = pairnext(&cursor)) {
new_vp = radius_paircreate(request,
&request->config_items,
attr, 0);
-
+
/*
* The data after the '}' may be binary,
* so we copy it via memcpy.
rlm_rcode_t rc = RLM_MODULE_INVALID;
vp_cursor_t cursor;
int (*auth_func)(REQUEST *, VALUE_PAIR *) = NULL;
-
+
if (!request->password ||
(request->password->da->attr != PW_USER_PASSWORD)) {
return hashentry;
}
}
-
+
return NULL;
}
if (ht->fp) {
offsetof(struct passwd_instance, format), NULL, NULL },
{ "delimiter", PW_TYPE_STRING_PTR,
offsetof(struct passwd_instance, delimiter), NULL, ":" },
-
+
{ "ignorenislike", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
offsetof(struct passwd_instance, ignore_nislike), NULL, NULL },
{ "ignore_nislike", PW_TYPE_BOOLEAN,
offsetof(struct passwd_instance, ignore_nislike), NULL, "yes" },
{ "ignoreempty", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, ignore_empty), NULL, NULL },
+ offsetof(struct passwd_instance, ignore_empty), NULL, NULL },
{ "ignore_empty", PW_TYPE_BOOLEAN,
offsetof(struct passwd_instance, ignore_empty), NULL, "yes" },
-
+
{ "allowmultiplekeys", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
offsetof(struct passwd_instance, allow_multiple), NULL, NULL },
{ "allow_multiple_keys", PW_TYPE_BOOLEAN,
offsetof(struct passwd_instance, allow_multiple), NULL, "no" },
{ "hashsize", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, hash_size), NULL, NULL },
+ offsetof(struct passwd_instance, hash_size), NULL, NULL },
{ "hash_size", PW_TYPE_INTEGER,
offsetof(struct passwd_instance, hash_size), NULL, "100" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
if (!key) {
return RLM_MODULE_NOTFOUND;
}
-
+
for (i = paircursor(&cursor, &key);
i;
i = pairfindnext(&cursor, inst->keyattr->attr, inst->keyattr->vendor, TAG_ANY)) {
addresult(inst, request, request->reply, &request->reply->vps, pw, 1, "reply_items");
addresult(inst, request, request->packet, &request->packet->vps, pw, 2, "request_items");
} while ((pw = get_next(buffer, inst->ht, &last_found)));
-
+
if (!inst->allow_multiple) {
break;
}
}
-
+
return RLM_MODULE_OK;
#undef inst
static PerlInterpreter *rlm_perl_clone(PerlInterpreter *perl, pthread_key_t *key)
{
int ret;
-
+
PerlInterpreter *interp;
UV clone_flags = 0;
ret = pthread_setspecific(*key, interp);
if (ret != 0) {
DEBUG("rlm_perl: Failed associating interpretor with thread %s", strerror(ret));
-
+
rlm_perl_destruct(interp);
return NULL;
}
ENTER;SAVETMPS;
PUSHMARK(SP);
-
+
p = fmt;
while ((q = strchr(p, ' '))) {
XPUSHs(sv_2mortal(newSVpv(p, p - q)));
-
+
p = q + 1;
}
-
+
PUTBACK;
count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);
LEAVE ;
}
-
+
return ret;
}
/*
inst->thread_key = rad_malloc(sizeof(*inst->thread_key));
memset(inst->thread_key,0,sizeof(*inst->thread_key));
-
+
rlm_perl_make_key(inst->thread_key);
#endif
char arg[] = "0";
-
+
embed[0] = NULL;
if (inst->perl_flags) {
embed[1] = inst->perl_flags;
int len;
hv_undef(rad_hv);
-
+
/*
* Copy the valuepair list so we can remove attributes
* we've already processed. This is a horrible hack to
av_push(av, newSVpv(buffer, len));
}
(void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
-
+
/*
* Attribute has a single value, so its value just gets
* added to the hash.
HV *rad_request_proxy_hv;
HV *rad_request_proxy_reply_hv;
#endif
-
+
/*
* Radius has told us to call this function, but none
* is defined.
dTHXa(interp);
PERL_SET_CONTEXT(interp);
}
-
+
pthread_mutex_unlock(&inst->clone_mutex);
#else
PERL_SET_CONTEXT(inst->perl);
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.
*/
if (!ptr) {
continue;
}
-
+
/*
* Cisco-AVPair's get packed as:
*
{
int number = 1;
vp_cursor_t cursor;
-
+
for (vp = paircursor(&cursor, &vp);
vp;
vp = pairnext(&cursor)) {
if (vp->da->vendor != 12394) {
continue;
}
-
+
if (vp->da->type != PW_TYPE_STRING) {
continue;
}
-
+
da = dict_attrbyvalue(number, 12394);
if (!da) {
continue;
}
-
+
vp->da = da;
number++;
if (!ev) {
return;
}
-
+
/*
* FIXME: write 100's of lines of code to decode
* each data structure above.
if (tmp->da->vendor != 0) {
continue;
}
-
+
if (tmp->da->attr != PW_PROXY_STATE) {
continue;
}
-
+
num_proxy_state++;
}
*/
return RLM_MODULE_NOOP;
}
-
+
for (i = hints; i; i = i->next) {
/*
* Use "paircompare", which is a little more general...
*/
add = paircopy(request->packet, i->reply);
ft = fallthrough(add);
-
+
pairdelete(&add, PW_STRIP_USER_NAME, 0, TAG_ANY);
pairdelete(&add, PW_FALL_THROUGH, 0, TAG_ANY);
radius_xlat_move(request, &request->packet->vps, &add);
-
+
pairfree(&add);
updated = 1;
if (!ft) {
if (updated == 0) {
return RLM_MODULE_NOOP;
}
-
+
return RLM_MODULE_UPDATED;
}
if (!huntgroups) {
return RLM_MODULE_OK;
}
-
+
for (i = huntgroups; i; i = i->next) {
/*
* See if this entry matches.
if (paircompare(request, request_pairs, i->check, NULL) != 0) {
continue;
}
-
+
/*
* Now check for access.
*/
ret = pairlist_read(inst, inst->huntgroup_file, &(inst->huntgroups), 0);
if (ret < 0) {
ERROR("rlm_preprocess: Error reading %s", inst->huntgroup_file);
-
+
return -1;
}
}
ret = pairlist_read(inst, inst->hints_file, &(inst->hints), 0);
if (ret < 0) {
ERROR("rlm_preprocess: Error reading %s", inst->hints_file);
-
+
return -1;
}
}
vp = radius_paircreate(request, &request->packet->vps, PW_CHAP_CHALLENGE, 0);
vp->length = AUTH_VECTOR_LEN;
vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
-
+
memcpy(p, request->packet->vector, AUTH_VECTOR_LEN);
}
RIDEBUG("No huntgroup access: [%s] (%s)",
request->username ? request->username->vp_strvalue : "<NO User-Name>",
auth_name(buf, sizeof(buf), request, 1));
-
+
return r;
}
vp = radius_paircreate(request, &request->packet->vps, PW_EVENT_TIMESTAMP, 0);
vp->vp_date = request->packet->timestamp.tv_sec;
-
+
delay = pairfind(request->packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
if (delay) {
vp->vp_date -= delay->vp_integer;
struct py_function_def {
PyObject *module;
PyObject *function;
-
+
char *module_name;
char *function_name;
};
{
int status;
char *msg;
-
+
if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
return NULL;
}
radlog(status, "%s", msg);
Py_INCREF(Py_None);
-
+
return Py_None;
}
*pTraceback = NULL,
*pStr1 = NULL,
*pStr2 = NULL;
-
+
Pyx_BLOCK_THREADS
PyErr_Fetch(&pType, &pValue, &pTraceback);
goto failed;
ERROR("rlm_python:EXCEPT:%s: %s", PyString_AsString(pStr1), PyString_AsString(pStr2));
-
+
failed:
Py_XDECREF(pStr1);
Py_XDECREF(pStr2);
Py_XDECREF(pType);
Py_XDECREF(pValue);
Py_XDECREF(pTraceback);
-
+
Pyx_UNBLOCK_THREADS
}
static char name[] = "radiusd";
if (radiusd_module) return 0;
-
+
Py_SetProgramName(name);
Py_InitializeEx(0); /* Don't override signal handlers */
PyEval_InitThreads(); /* This also grabs a lock */
if ((radiusd_module = Py_InitModule3("radiusd", radiusd_methods,
"FreeRADIUS Module.")) == NULL)
goto failed;
-
+
for (i = 0; radiusd_constants[i].name; i++) {
if ((PyModule_AddIntConstant(radiusd_module, radiusd_constants[i].name,
radiusd_constants[i].value)) < 0) {
goto failed;
}
}
-
+
PyEval_ReleaseLock(); /* Drop lock grabbed by InitThreads */
-
+
DEBUG("mod_init done");
return 0;
-
+
failed:
mod_error();
Py_XDECREF(radiusd_module);
{
PyObject *pStr = NULL;
char buf[1024];
-
+
/* Look at the vp_print_name? */
-
+
if (vp->da->flags.has_tag)
pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
else
pStr = PyString_FromString(vp->da->name);
-
+
if (!pStr)
goto failed;
-
+
PyTuple_SET_ITEM(pPair, 0, pStr);
-
+
vp_prints_value(buf, sizeof(buf), vp, '"');
-
+
if ((pStr = PyString_FromString(buf)) == NULL)
goto failed;
PyTuple_SET_ITEM(pPair, 1, pStr);
-
+
return 0;
-
+
failed:
return -1;
}
PyObject *pArgs = NULL;
int tuplelen;
int ret;
-
+
PyGILState_STATE gstate;
/* Return with "noop" if the function is not defined. */
if (!pFunc)
return RLM_MODULE_NOOP;
-
+
/* Default return value is "OK, continue" */
ret = RLM_MODULE_OK;
-
+
/*
* We will pass a tuple containing (name, value) tuples
* We can safely use the Python function to build up a
}
gstate = PyGILState_Ensure();
-
+
if (tuplelen == 0) {
Py_INCREF(Py_None);
pArgs = Py_None;
vp;
vp = pairnext(&cursor), i++) {
PyObject *pPair;
-
+
/* The inside tuple has two only: */
if ((pPair = PyTuple_New(2)) == NULL)
goto failed;
-
+
if (mod_populate_vptuple(pPair, vp) == 0) {
/* Put the tuple inside the container */
PyTuple_SET_ITEM(pArgs, i, pPair);
}
}
}
-
+
/* Call Python function. */
pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
-
+
if (!pRet)
goto failed;
-
+
if (!request)
goto okay;
*/
if (PyTuple_CheckExact(pRet)) {
PyObject *pTupleInt;
-
+
if (PyTuple_GET_SIZE(pRet) != 3) {
ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
goto failed;
}
-
+
pTupleInt = PyTuple_GET_ITEM(pRet, 0);
if (!PyInt_CheckExact(pTupleInt)) {
ERROR("rlm_python:%s: first tuple element not an integer", funcname);
Py_DECREF(pRet);
PyGILState_Release(gstate);
return ret;
-
+
failed:
mod_error();
Py_XDECREF(pArgs);
Py_XDECREF(pRet);
PyGILState_Release(gstate);
-
+
return RLM_MODULE_FAIL;
}
{
char const *funcname = "mod_load_function";
PyGILState_STATE gstate;
-
+
gstate = PyGILState_Ensure();
-
+
if (def->module_name != NULL && def->function_name != NULL) {
if ((def->module = PyImport_ImportModule(def->module_name)) == NULL) {
ERROR("rlm_python:%s: module '%s' is not found", funcname, def->module_name);
goto failed;
}
-
+
if ((def->function = PyObject_GetAttrString(def->module, def->function_name)) == NULL) {
ERROR("rlm_python:%s: function '%s.%s' is not found", funcname, def->module_name, def->function_name);
goto failed;
}
-
+
if (!PyCallable_Check(def->function)) {
ERROR("rlm_python:%s: function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
goto failed;
}
PyGILState_Release(gstate);
return 0;
-
+
failed:
mod_error();
ERROR("rlm_python:%s: failed to import python function '%s.%s'", funcname, def->module_name, def->function_name);
static void mod_instance_clear(rlm_python_t *inst)
{
#define A(x) mod_funcdef_clear(&inst->x)
-
+
A(instantiate);
A(authorize);
A(authenticate);
{
rlm_python_t *inst = instance;
int ret;
-
+
ret = do_python(NULL, inst->detach.function, "detach");
-
+
mod_instance_clear(inst);
return ret;
}
if (write(fd, &u, sizeof(u)) < 0) {
REDEBUG("Failed writing: %s", strerror(errno));
-
+
close(fd);
return RLM_MODULE_FAIL;
}
port == cl->port)
break;
}
-
+
return cl;
}
char const *nas;
NAS_PORT *cache;
int r;
-
+
char *filename = NULL;
char *expanded = NULL;
} else {
ut.proto = 'T';
}
-
+
ut.time = t - ut.delay;
/*
if (status == PW_STATUS_ACCOUNTING_ON && (ut.nas_address != htonl(INADDR_NONE))) {
RIDEBUG("NAS %s restarted (Accounting-On packet seen)", nas);
rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
-
+
goto finish;
}
if (status == PW_STATUS_ACCOUNTING_OFF && (ut.nas_address != htonl(INADDR_NONE))) {
- RIDEBUG("NAS %s rebooted (Accounting-Off packet seen)", nas);
+ RIDEBUG("NAS %s rebooted (Accounting-Off packet seen)", nas);
rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
-
+
goto finish;
}
if (status != PW_STATUS_START && status != PW_STATUS_STOP && status != PW_STATUS_ALIVE) {
REDEBUG("NAS %s port %u unknown packet type %d)", nas, ut.nas_port, status);
rcode = RLM_MODULE_NOOP;
-
+
goto finish;
}
*/
if (radius_axlat(&expanded, request, inst->username, NULL, NULL) < 0) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
strlcpy(ut.login, expanded, RUT_NAMESIZE);
if (!port_seen) {
RWDEBUG2("No NAS-Port seen. Cannot do anything. Checkrad will probably not work!");
rcode = RLM_MODULE_NOOP;
-
+
goto finish;
}
if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) {
RDEBUG2("Not recording administrative user");
rcode = RLM_MODULE_NOOP;
-
+
goto finish;
}
if (fd < 0) {
REDEBUG("Error accessing file %s: %s", filename, strerror(errno));
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
if (u.type == P_LOGIN) {
RWDEBUG("Logout entry for NAS %s port %u has wrong ID", nas, u.nas_port);
}
-
+
r = -1;
break;
}
r = -1;
break;
}
-
+
RWDEBUG("Login entry for NAS %s port %u wrong order", nas, u.nas_port);
r = -1;
break;
} else {
off -= sizeof(u);
}
-
+
r = 1;
break;
} /* read the file until we find a match */
ut.type = P_LOGIN;
if (write(fd, &ut, sizeof(u)) < 0) {
REDEBUG("Failed writing: %s", strerror(errno));
-
+
rcode = RLM_MODULE_FAIL;
goto finish;
}
u.delay = ut.delay;
if (write(fd, &u, sizeof(u)) < 0) {
REDEBUG("Failed writing: %s", strerror(errno));
-
+
rcode = RLM_MODULE_FAIL;
goto finish;
}
}
finish:
-
+
talloc_free(filename);
-
+
if (fd > -1) {
close(fd); /* and implicitely release the locks */
}
-
+
return rcode;
}
#endif
uint32_t ipno = 0;
char const *call_num = NULL;
rlm_radutmp_t *inst = instance;
-
+
char *expanded = NULL;
ssize_t len;
* Error accessing the file.
*/
ERROR("rlm_radumtp: Error accessing file %s: %s", expanded, strerror(errno));
-
+
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
TALLOC_FREE(expanded);
len = radius_axlat(&expanded, request, inst->username, NULL, NULL);
if (len < 0) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if (!len) {
rcode = RLM_MODULE_NOOP;
* Loop over utmp, counting how many people MAY be logged in.
*/
while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) ||
+ if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) ||
(!inst->case_sensitive && (strncasecmp(expanded, u.login, RUT_NAMESIZE) == 0))) &&
(u.type == P_LOGIN)) {
++request->simul_count;
*/
if ((request->simul_count < request->simul_max) || !inst->check_nas) {
rcode = RLM_MODULE_OK;
-
+
goto finish;
}
lseek(fd, (off_t)0, SEEK_SET);
if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
ipno = vp->vp_ipaddr;
}
-
+
if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
call_num = vp->vp_strvalue;
}
} else {
RWDEBUG("Failed to check the terminal server for user '%s'.", utmp_login);
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
}
}
finish:
-
+
talloc_free(expanded);
-
+
if (fd > -1) {
close(fd); /* and implicitely release the locks */
}
-
+
return rcode;
}
#endif
|| (request->proxy != NULL)
#endif
) {
-
+
RDEBUG2("Proxy reply, or no User-Name. Ignoring.");
return RLM_MODULE_OK;
}
vp = pairfind(request->packet->vps, PW_OPERATOR_NAME, 0, TAG_ANY);
if (!vp) return RLM_MODULE_NOOP;
-
+
/*
* Catch the case of broken dictionaries.
*/
ret = -1;
goto release;
}
-
+
strlcpy(out, buffer_ptr, freespace);
release:
rlm_redis_finish_query(dissocket);
fr_connection_release(inst->pool, dissocket);
-
+
return ret;
}
offsetof(rlm_rediswho_t, trim_count), NULL, NULL},
{ "trim_count", PW_TYPE_INTEGER,
offsetof(rlm_rediswho_t, trim_count), NULL, "-1"},
-
+
{ NULL, -1, 0, NULL, NULL}
};
REDEBUG2("Cannot Replicate to unknown realm \"%s\"", realm->name);
continue;
}
-
+
/*
* We shouldn't really do this on every loop.
*/
request->packet->code);
cleanup(packet);
return RLM_MODULE_FAIL;
-
+
case PW_AUTHENTICATION_REQUEST:
pool = realm->auth_pool;
break;
-
+
#ifdef WITH_ACCOUNTING
-
+
case PW_ACCOUNTING_REQUEST:
pool = realm->acct_pool;
break;
#endif
-
+
#ifdef WITH_COA
case PW_COA_REQUEST:
case PW_DISCONNECT_REQUEST:
break;
#endif
}
-
+
if (!pool) {
RWDEBUG2("Cancelling replication to Realm %s, as the realm is local.", realm->name);
continue;
}
-
+
home = home_server_ldb(realm->name, pool, request);
if (!home) {
REDEBUG2("Failed to find live home server for realm %s",
realm->name);
continue;
}
-
+
/*
* For replication to multiple servers we re-use the packet
* we built here.
rcode = RLM_MODULE_FAIL;
goto done;
}
-
+
vps = radius_list(request, list);
if (!vps) {
RWDEBUG("List '%s' doesn't exist for "
rcode = RLM_MODULE_INVALID;
goto done;
}
-
+
/*
* Don't assume the list actually contains any
* attributes.
goto done;
}
}
-
+
/*
packet->dst_port = home->port;
memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
packet->src_port = 0;
-
+
/*
* Encode, sign and then send the packet.
*/
*/
rcode = RLM_MODULE_OK;
}
-
+
done:
-
+
cleanup(packet);
return rcode;
}
if ((ctx->chunk) && (ctx->chunk <= s)) {
s = (ctx->chunk - 1);
}
-
+
if (ctx->state == READ_STATE_END) return 0;
if (ctx->state == READ_STATE_INIT) {
ctx->first = current = rad_malloc((sizeof(tmp) * (count + 1)));
ctx->next = ctx->first;
-
+
current[0] = NULL;
for (tmp = paircursor(&cursor, &request->packet->vps);
tmp;
tmp = pairnext(&cursor)) {
- *current++ = tmp;
+ *current++ = tmp;
}
-
+
current = ctx->first;
if (!sort || (count < 2)) return;
char const *attribute;
char *name = NULL;
char *value = NULL;
-
+
char *expanded = NULL;
const DICT_ATTR *da;
p = (q + 1);
RDEBUG("Decoding attribute \"%s\"", name);
-
+
request_name = radius_request_name(&attribute, REQUEST_CURRENT);
if (request_name == REQUEST_UNKNOWN) {
RWDEBUG("Invalid request qualifier, skipping");
RDEBUG2("\tLength : %i", curl_len);
RDEBUG2("\tValue : \"%s\"", value);
-
+
RDEBUG("Performing xlat expansion of response value");
-
+
if (!radius_axlat(&expanded, request, value, NULL, NULL)) {
goto skip;
}
ERROR("rlm_rest (%s): Failed creating"
" valuepair", instance->xlat_name);
talloc_free(expanded);
-
+
goto error;
}
break;
}
}
-
+
if (vp->op != T_OP_ADD) {
current[0] = da;
current[1] = NULL;
char const *value, *to_parse;
char *expanded = NULL;
int ret;
-
+
VALUE_PAIR *vp;
/*
if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
return NULL;
}
-
+
to_parse = expanded;
} else {
to_parse = value;
if (!vp) {
REDEBUG("Failed creating valuepair");
talloc_free(expanded);
-
+
return NULL;
}
vp->op = flags->op;
-
+
ret = pairparsevalue(vp, to_parse);
talloc_free(expanded);
if (!ret) {
RDEBUG("Incompatible value assignment, skipping");
pairbasicfree(vp);
-
+
return NULL;
}
{
char const *p;
char *q;
-
+
char const *name, *attribute;
struct json_object *value, *idx, *tmp;
const DICT_ATTR *da;
VALUE_PAIR *vp = NULL;
-
+
request_refs_t request_name;
pair_lists_t list_name;
REQUEST *reference = request;
attribute = name;
reference = request;
-
+
/*
* Resolve attribute name to a dictionary entry and
* pairlist.
*/
RDEBUG2("Decoding attribute \"%s\"", name);
-
+
request_name = radius_request_name(&attribute, REQUEST_CURRENT);
if (request_name == REQUEST_UNKNOWN) {
RWDEBUG("Request qualifier unknown, skipping");
json_object_is_type(value, json_type_object)) {
/* TODO: Insert nested VP into VP structure...*/
REDEBUG("Found nested VP, these are not yet supported");
-
+
return NULL;
-
+
/*
vp = json_pairmake(instance, section,
request, value,
char *raw, UNUSED size_t rawlen)
{
char const *p = raw;
-
+
struct json_object *json;
-
+
int max = REST_BODY_MAX_ATTRS;
/*
{
rlm_rest_write_t *ctx = userdata;
REQUEST *request = ctx->request; /* Used by RDEBUG */
-
+
char const *p = ptr, *q;
char *tmp;
}
}
break;
-
+
default:
break;
}
{
rlm_rest_write_t *ctx = userdata;
REQUEST *request = ctx->request; /* Used by RDEBUG */
-
+
char const *p = ptr;
char *tmp;
fr_int2str(http_content_type_table, type, "¿Unknown?"));
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
-
+
if (section->timeout) {
ret = curl_easy_setopt(candle, CURLOPT_TIMEOUT,
section->timeout);
if (ret != CURLE_OK) goto error;
}
-
+
ret = curl_easy_setopt(candle, CURLOPT_PROTOCOLS,
(CURLPROTO_HTTP | CURLPROTO_HTTPS));
if (ret != CURLE_OK) goto error;
-
+
/*
* FreeRADIUS custom headers
*/
(auth <= HTTP_AUTH_ANY_SAFE)) {
ret = curl_easy_setopt(candle, CURLOPT_HTTPAUTH, http_curl_auth[auth]);
if (ret != CURLE_OK) goto error;
-
+
if (username) {
ret = curl_easy_setopt(candle, CURLOPT_USERNAME, username);
if (ret != CURLE_OK) {
goto error;
}
- } else if (section->username) {
+ } else if (section->username) {
if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
goto error;
}
goto error;
}
}
-
+
if (password) {
ret = curl_easy_setopt(candle, CURLOPT_PASSWORD, password);
if (ret != CURLE_OK) {
if (ret != CURLE_OK) {
goto error;
}
- }
+ }
#ifdef CURLOPT_TLSAUTH_USERNAME
} else if (type == HTTP_AUTH_TLS_SRP) {
ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_TYPE, http_curl_auth[auth]);
if (ret != CURLE_OK) {
goto error;
}
- } else if (section->username) {
+ } else if (section->username) {
if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
goto error;
}
goto error;
}
}
-
+
if (password) {
ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_PASSWORD, password);
if (ret != CURLE_OK) {
if (ret != CURLE_OK) {
goto error;
}
- }
+ }
#endif
}
}
-
+
/*
* Set SSL/TLS authentication parameters
*/
section->tls_certificate_file);
if (ret != CURLE_OK) goto error;
}
-
+
if (section->tls_private_key_file) {
ret = curl_easy_setopt(candle,
CURLOPT_SSLKEY,
section->tls_private_key_password);
if (ret != CURLE_OK) goto error;
}
-
+
if (section->tls_ca_file) {
ret = curl_easy_setopt(candle,
CURLOPT_ISSUERCERT,
section->tls_ca_file);
if (ret != CURLE_OK) goto error;
}
-
+
if (section->tls_ca_path) {
ret = curl_easy_setopt(candle,
CURLOPT_CAPATH,
section->tls_ca_path);
if (ret != CURLE_OK) goto error;
}
-
+
if (section->tls_random_file) {
ret = curl_easy_setopt(candle,
CURLOPT_RANDOM_FILE,
section->tls_random_file);
if (ret != CURLE_OK) goto error;
}
-
+
if (section->tls_check_cert) {
ret = curl_easy_setopt(candle,
CURLOPT_SSL_VERIFYHOST,
0);
if (ret != CURLE_OK) goto error;
}
-
+
/*
* Tell CURL how to get HTTP body content, and how to process
* incoming data.
case HTTP_METHOD_GET :
case HTTP_METHOD_DELETE :
return 0;
-
+
case HTTP_METHOD_POST :
case HTTP_METHOD_PUT :
case HTTP_METHOD_CUSTOM :
* @return 0 on success or -1 on error.
*/
int rest_request_perform(UNUSED rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
+ UNUSED rlm_rest_section_t *section,
REQUEST *request, void *handle)
{
rlm_rest_handle_t *randle = handle;
ret = curl_easy_perform(candle);
if (ret != CURLE_OK) {
RERROR("Request failed: %i - %s", ret, curl_easy_strerror(ret));
-
+
return -1;
}
{
char const *p;
char *path_exp = NULL;
-
+
char *scheme;
char const *path;
talloc_free(scheme);
if (len < 0) {
TALLOC_FREE(*out);
-
+
return 0;
}
len = radius_axlat(&path_exp, request, path, rest_uri_escape, NULL);
if (len < 0) {
TALLOC_FREE(*out);
-
+
return 0;
}
*out = talloc_strdup_append(*out, path_exp);
talloc_free(path_exp);
-
+
return outlen += len;
}
typedef struct rlm_rest_section_t {
char const *name;
char *uri;
-
+
char *method_str;
http_method_t method;
char *auth_str;
http_auth_type_t auth;
int require_auth;
-
+
char *tls_certificate_file;
char *tls_private_key_file;
char *tls_private_key_password;
char *tls_random_file;
int tls_check_cert;
int tls_check_cert_cn;
-
+
int timeout;
unsigned int chunk;
} rlm_rest_section_t;
http_body_type_t type, char const *uri,
char const *username, char const *password);
-int rest_request_perform(rlm_rest_t *instance,
+int rest_request_perform(rlm_rest_t *instance,
rlm_rest_section_t *section, REQUEST *request,
void *handle);
offsetof(rlm_rest_section_t, tls_check_cert), NULL, "yes" },
{ "check_cert_cn", PW_TYPE_BOOLEAN,
offsetof(rlm_rest_section_t, tls_check_cert_cn), NULL, "yes" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
offsetof(rlm_rest_section_t, method_str), NULL, "GET" },
{ "body", PW_TYPE_STRING_PTR,
offsetof(rlm_rest_section_t, body_str), NULL, "post" },
-
+
/* User authentication */
{ "auth", PW_TYPE_STRING_PTR,
offsetof(rlm_rest_section_t, auth_str), NULL, "none" },
{
size_t uri_len;
char *uri = NULL;
-
+
int ret;
-
+
RDEBUG("Expanding URI components");
/*
/* TODO: Should really setup section with default values */
return 0;
}
-
+
if (cf_section_parse(cs, config, section_config) < 0) {
return -1;
}
* Add section name (Maybe add to headers later?).
*/
config->name = name;
-
+
/*
* Sanity check
*/
if ((config->username && !config->password) || (!config->username && config->password)) {
cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");
-
+
return -1;
}
* Convert HTTP method auth and body type strings into their
* integer equivalents.
*/
- config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
+ config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
if (config->auth == HTTP_AUTH_UNKNOWN) {
cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
- return -1;
+ return -1;
} else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
"configuration, then recompile this module", config->auth_str);
-
+
return -1;
}
-
+
config->method = fr_str2int(http_method_table, config->method_str,
HTTP_METHOD_CUSTOM);
int hcode;
int rcode = RLM_MODULE_OK;
int ret;
-
+
VALUE_PAIR const *username;
VALUE_PAIR const *password;
-
+
username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
if (!username) {
REDEBUG("Can't perform authentication, 'User-Name' attribute not found in the request");
-
+
return RLM_MODULE_INVALID;
}
-
+
password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
if (!password) {
REDEBUG("Can't perform authentication, 'Cleartext-Password' attribute not found in the control list");
-
+
return RLM_MODULE_INVALID;
}
{
rlm_rest_t *inst = instance;
rlm_rest_section_t *section = &inst->accounting;
-
+
void *handle;
int hcode;
int rcode = RLM_MODULE_OK;
ret = rest_request_decode(inst, section, request, handle);
if (ret < 0) rcode = RLM_MODULE_FAIL;
else if (ret == 0) rcode = RLM_MODULE_OK;
- else rcode = RLM_MODULE_UPDATED;
+ else rcode = RLM_MODULE_UPDATED;
} else {
rcode = RLM_MODULE_INVALID;
}
for (vp = paircursor(&cursor, &request->packet->vps);
vp;
vp = pairnext(&cursor)) {
- n_tuple++;
+ n_tuple++;
}
}
if (request) {
rb_reply_items = rb_ary_entry(rb_result, 1);
rb_config_items = rb_ary_entry(rb_result, 2);
-
+
add_vp_tuple(request->reply, request, &request->reply->vps,
rb_reply_items, function_name);
add_vp_tuple(request, request, &request->config_items,
{
rlm_ruby_t *inst = instance;
VALUE module;
-
+
int idx;
int status;
module = inst->module = rb_define_module(inst->module_name);
if (!module) {
EDEBUG("Ruby rb_define_module failed");
-
+
return -1;
}
-
+
/*
* Load constants into module
*/
for (idx = 0; constants[idx].name; idx++) {
rb_define_const(module, constants[idx].name, INT2NUM(constants[idx].value));
}
-
+
/*
* Expose some FreeRADIUS API functions as ruby functions
*/
rb_load_protect(rb_str_new2(inst->filename), 0, &status);
if (status) {
EDEBUG("Error loading file %s status: %d", inst->filename, status);
-
+
return -1;
}
DEBUG("Loaded file %s", inst->filename);
securid_sessionlist_clean_expired(inst, request, session->timestamp);
goto done;
}
-
+
if (session->session_id == 0) {
/* this is a NEW session (we are not inserting an updated session) */
inst->last_session_id++;
VALUE_PAIR *state;
SECURID_SESSION* session;
SECURID_SESSION mySession;
-
+
/* clean expired sessions if any */
pthread_mutex_lock(&(inst->session_mutex));
securid_sessionlist_clean_expired(inst, request, request->timestamp);
* Delete old session from the tree.
*/
rbtree_delete(inst->session_tree, node);
-
+
/*
* And unsplice it from the linked list.
*/
* it under the terms of the GNU General Public License, version 2 if the
* License as published by the Free Software Foundation.
*
- * This program is distributed in the hope that it will be useful,
+ * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
#include "rlm_securid.h"
typedef enum {
- RC_SECURID_AUTH_SUCCESS = 0,
- RC_SECURID_AUTH_FAILURE = -3,
- RC_SECURID_AUTH_ACCESS_DENIED_FAILURE = -4,
- RC_SECURID_AUTH_INVALID_SERVER_FAILURE = -5,
+ RC_SECURID_AUTH_SUCCESS = 0,
+ RC_SECURID_AUTH_FAILURE = -3,
+ RC_SECURID_AUTH_ACCESS_DENIED_FAILURE = -4,
+ RC_SECURID_AUTH_INVALID_SERVER_FAILURE = -5,
RC_SECURID_AUTH_CHALLENGE = -17
} SECURID_AUTH_RC;
static const CONF_PARSER module_config[] = {
- { "timer_expire", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, timer_limit), NULL, "600"},
- { "max_sessions", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_sessions), NULL, "2048"},
- { "max_trips_per_session", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_trips_per_session), NULL, NULL},
- { "max_round_trips", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_trips_per_session), NULL, "6"},
+ { "timer_expire", PW_TYPE_INTEGER,
+ offsetof(rlm_securid_t, timer_limit), NULL, "600"},
+ { "max_sessions", PW_TYPE_INTEGER,
+ offsetof(rlm_securid_t, max_sessions), NULL, "2048"},
+ { "max_trips_per_session", PW_TYPE_INTEGER,
+ offsetof(rlm_securid_t, max_trips_per_session), NULL, NULL},
+ { "max_round_trips", PW_TYPE_INTEGER,
+ offsetof(rlm_securid_t, max_trips_per_session), NULL, "6"},
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
-
+
static SD_CHAR empty_pin[] = "";
/* comparison function to find session in the tree */
}
-static SECURID_AUTH_RC securidAuth(void *instance, REQUEST *request,
- char const *username,
- char const *passcode,
+static SECURID_AUTH_RC securidAuth(void *instance, REQUEST *request,
+ char const *username,
+ char const *passcode,
char *replyMsgBuffer, size_t replyMsgBufferSize)
{
rlm_securid_t *inst = (rlm_securid_t *) instance;
if (!username) {
ERROR("SecurID username is NULL");
- return RC_SECURID_AUTH_FAILURE;
+ return RC_SECURID_AUTH_FAILURE;
}
if (!passcode) {
ERROR("SecurID passcode is NULL for %s user", username);
- return RC_SECURID_AUTH_FAILURE;
+ return RC_SECURID_AUTH_FAILURE;
}
-
+
memcpy(&securid_user, &username, sizeof(securid_user));
memcpy(&securid_pass, &passcode, sizeof(securid_pass));
-
+
*replyMsgBuffer = '\0';
securid_session = securid_sessionlist_find(inst, request);
securid_session->sdiHandle = sdiHandle; /* save ACE handle for future use */
securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
securid_session->identity = strdup(username);
-
+
/* Get PIN requirements */
acm_ret = AceGetPinParams(sdiHandle, &pin_params);
-
+
/* If a system-generated PIN is required */
if (pin_params.Selectable == CANNOT_CHOOSE_PIN) {
/* Prompt user to accept a system generated PIN */
- snprintf(replyMsgBuffer, replyMsgBufferSize,
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
"\r\nAre you prepared to accept a new system-generated PIN [y/n]?");
securid_session->securidSessionState = NEW_PIN_SYSTEM_ACCEPT_STATE;
} else if (pin_params.Selectable == USER_SELECTABLE) { //may be returned by AM 6.x servers.
- snprintf(replyMsgBuffer, replyMsgBufferSize,
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
"\r\nPress 'y' to generate a new PIN\r\nOR\r\n'n'to enter a new PIN yourself [y/n]");
securid_session->securidSessionState = NEW_PIN_USER_SELECT_STATE;
} else {
strcpy(format, "digits");
}
- snprintf(replyMsgBuffer, replyMsgBufferSize,
- " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
pin_params.Min, pin_params.Max, format);
}
/* insert new session in the session list */
securid_sessionlist_add(inst, request, securid_session);
-
+
return RC_SECURID_AUTH_CHALLENGE;
case ACM_NEXT_CODE_REQUIRED:
- RDEBUG2("Next securid token code required for %s",
+ RDEBUG2("Next securid token code required for %s",
username);
/* create a new session */
/* insert new session in the session list */
securid_sessionlist_add(inst, request, securid_session);
-
+
strlcpy(replyMsgBuffer, "\r\nPlease Enter the Next Code from Your Token:", replyMsgBufferSize);
return RC_SECURID_AUTH_CHALLENGE;
securid_session_free(inst, request, securid_session);
return RC_SECURID_AUTH_FAILURE;
-
+
}
} else {
/* existing session found */
return rc;
case NEW_PIN_REQUIRED_STATE:
- RDEBUG2("SecurID NEW_PIN_REQUIRED_STATE for %s",
+ RDEBUG2("SecurID NEW_PIN_REQUIRED_STATE for %s",
username);
/* save the previous pin */
/* insert the updated session in the session list */
securid_sessionlist_add(inst, request, securid_session);
return RC_SECURID_AUTH_CHALLENGE;
-
+
case NEW_PIN_USER_CONFIRM_STATE:
RDEBUG2("SecurID NEW_PIN_USER_CONFIRM_STATE: User [%s]", username);
/* compare previous pin and current pin */
if (!securid_session->pin || strcmp(securid_session->pin, passcode)) {
- RDEBUG2("Pin confirmation failed. Pins do not match [%s] and [%s]",
+ RDEBUG2("Pin confirmation failed. Pins do not match [%s] and [%s]",
SAFE_STR(securid_session->pin), securid_pass);
/* pins do not match */
} else {
strcpy(format, "digits");
}
- snprintf(replyMsgBuffer, replyMsgBufferSize,
- " \r\n Pins do not match--Please try again.\r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Pins do not match--Please try again.\r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
pin_params.Min, pin_params.Max, format);
securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
} else {
RDEBUG("SecurID: New SecurID pin rejected for %s.", securid_session->identity);
SD_Pin(securid_session->sdiHandle, &empty_pin[0]); /* cancel PIN */
-
+
rc = RC_SECURID_AUTH_FAILURE;
securid_session_free(inst, request, securid_session);
}
}
- return rc;
+ return rc;
case NEW_PIN_AUTH_VALIDATE_STATE:
acm_ret = SD_Check(securid_session->sdiHandle, securid_pass, securid_user);
if (acm_ret == ACM_OK) {
- RDEBUG("New SecurID passcode accepted for %s.",
+ RDEBUG("New SecurID passcode accepted for %s.",
securid_session->identity);
rc = RC_SECURID_AUTH_SUCCESS;
case NEW_PIN_SYSTEM_ACCEPT_STATE:
if (!strcmp(passcode, "y")) {
AceGetSystemPin(securid_session->sdiHandle, new_pin);
-
+
/* Save the PIN for the next session
* continuation */
if (securid_session->pin) {
securid_session->pin = NULL;
}
securid_session->pin = strdup(new_pin);
-
- snprintf(replyMsgBuffer, replyMsgBufferSize,
- "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
+
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
new_pin);
securid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
-
+
/* insert the updated session in the
* session list */
securid_sessionlist_add(inst, request, securid_session);
-
+
rc = RC_SECURID_AUTH_CHALLENGE;
} else {
SD_Pin(securid_session->sdiHandle, &empty_pin[0]); //Cancel new PIN
-
+
/* deallocate session */
- securid_session_free(inst, request,
+ securid_session_free(inst, request,
securid_session);
-
+
rc = RC_SECURID_AUTH_FAILURE;
}
-
- return rc;
-
+
+ return rc;
+
case NEW_PIN_SYSTEM_CONFIRM_STATE:
acm_ret = SD_Pin(securid_session->sdiHandle, (SD_CHAR*)securid_session->pin);
if (acm_ret == ACM_NEW_PIN_ACCEPTED) {
SD_Pin(securid_session->sdiHandle, &empty_pin[0]); //Cancel new PIN
strlcpy(replyMsgBuffer, " \r\n\r\nPin Rejected. Wait for the code on your card to change, then try again.\r\n\r\nEnter PASSCODE:", replyMsgBufferSize);
/* deallocate session */
- securid_session_free(inst, request,
+ securid_session_free(inst, request,
securid_session);
rc = RC_SECURID_AUTH_FAILURE;
}
-
+
return rc;
-
+
/* USER_SELECTABLE state should be implemented to preserve compatibility with AM 6.x servers, which can return this state */
case NEW_PIN_USER_SELECT_STATE:
if (!strcmp(passcode, "y")) {
/* User has opted for a system-generated PIN */
AceGetSystemPin(securid_session->sdiHandle, new_pin);
- snprintf(replyMsgBuffer, replyMsgBufferSize,
- "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
new_pin);
securid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
-
+
/* insert the updated session in the session list */
- securid_sessionlist_add(inst, request,
+ securid_sessionlist_add(inst, request,
securid_session);
rc = RC_SECURID_AUTH_CHALLENGE;
} else {
/* User has opted for a user-defined PIN */
- AceGetPinParams(securid_session->sdiHandle,
+ AceGetPinParams(securid_session->sdiHandle,
&pin_params);
if (pin_params.Alphanumeric) {
strcpy(format, "alphanumeric characters");
} else {
strcpy(format, "digits");
}
-
- snprintf(replyMsgBuffer, replyMsgBufferSize,
- " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
pin_params.Min, pin_params.Max, format);
securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
-
+
/* insert the updated session in the session list */
- securid_sessionlist_add(inst, request,
+ securid_sessionlist_add(inst, request,
securid_session);
rc = RC_SECURID_AUTH_CHALLENGE;
}
-
+
return rc;
-
+
default:
- ERROR("rlm_securid: Invalid session state %d for user [%s]",
- securid_session->securidSessionState,
+ ERROR("rlm_securid: Invalid session state %d for user [%s]",
+ securid_session->securidSessionState,
username);
- break;
+ break;
}
}
-
+
return 0;
-
+
}
/******************************************/
char buffer[MAX_STRING_LEN]="";
char const *username=NULL, *password=NULL;
VALUE_PAIR *vp;
-
+
/*
* We can only authenticate user requests which HAVE
* a User-Name attribute.
*/
username = request->username->vp_strvalue;
password = request->password->vp_strvalue;
-
- RDEBUG("User [%s] login attempt with password [%s]",
+
+ RDEBUG("User [%s] login attempt with password [%s]",
username, password);
-
- rcode = securidAuth(inst, request, username, password,
+
+ rcode = securidAuth(inst, request, username, password,
buffer, sizeof(buffer));
-
+
switch (rcode) {
case RC_SECURID_AUTH_SUCCESS:
rcode = RLM_MODULE_OK;
/* Generate Prompt attribute */
vp = paircreate(request->reply, PW_PROMPT, 0);
-
+
rad_assert(vp != NULL);
vp->vp_integer = 0; /* no echo */
pairadd(&request->reply->vps, vp);
* is single-threaded.
*/
module_t rlm_securid = {
- RLM_MODULE_INIT,
- "securid",
+ RLM_MODULE_INIT,
+ "securid",
RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
- sizeof(rlm_securid_t),
- module_config,
+ sizeof(rlm_securid_t),
+ module_config,
mod_instantiate, /* instantiation */
mod_detach, /* detach */
{
NULL, /* pre-proxy */
NULL, /* post-proxy */
NULL /* post-auth */
- },
+ },
};
time_t timestamp;
unsigned int session_id;
int trips;
-
+
char *pin; /* previous pin if user entered it during NEW-PIN mode process */
char *identity; /* save user's identity name for future use */
{ "challenge_type", PW_TYPE_STRING_PTR,
offsetof(rlm_smsotp_t, authtype),
NULL, "smsotp-reply" },
-
+
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
{
ssize_t n;
size_t total = 0;
-
+
fd_set fds;
struct timeval tv;
int retval;
FD_SET(*fdp, &fds);
tv.tv_sec = 0;
tv.tv_usec = 0;
-
+
while (total < len) {
n = read(*fdp, &buf[total], len - total);
if (n < 0) {
break;
}
}
-
+
return total;
}
REDEBUG("Failed to get handle from connection pool");
return RLM_MODULE_FAIL;
}
-
+
/* Get greeting */
bufsize = read_all(fdp, buffer, sizeof(buffer));
if (bufsize <= 0) {
state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
if (!state) {
RDEBUG("Found reply to access challenge");
-
+
/* send username */
snprintf(output, sizeof(output), "check otp for %s\n",
request->username->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
bufsize = read_all(fdp, buffer, sizeof(buffer));
-
+
/* send password */
snprintf(output, sizeof(output), "user otp is %s\n",
request->password->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
bufsize = read_all(fdp, buffer, sizeof(buffer));
-
+
/* set uuid */
snprintf(output, sizeof(output), "otp id is %s\n",
state->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
bufsize = read_all(fdp, buffer, sizeof(buffer));
-
+
/* now check the otp */
WRITE_ALL(fdp, "get check result\n", 17);
bufsize = read_all(fdp, buffer, sizeof(buffer));
-
+
/* end the sesssion */
WRITE_ALL(fdp, "quit\n", 5);
/*
* Create the challenge, and add it to the reply.
*/
-
+
pairmake_reply("Reply-Message", inst->challenge, T_OP_EQ);
pairmake_reply("State", buffer, T_OP_EQ);
-
+
/*
* Mark the packet as an Access-Challenge packet.
*
*/
request->reply->code = PW_ACCESS_CHALLENGE;
DEBUG("rlm_smsotp: Sending Access-Challenge.");
-
+
rcode = RLM_MODULE_HANDLED;
done:
state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
if (state != NULL) {
DEBUG("rlm_smsotp: Found reply to access challenge (AUTZ), Adding Auth-Type '%s'",inst->authtype);
-
+
pairdelete(&request->config_items, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */
pairmake_config("Auth-Type", inst->authtype, T_OP_SET);
}
static int sql_socket_destructor(void *c)
{
rlm_sql_db2_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_db2: Socket destructor called, closing socket");
-
+
if (conn->hdbc) {
SQLDisconnect(conn->hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, conn->hdbc);
}
-
+
if (conn->henv) {
SQLFreeHandle(SQL_HANDLE_ENV, conn->henv);
}
-
+
return RLM_SQL_OK;
}
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
talloc_set_destructor((void *) conn, sql_socket_destructor);
-
+
/* allocate handles */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->henv));
SQLAllocHandle(SQL_HANDLE_DBC, conn->henv, &(conn->hdbc));
*/
{
SQLCHAR *server, *login, *password;
-
+
memcpy(&server, &config->sql_server, sizeof(server));
memcpy(&login, &config->sql_login, sizeof(login));
memcpy(&password, &config->sql_password, sizeof(password));
-
+
retval = SQLConnect(conn->hdbc,
server, SQL_NTS,
login, SQL_NTS,
password, SQL_NTS);
}
-
+
if(retval != SQL_SUCCESS) {
ERROR("could not connect to DB2 server %s", config->sql_server);
-
+
return RLM_SQL_ERROR;
}
for(i = 0; i < c; i++) {
/* get column length */
SQLColAttribute(conn->stmt, i+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len);
-
+
retval[i] = rad_malloc(len+1);
-
+
/* get the actual column */
SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, retval[i], len+1, &slen);
if(slen == SQL_NULL_DATA) {
free(retval[i]);
}
free(retval);
-
+
return RLM_SQL_ERROR;
}
rlm_sql_db2_conn_t *conn;
conn = handle->conn;
SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
-
+
return RLM_SQL_OK;
}
TALLOC_FREE(conn->error);
SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) sqlstate, &err, (SQLCHAR *) msg, sizeof(msg), &rl);
conn->error = talloc_asprintf(conn, "sqlstate %s: %s", sqlstate, msg);
-
+
return conn->error;
}
rlm_sql_db2_conn_t *conn = handle->conn;
SQLRowCount(conn->stmt, &c);
-
+
return c;
}
{
rlm_sql_firebird_conn_t *conn = c;
int i;
-
+
DEBUG2("rlm_sql_firebird: socket destructor called, closing socket");
-
+
fb_commit(conn);
if (conn->dbh) {
fb_free_statement(conn);
isc_detach_database(conn->status, &(conn->dbh));
-
+
if (fb_error(conn)) {
WDEBUG("rlm_sql_firebird: Got error "
"when closing socket: %s", conn->error);
}
}
-
+
#ifdef _PTHREAD_H
pthread_mutex_destroy (&conn->mut);
#endif
for (i=0; i < conn->row_fcount; i++) {
free(conn->row[i]);
}
-
+
free(conn->row);
free(conn->row_sizes);
fb_free_sqlda(conn->sqlda_out);
-
+
free(conn->sqlda_out);
free(conn->tpb);
free(conn->dpb);
*/
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
rlm_sql_firebird_conn_t *conn;
-
+
long res;
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_firebird_conn_t));
if (res) {
return -1;
}
-
+
if (fb_connect(conn, config)) {
ERROR("rlm_sql_firebird: Connection failed: %s", conn->error);
-
+
return RLM_SQL_RECONNECT;
}
*/
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query) {
rlm_sql_firebird_conn_t *conn = handle->conn;
-
+
int deadlock = 0;
#ifdef _PTHREAD_H
if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
!deadlock) {
DEBUG("conn_id deadlock. Retry query %s", query);
-
+
/*
* @todo For non READ_COMMITED transactions put
* rollback here
deadlock = 1;
goto try_again;
}
-
+
ERROR("conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
(long int) conn->sql_code, conn->error, query);
return RLM_SQL_RECONNECT;
}
-
+
/* Free problem query */
if (fb_rollback(conn)) {
//assume the network is down if rollback had failed
ERROR("Fail to rollback transaction after previous error: %s", conn->error);
-
+
return RLM_SQL_RECONNECT;
}
// conn->in_use=0;
{
rlm_sql_firebird_conn_t *conn = handle->conn;
int res;
-
+
handle->row = NULL;
-
+
if (conn->statement_type != isc_info_sql_stmt_exec_procedure) {
res = fb_fetch(conn);
if (res == 100) {
return 0;
}
-
+
if (res) {
ERROR("rlm_sql_firebird. Fetch problem: %s", conn->error);
-
+
return -1;
}
} else {
conn->statement_type=0;
}
-
+
fb_store_row(conn);
handle->row = conn->row;
-
+
return 0;
}
*/
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle,
UNUSED rlm_sql_config_t *config) {
-
+
rlm_sql_firebird_conn_t *conn = (rlm_sql_firebird_conn_t *) handle->conn;
-
+
fb_commit(conn);
fb_close_cursor(conn);
-
+
return 0;
}
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle,
rlm_sql_config_t *config) {
sql_free_result(handle, config);
-
+
return 0;
}
*/
static char const *sql_error(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config) {
rlm_sql_firebird_conn_t *conn = handle->conn;
-
+
return conn->error;
}
*/
static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
int affected_rows=fb_affected_rows(handle->conn);
-
+
if (affected_rows < 0) {
ERROR("sql_affected_rows, rlm_sql_firebird. error:%s", sql_error(handle, config));
}
-
+
return affected_rows;
}
{
int i;
va_list arg;
-
+
va_start(arg, count);
conn->tpb = malloc(count);
-
+
for (i = 0; i < count; i++) {
conn->tpb[i] = (char) va_arg(arg, int);
}
-
+
conn->tpb_len = count;
-
+
va_end(arg);
}
static void fb_dpb_add_str(char **dpb, char name, char const *value)
{
int l;
-
+
if (!value) {
return;
}
-
+
l = strlen(value);
*(*dpb)++= name;
*(*dpb)++= (char) l;
-
+
memmove(*dpb, value, l);
-
+
*dpb += l;
}
static void fb_set_sqlda(XSQLDA *sqlda) {
int i;
-
+
for (i = 0; i < sqlda->sqld; i++) {
if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_VARYING) {
sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short));
} else {
sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);
}
-
+
if (sqlda->sqlvar[i].sqltype & 1) {
sqlda->sqlvar[i].sqlind = (short*)calloc(sizeof(short), 1);
} else {
{
ISC_SCHAR error[2048]; /* Only 1024 bytes should be written to this, but were playing it extra safe */
ISC_STATUS *pstatus;
-
+
conn->sql_code = 0;
/*
*/
if (IS_ISC_ERROR(conn->status)) {
conn->sql_code = isc_sqlcode(conn->status);
-
+
/*
* pstatus is a pointer into the status array which is
* advanced by isc_interprete. It's initialised to the
* first element of the status array.
*/
pstatus = &conn->status[0];
-
+
/*
* It's deprecated because the size of the buffer isn't
* passed and this isn't safe. But as were passing a very
while (isc_interprete(&error[0], &pstatus)) {
conn->error = talloc_asprintf_append(conn->error, "%s. ", &error[0]);
}
-
+
memset(&conn->status, 0, sizeof(conn->status));
}
-
+
return conn->sql_code;
}
DIAG_ON(deprecated-declarations)
conn->row_fcount = conn->sqlda_out->sqld;
conn->row = (char **) realloc(conn->row, conn->row_fcount * sizeof(char *));
conn->row_sizes = (int *) realloc(conn->row_sizes, conn->row_fcount * sizeof(int));
-
+
while( i <conn->row_fcount) {
conn->row[i] = 0;
conn->row_sizes[i++] = 0;
strcpy(conn->row[i], "NULL");
continue;
}
-
+
dtype = var->sqltype & ~1;
-
+
switch (dtype) {
case SQL_TEXT:
if (conn->row_sizes[i]<= var->sqllen) {
conn->row[i] = realloc(conn->row[i],
conn->row_sizes[i]);
}
-
+
memmove(conn->row[i], var->sqldata, var->sqllen);
conn->row[i][var->sqllen] = 0;
}
memmove(conn->row[i], vary->vary_string, vary->vary_length);
conn->row[i][vary->vary_length] = 0;
-
+
break;
case SQL_FLOAT:
short dscale = 0;
char *p;
p = conn->row[i];
-
+
switch (dtype) {
case SQL_SHORT:
value = (ISC_INT64) *(short *)var->sqldata;
break;
}
dscale = var->sqlscale;
-
+
if (dscale < 0) {
ISC_INT64 tens;
short j;
for (j = 0; j > dscale; j--) {
tens *= 10;
}
-
+
if (value >= 0) {
sprintf(p, "%*lld.%0*lld",
field_width - 1 + dscale,
if (!conn->tpb) {
return -1;
}
-
+
return 0;
}
if (config->sql_login) {
conn->dpb_len+= strlen(config->sql_login) + 2;
}
-
+
if (config->sql_password) {
conn->dpb_len += strlen(config->sql_password) + 2;
}
-
+
conn->dpb = (char *) malloc(conn->dpb_len);
p = conn->dpb;
fb_dpb_add_str(&conn->dpb, isc_dpb_password, config->sql_password);
conn->dpb = p;
-
+
/*
* Check if database and server in the form of server:database.
* If config->sql_server contains ':', then config->sql_db
isc_attach_database(conn->status, 0, database, &conn->dbh,
conn->dpb_len, conn->dpb);
free(database);
-
+
return fb_error(conn);
}
if (conn->statement_type!= isc_info_sql_stmt_select) {
return 100;
}
-
+
fetch_stat = isc_dsql_fetch(conn->status, &conn->stmt,
SQL_DIALECT_V6, conn->sqlda_out);
if (fetch_stat) {
conn->sql_code = 0;
}
}
-
+
return fetch_stat;
}
if (IS_ISC_ERROR(conn->status)) {
return -2;
}
-
+
if (conn->sqlda_out->sqln<conn->sqlda_out->sqld) {
conn->sqlda_out->sqln = conn->sqlda_out->sqld;
conn->sqlda_out = (XSQLDA ISC_FAR *) realloc(conn->sqlda_out,
XSQLDA_LENGTH(conn->sqlda_out->sqld));
isc_dsql_describe(conn->status, &conn->stmt, SQL_DIALECT_V6,
conn->sqlda_out);
-
+
if (IS_ISC_ERROR(conn->status)) {
return -3;
}
if (conn->sqlda_out->sqld) {
fb_set_sqlda(conn->sqlda_out); //set out sqlda
}
-
+
return 0;
}
if (fb_prepare(conn, query)) {
return fb_error(conn);
}
-
+
switch (conn->statement_type) {
case isc_info_sql_stmt_exec_procedure:
isc_dsql_execute2(conn->status, &conn->trh, &conn->stmt,
isc_dsql_sql_info(conn->status, &conn->stmt,
sizeof (count_info), count_info,
sizeof (info_buffer), info_buffer);
-
+
if (IS_ISC_ERROR(conn->status)) {
return fb_error(conn);
}
-
+
p = info_buffer + 3;
while (*p != isc_info_end) {
p++;
short len = (short)isc_vax_integer(p, 2);
p += 2;
-
+
affected_rows = isc_vax_integer(p, len);
if (affected_rows > 0) {
break;
int fb_close_cursor(rlm_sql_firebird_conn_t *conn) {
isc_dsql_free_statement(conn->status, &conn->stmt, DSQL_close);
-
+
return fb_error(conn);
}
isc_db_handle dbh;
isc_stmt_handle stmt;
isc_tr_handle trh;
-
+
ISC_STATUS status[20]; //!< Magic interbase status code array (holds multiple error codes used
//!< to construct more detailed error messages.
-
+
ISC_LONG sql_code;
XSQLDA *sqlda_out;
int sql_dialect;
*/
if (emsgp->severity == CS_SV_INFORM) {
INFO("rlm_sql_freetds: %s", emsgp->msgstring);
-
+
return CS_SUCCEED;
}
if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
ERROR("rlm_sql_freetds: failed retrieving context userdata");
-
+
return CS_SUCCEED;
}
-
+
if (this->error) TALLOC_FREE(this->error);
-
- this->error = talloc_asprintf(this, "client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+
+ this->error = talloc_asprintf(this, "client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
(long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
(long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
emsgp->msgstring);
-
+
if (emsgp->osstringlen > 0) {
this->error = talloc_asprintf_append(this->error, ". os error: number(%ld): %s",
(long)emsgp->osnumber, emsgp->osstring);
}
-
+
return CS_SUCCEED;
}
{
rlm_sql_freetds_conn_t *this = NULL;
int len = 0;
-
+
/*
* Not actually an error, but the client wanted to tell us something...
*/
if (emsgp->severity == CS_SV_INFORM) {
INFO("rlm_sql_freetds: %s", emsgp->msgstring);
-
+
return CS_SUCCEED;
}
-
+
if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
ERROR("rlm_sql_freetds: failed retrieving context userdata");
-
+
return CS_SUCCEED;
}
-
+
if (this->error) TALLOC_FREE(this->error);
-
- this->error = talloc_asprintf(this, "cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+
+ this->error = talloc_asprintf(this, "cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
(long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
(long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
emsgp->msgstring);
-
+
if (emsgp->osstringlen > 0) {
this->error = talloc_asprintf_append(this->error, ". os error: number(%ld): %s",
(long)emsgp->osnumber, emsgp->osstring);
{
rlm_sql_freetds_conn_t *this = NULL;
int len = 0;
-
+
if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
ERROR("rlm_sql_freetds: failed retrieving context userdata");
-
+
return CS_SUCCEED;
}
-
+
/*
* Because apparently there are no standard severity levels *brilliant*
*/
(msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
} else {
if (this->error) TALLOC_FREE(this->error);
-
+
this->error = talloc_asprintf(this, "server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
"layer(%ld), procedure \"%s\": %s",
(msgp->svrnlen > 0) ? msgp->svrname : "unknown",
(long)msgp->line,
(msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
}
-
+
return CS_SUCCEED;
}
if (ct_cmd_alloc(conn->db, &conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to allocate command structure (ct_cmd_alloc())");
-
+
return RLM_SQL_ERROR;
}
if (ct_command(conn->command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to initialise command structure (ct_command())");
-
+
return RLM_SQL_ERROR;
}
if (ct_send(conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to send command (ct_send())");
-
+
return RLM_SQL_ERROR;
}
/*
- * We'll make three calls to ct_results, first to get a success indicator, secondly to get a
+ * We'll make three calls to ct_results, first to get a success indicator, secondly to get a
* done indicator, and thirdly to get a "nothing left to handle" status.
*/
"Use sql_select_query instead!");
}
ERROR("rlm_sql_freetds: result failure or unexpected result type from query");
-
+
return RLM_SQL_ERROR;
}
} else {
switch (results_ret) {
case CS_FAIL: /* Serious failure, freetds requires us to cancel and maybe even close db */
ERROR("rlm_sql_freetds: failure retrieving query results");
-
+
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
INFO("rlm_sql_freetds: cleaning up");
return RLM_SQL_RECONNECT;
}
conn->command = NULL;
-
+
return RLM_SQL_ERROR;
default:
ERROR("rlm_sql_freetds: unexpected return value from ct_results()");
-
+
return RLM_SQL_ERROR;
}
}
if ((results_ret = ct_results(conn->command, &result_type)) == CS_SUCCEED) {
if (result_type != CS_CMD_DONE) {
ERROR("rlm_sql_freetds: result failure or unexpected result type from query");
-
+
return RLM_SQL_ERROR;
}
} else {
ERROR("rlm_sql_freetds: failure retrieving query results");
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
INFO("rlm_sql_freetds: cleaning up");
-
+
return RLM_SQL_RECONNECT;
}
conn->command = NULL;
return RLM_SQL_ERROR;
-
+
default:
ERROR("rlm_sql_freetds: unexpected return value from ct_results()");
-
+
return RLM_SQL_ERROR;
}
}
ERROR("rlm_sql_freetds: failure retrieving query results");
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
INFO("rlm_sql_freetds: cleaning up.");
-
+
return RLM_SQL_RECONNECT;
}
conn->command = NULL;
-
+
return RLM_SQL_ERROR;
case CS_END_RESULTS: /* This is where we want to end up */
default:
ERROR("rlm_sql_freetds: Unexpected return value from ct_results()");
-
+
return RLM_SQL_ERROR;
}
-
+
return RLM_SQL_OK;
}
if (ct_res_info(conn->command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: error retrieving column count");
-
+
return RLM_SQL_ERROR;
}
-
+
return num;
}
if (!conn || !conn->db) {
return "rlm_sql_freetds: no connection to db";
}
-
+
return conn->error;
}
ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: freeing command structure failed");
-
+
return RLM_SQL_ERROR;
}
conn->command = NULL;
if (!conn->db) {
ERROR("rlm_sql_freetds: socket not connected");
-
+
return RLM_SQL_ERROR;
}
if (ct_cmd_alloc(conn->db, &conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to allocate command structure (ct_cmd_alloc())");
-
+
return RLM_SQL_ERROR;
}
if (ct_command(conn->command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to initiate command structure (ct_command()");
-
+
return RLM_SQL_ERROR;
}
descriptor.locale = NULL; /* Don't do NLS stuff */
colcount = sql_num_fields(handle, config); /* Get number of elements in row result */
-
+
rowdata = talloc_zero_array(conn, char *, colcount + 1); /* Space for pointers */
rowdata[colcount] = NULL;
/* Associate the target buffer with the data */
if (ct_bind(conn->command, i + 1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
talloc_free(rowdata);
-
+
ERROR("rlm_sql_freetds: ct_bind() failed)");
-
+
return RLM_SQL_ERROR;
}
}
-
+
rowdata[i] = NULL; /* Terminate the array */
conn->results = rowdata;
break;
ERROR("rlm_sql_freetds: unexpected result type from query");
sql_finish_select_query(handle, config);
-
+
return RLM_SQL_ERROR;
}
break;
*/
ERROR("rlm_sql_freetds: failure retrieving query results");
-
+
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
ERROR("rlm_sql_freetds: cleaning up.");
return RLM_SQL_RECONNECT;
}
conn->command = NULL;
-
+
return RLM_SQL_ERROR;
default:
ERROR("rlm_sql_freetds: unexpected return value from ct_results()");
-
+
return RLM_SQL_ERROR;
}
-
+
return RLM_SQL_OK;
}
if (ct_res_info(conn->command, CS_ROW_COUNT, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: error retrieving row count");
-
+
return RLM_SQL_ERROR;
}
-
+
return num;
}
} else {
conn->command = NULL;
}
-
+
return RLM_SQL_RECONNECT;
case CS_END_DATA:
case CS_SUCCEED:
handle->row = conn->results;
-
+
return RLM_SQL_OK;
case CS_ROW_FAIL:
ERROR("rlm_sql_freetds: recoverable failure fetching row data");
-
+
return RLM_SQL_RECONNECT;
default:
ERROR("rlm_sql_freetds: unexpected returncode from ct_fetch");
-
+
return RLM_SQL_ERROR;
}
}
ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: freeing command structure failed");
-
+
return RLM_SQL_ERROR;
}
conn->command = NULL;
static int sql_socket_destructor(void *c)
{
rlm_sql_freetds_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_freetds: socket destructor called, closing socket");
if (conn->command) {
ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: freeing command structure failed");
-
+
return RLM_SQL_ERROR;
}
}
* We first try gracefully closing the connection (which informs the server)
* Then if that fails we force the connection closure.
*
- * Sybase docs says this may fail because of pending results, but we
+ * Sybase docs says this may fail because of pending results, but we
* should not have any pending results at this point, so something else must
* of gone wrong.
*/
if (ct_close(conn->db, CS_UNUSED) != CS_SUCCEED) {
ct_close(conn->db, CS_FORCE_CLOSE);
}
-
+
ct_con_drop(conn->db);
}
-
+
if (conn->context) {
ct_exit(conn->context, CS_UNUSED);
cs_ctx_drop(conn->context);
}
-
+
return RLM_SQL_OK;
}
goto error;
}
-
+
if (cs_config(conn->context, CS_SET, CS_USERDATA,
(CS_VOID *)&handle->conn, sizeof(handle->conn), NULL) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to set userdata pointer");
-
+
goto error;
}
-
+
if (ct_callback(conn->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)clientmsg_callback) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to install client message callback");
}
/*
- * Allocate a ctlib db structure
+ * Allocate a ctlib db structure
*/
if (ct_con_alloc(conn->context, &conn->db) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to allocate db structure");
CS_VOID *login, *password;
CS_CHAR *server;
char database[128];
-
+
memcpy(&login, &config->sql_login, sizeof(login));
if (ct_con_props(conn->db, CS_SET, CS_USERNAME, login, strlen(config->sql_login), NULL) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to set username for db");
goto error;
}
-
+
memcpy(&password, &config->sql_password, sizeof(password));
if (ct_con_props(conn->db, CS_SET, CS_PASSWORD,
password, strlen(config->sql_password), NULL) != CS_SUCCEED) {
goto error;
}
-
+
/*
* Connect to the database
*/
if (ct_connect(conn->db, server, strlen(config->sql_server)) != CS_SUCCEED) {
ERROR("rlm_sql_freetds: unable to establish db to symbolic servername %s",
config->sql_server);
-
+
goto error;
}
-
+
/*
* There doesn't appear to be a way to set the database with the API, so use an
* sql statement when we first open the connection.
*/
- snprintf(database, sizeof(database), "USE %s;", config->sql_db);
+ snprintf(database, sizeof(database), "USE %s;", config->sql_db);
if (sql_query(handle, config, database) != RLM_SQL_OK) {
goto error;
}
-
+
sql_finish_query(handle, config);
}
return RLM_SQL_OK;
-
+
error:
if (conn->context) {
char const *error;
HDBC dbc_handle;
HSTMT stmt_handle;
int id;
-
+
rlm_sql_row_t row;
struct sql_socket *next;
-
+
SQLCHAR error[IODBC_MAX_ERROR_LEN];
void *conn;
} rlm_sql_iodbc_conn_t;
static int sql_socket_destructor(void *c)
{
rlm_sql_iodbc_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_iodbc: Socket destructor called, closing socket");
-
+
if (conn->stmt_handle) {
SQLFreeStmt(conn->stmt_handle, SQL_DROP);
}
-
+
if (conn->dbc_handle) {
SQLDisconnect(conn->dbc_handle);
SQLFreeConnect(conn->dbc_handle);
}
-
+
if (conn->env_handle) {
SQLFreeEnv(conn->env_handle);
}
-
+
return 0;
}
*/
{
SQLCHAR *server, *login, *password;
-
+
memcpy(&server, &config->sql_server, sizeof(server));
memcpy(&login, &config->sql_login, sizeof(login));
memcpy(&password, &config->sql_password, sizeof(password));
-
+
rcode = SQLConnect(conn->dbc_handle, server, SQL_NTS, login, SQL_NTS, password, SQL_NTS);
}
if (!SQL_SUCCEEDED(rcode)) {
{
SQLCHAR *statement;
-
+
memcpy(&statement, &query, sizeof(statement));
rcode = SQLExecDirect(conn->stmt_handle, statement, SQL_NTS);
}
-
+
if (!SQL_SUCCEEDED(rcode)) {
ERROR("sql_query: failed: %s",
sql_error(handle, config));
rlm_sql_iodbc_conn_t *conn = handle->conn;
conn->error[0] = '\0';
-
+
SQLError(conn->env_handle, conn->dbc_handle, conn->stmt_handle,
state, &errornum, conn->error, IODBC_MAX_ERROR_LEN, &length);
return (char const *) &conn->error;
static int sql_socket_destructor(void *c)
{
rlm_sql_mysql_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_mysql: Socket destructor called, closing socket");
-
+
if (conn->sock){
mysql_close(conn->sock);
}
-
+
return 0;
}
config->sql_db);
ERROR("rlm_sql_mysql: Mysql error '%s'",
mysql_error(&conn->db));
-
+
conn->sock = NULL;
-
+
return -1;
}
if (errcode) {
return msgbuf;
}
-
+
return NULL;
}
static int sql_socket_destructor(void *c)
{
rlm_sql_oracle_conn_t *conn = c;
-
+
if (conn->ctx) {
OCILogoff(conn->ctx, conn->error);
}
if (conn->query) {
OCIHandleFree((dvoid *)conn->query, OCI_HTYPE_STMT);
}
-
+
if (conn->error) {
OCIHandleFree((dvoid *)conn->error, OCI_HTYPE_ERROR);
}
-
+
if (conn->env) {
OCIHandleFree((dvoid *)conn->env, OCI_HTYPE_ENV);
}
-
+
return 0;
}
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_oracle_conn_t));
talloc_set_destructor((void *) conn, sql_socket_destructor);
- /*
+ /*
* Initialises the oracle environment
*/
if (OCIEnvCreate(&conn->env, OCI_DEFAULT | OCI_THREADED, NULL, NULL, NULL, NULL, 0, NULL)) {
ERROR("rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())");
-
+
return -1;
}
*/
if (OCIHandleAlloc((dvoid *)conn->env, (dvoid **)&conn->error, OCI_HTYPE_ERROR, 0, NULL)) {
ERROR("rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
-
+
return -1;
}
*/
if (OCIHandleAlloc((dvoid *)conn->env, (dvoid **)&conn->query, OCI_HTYPE_STMT, 0, NULL)) {
ERROR("rlm_sql_oracle: Couldn't init Oracle query handles: %s", sql_error(handle, config));
-
+
return -1;
}
if (OCIAttrGet((dvoid *)conn->query, OCI_HTYPE_STMT, (dvoid *)&count, NULL, OCI_ATTR_PARAM_COUNT,
conn->error)) {
ERROR("rlm_sql_oracle: Error retrieving column count : %s", sql_error(handle, config));
-
+
return -1;
}
-
+
return count;
}
{
int status;
rlm_sql_oracle_conn_t *conn = handle->conn;
-
+
OraText *oracle_query;
memcpy(&oracle_query, &query, sizeof(oracle_query));
if (!conn->ctx) {
ERROR("rlm_sql_oracle: Socket not connected");
-
+
return RLM_SQL_RECONNECT;
}
if (OCIStmtPrepare(conn->query, conn->error, oracle_query, strlen(query),
OCI_NTV_SYNTAX, OCI_DEFAULT)) {
ERROR("rlm_sql_oracle: prepare failed in sql_query: %s", sql_error(handle, config));
-
+
return -1;
}
ERROR("rlm_sql_oracle: execute query failed in sql_query: %s", sql_error(handle, config));
return sql_check_error(handle, config);
}
-
+
return -1;
}
int status;
char **row;
-
+
int i;
OCIParam *param;
OCIDefine *define;
-
+
ub2 dtype;
ub2 dsize;
-
+
sb2 *ind;
-
+
OraText *oracle_query;
rlm_sql_oracle_conn_t *conn = handle->conn;
if (OCIStmtPrepare(conn->query, conn->error, oracle_query, strlen(query), OCI_NTV_SYNTAX,
OCI_DEFAULT)) {
ERROR("rlm_sql_oracle: prepare failed in sql_select_query: %s", sql_error(handle, config));
-
+
return -1;
}
if (status != OCI_SUCCESS) {
ERROR("rlm_sql_oracle: query failed in sql_select_query: %s", sql_error(handle, config));
-
+
return sql_check_error(handle, config);
}
if (status != OCI_SUCCESS) {
ERROR("rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s",
sql_error(handle, config));
-
+
goto error;
}
}
MEM(row[i] = talloc_zero_array(row, char, dsize + 1));
-
+
break;
case SQLT_DAT:
case SQLT_INT:
}
ind[i] = 0;
-
+
/*
* Grab the actual row value and write it to the buffer we allocated.
*/
if (status != OCI_SUCCESS) {
ERROR("rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s",
sql_error(handle, config));
-
+
goto error;
}
}
rlm_sql_oracle_conn_t *conn = handle->conn;
ub4 rows = 0;
ub4 size = sizeof(ub4);
-
+
OCIAttrGet((CONST dvoid *)conn->query, OCI_HTYPE_STMT, (dvoid *)&rows, &size, OCI_ATTR_ROW_COUNT, conn->error);
return rows;
if (!conn->ctx) {
ERROR("rlm_sql_oracle: Socket not connected");
-
+
return RLM_SQL_RECONNECT;
}
status = OCIStmtFetch(conn->query, conn->error, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
if (status == OCI_SUCCESS) {
handle->row = conn->row;
-
+
return 0;
}
ERROR("rlm_sql_oracle: fetch failed in sql_fetch_row: %s", sql_error(handle, config));
return sql_check_error(handle, config);
}
-
+
return -1;
}
static int sql_socket_destructor(void *c)
{
rlm_sql_postgres_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_postgresql: Socket destructor called, closing socket");
-
+
if (!conn->db) {
return 0;
}
return 0;
}
-
+
/*************************************************************************
*
* Function: sql_create_socket
offsetof(rlm_sql_sqlite_config_t, filename), NULL, NULL},
{"bootstrap", PW_TYPE_FILE_INPUT,
offsetof(rlm_sql_sqlite_config_t, bootstrap), NULL, NULL},
-
+
{NULL, -1, 0, NULL, NULL}
};
case SQLITE_CONSTRAINT:
case SQLITE_MISMATCH:
ERROR("rlm_sql_sqlite: Error (%d): %s", error, sqlite3_errmsg(db));
-
+
return -1;
break;
-
+
/*
* Errors with the handle, that probably require reinitialisation
*/
if (!f) {
ERROR("rlm_sql_sqlite: Failed opening SQL file \"%s\": %s", filename,
strerror(errno));
-
+
return -1;
}
-
+
if (fstat(fileno(f), &finfo) < 0) {
ERROR("rlm_sql_sqlite: Failed stating SQL file \"%s\": %s", filename,
strerror(errno));
-
+
fclose(f);
return -1;
}
-
+
if (finfo.st_size > BOOTSTRAP_MAX) {
too_big:
ERROR("rlm_sql_sqlite: Size of SQL (%zu) file exceeds limit (%uk)",
(size_t) finfo.st_size / 1024, BOOTSTRAP_MAX / 1024);
-
+
fclose(f);
return -1;
}
-
+
MEM(buffer = talloc_array(ctx, char, finfo.st_size + 1));
len = fread(buffer, sizeof(char), finfo.st_size + 1, f);
if (len > finfo.st_size) {
talloc_free(buffer);
goto too_big;
}
-
+
if (!len) {
if (ferror(f)) {
ERROR("rlm_sql_sqlite: Error reading SQL file: %s", strerror(errno));
-
+
fclose(f);
talloc_free(buffer);
return -1;
}
-
+
DEBUG("rlm_sql_sqlite: Ignoring empty SQL file");
-
+
fclose(f);
talloc_free(buffer);
-
+
return 0;
}
-
+
buffer[len] = '\0';
fclose(f);
if (!cl) break;
}
}
-
+
if ((p - buffer) != len) {
ERROR("rlm_sql_sqlite: Bootstrap file contains non-UTF8 char at offset %zu", p - buffer);
talloc_free(buffer);
p = q + 1;
continue;
}
-
+
*q = '\0';
-
+
(void) sqlite3_prepare_v2(db, s, len, &statement, &z_tail);
if (sql_check_error(db)) {
talloc_free(buffer);
- return -1;
+ return -1;
}
-
+
(void) sqlite3_step(statement);
status = sql_check_error(db);
-
+
(void) sqlite3_finalize(statement);
if (status || sql_check_error(db)) {
talloc_free(buffer);
- return -1;
+ return -1;
}
-
+
p = s = q + 1;
}
-
+
talloc_free(buffer);
return 0;
}
"originally built against (%s), this may cause issues",
sqlite3_libversion(), SQLITE_VERSION);
}
-
+
MEM(driver = config->driver = talloc_zero(config, rlm_sql_sqlite_config_t));
-
+
if (cf_section_parse(conf, driver, driver_config) < 0) {
return -1;
}
-
+
INFO("rlm_sql_sqlite: SQLite library version: %s", sqlite3_libversion());
if (!driver->filename) {
MEM(driver->filename = talloc_asprintf(driver, "%s/%s", radius_dir, config->sql_db));
}
-
+
exists = rad_file_exists(driver->filename);
if (exists < 0) {
ERROR("rlm_sql_sqlite: Database exists, but couldn't be opened: %s", strerror(errno));
-
+
return -1;
}
char *p;
char *buff;
sqlite3 *db = NULL;
-
+
INFO("rlm_sql_sqlite: Database doesn't exist, creating it and loading schema");
-
+
p = strrchr(driver->filename, '/');
if (p) {
size_t len = (p - driver->filename) + 1;
-
+
buff = talloc_array(conf, char, len);
strlcpy(buff, driver->filename, len);
} else {
MEM(buff = talloc_strdup(conf, driver->filename));
}
-
+
if (rad_mkdir(buff, 0700) < 0) {
ERROR("rlm_sql_sqlite: Failed creating directory for SQLite database");
-
+
talloc_free(buff);
-
+
return -1;
}
if (!db) {
ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database, error "
"code (%u)", status);
-
+
goto unlink;
}
-
+
if (sql_check_error(db)) {
(void) sqlite3_close(db);
-
+
goto unlink;
}
-
+
ret = sql_loadfile(conf, db, driver->bootstrap);
-
+
status = sqlite3_close(db);
if (status != SQLITE_OK) {
ERROR("rlm_sql_sqlite: Error closing SQLite handle, error code (%u)", status);
goto unlink;
}
-
+
if (ret < 0) {
unlink:
if (unlink(driver->filename) < 0) {
"Upgrade to SQLite >= 3.5.1 if you need this functionality");
#endif
}
-
+
return 0;
}
{
int status = 0;
rlm_sql_sqlite_conn_t * conn = c;
-
+
DEBUG2("rlm_sql_sqlite: Socket destructor called, closing socket");
-
+
if (conn->db) {
status = sqlite3_close(conn->db);
if (status != SQLITE_OK) {
WDEBUG("rlm_sql_sqlite: Got SQLite error code (%u) when closing socket", status);
}
}
-
+
return 0;
}
{
rlm_sql_sqlite_conn_t *conn;
rlm_sql_sqlite_config_t *driver = config->driver;
-
+
int status;
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_sqlite_conn_t));
INFO("rlm_sql_sqlite: Opening SQLite database \"%s\"", driver->filename);
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE_V2_API
status = sqlite3_open_v2(driver->filename, &(conn->db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX, NULL);
#else
status = sqlite3_open(driver->filename, &(conn->db));
if (!conn->db) {
ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database error code (%u)",
status);
-
+
return -1;
}
-
+
if (sql_check_error(conn->db)) {
return -1;
}
-
+
/*
* Enable extended return codes for extra debugging info.
*/
status = sqlite3_extended_result_codes(conn->db, 1);
-
+
if (sql_check_error(conn->db)) {
return -1;
}
-
+
return 0;
}
{
rlm_sql_sqlite_conn_t *conn = handle->conn;
char const *z_tail;
-
+
#ifdef HAVE_SQLITE_V2_API
(void) sqlite3_prepare_v2(conn->db, query, strlen(query), &conn->statement, &z_tail);
#else
(void) sqlite3_prepare(conn->db, query, strlen(query), &conn->statement, &z_tail);
#endif
-
+
conn->col_count = 0;
-
+
return sql_check_error(conn->db);
}
#endif
if (status != SQLITE_OK) {
return sql_check_error(conn->db);
- }
-
+ }
+
(void) sqlite3_step(conn->statement);
-
+
return sql_check_error(conn->db);
}
static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
{
rlm_sql_sqlite_conn_t *conn = handle->conn;
-
+
if (conn->statement) {
return sqlite3_column_count(conn->statement);
}
-
+
return 0;
}
static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
{
rlm_sql_sqlite_conn_t *conn = handle->conn;
-
+
if (conn->statement) {
return sqlite3_data_count(conn->statement);
}
-
+
return 0;
}
{
int status;
rlm_sql_sqlite_conn_t *conn = handle->conn;
-
+
int i = 0;
-
+
char **row;
/*
* Executes the SQLite query and interates over the results
*/
status = sqlite3_step(conn->statement);
-
+
/*
* Error getting next row
*/
if (status == SQLITE_DONE) {
return 1;
}
-
+
/*
* We only need to do this once per result set, because
* the number of columns won't change.
* Free the previous result (also gets called on finish_query)
*/
talloc_free(handle->row);
-
+
MEM(row = handle->row = talloc_zero_array(handle->conn, char *, conn->col_count + 1));
-
+
for (i = 0; i < conn->col_count; i++) {
switch (sqlite3_column_type(conn->statement, i)) {
- case SQLITE_INTEGER:
+ case SQLITE_INTEGER:
MEM(row[i] = talloc_asprintf(row, "%d", sqlite3_column_int(conn->statement, i)));
break;
-
+
case SQLITE_FLOAT:
MEM(row[i] = talloc_asprintf(row, "%f", sqlite3_column_double(conn->statement, i)));
break;
-
+
case SQLITE_TEXT:
{
char const *p;
p = (char const *) sqlite3_column_text(conn->statement, i);
-
+
if (p) {
MEM(row[i] = talloc_strdup(row, p));
}
}
break;
-
+
case SQLITE_BLOB:
{
const uint8_t *p;
p = sqlite3_column_blob(conn->statement, i);
if (p) {
len = sqlite3_column_bytes(conn->statement, i);
-
+
MEM(row[i] = talloc_zero_array(row, char, len + 1));
- memcpy(row[i], p, len);
+ memcpy(row[i], p, len);
}
}
break;
-
+
default:
break;
}
}
-
+
return 0;
}
UNUSED rlm_sql_config_t *config)
{
rlm_sql_sqlite_conn_t *conn = handle->conn;
-
+
if (conn->statement) {
TALLOC_FREE(handle->row);
-
+
(void) sqlite3_finalize(conn->statement);
conn->statement = NULL;
conn->col_count = 0;
}
-
+
/*
* There's no point in checking the code returned by finalize
* as it'll have already been encountered elsewhere in the code.
rlm_sql_sqlite_conn_t *conn = handle->conn;
if (conn->db) {
- return sqlite3_changes(conn->db);
+ return sqlite3_changes(conn->db);
}
return -1;
static int sql_socket_destructor(void *c)
{
rlm_sql_unixodbc_conn_t *conn = c;
-
+
DEBUG2("rlm_sql_unixodbc: Socket destructor called, closing socket");
if (conn->statement) {
SQLFreeStmt(conn->statement, SQL_DROP);
}
-
+
if (conn->dbc) {
SQLDisconnect(conn->dbc);
SQLFreeConnect(conn->dbc);
}
-
+
if (conn->env) {
SQLFreeEnv(conn->env);
}
-
+
return 0;
}
ERROR("rlm_sql_unixodbc: Can't allocate environment handle\n");
return -1;
}
-
+
err_handle = SQLSetEnvAttr(conn->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
if (sql_state(err_handle, handle, config)) {
ERROR("rlm_sql_unixodbc: Can't register ODBC version\n");
return -1;
}
-
+
/* 2. Allocate connection handle */
err_handle = SQLAllocHandle(SQL_HANDLE_DBC, conn->env, &conn->dbc);
if (sql_state(err_handle, handle, config)) {
/* 3. Connect to the datasource */
{
SQLCHAR *odbc_server, *odbc_login, *odbc_password;
-
+
memcpy(&odbc_server, &config->sql_server, sizeof(odbc_server));
memcpy(&odbc_login, &config->sql_login, sizeof(odbc_login));
memcpy(&odbc_password, &config->sql_password, sizeof(odbc_password));
odbc_login, strlen(config->sql_login),
odbc_password, strlen(config->sql_password));
}
-
+
if (sql_state(err_handle, handle, config)) {
ERROR("rlm_sql_unixodbc: Connection failed\n");
return -1;
if(err_handle == SQL_NO_DATA_FOUND) {
return 0;
}
-
+
if ((state = sql_state(err_handle, handle, config))) {
if(state == RLM_SQL_RECONNECT) {
DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect");
}
-
+
return state;
}
-
+
handle->row = conn->row;
return 0;
}
sql_free_result(handle, config);
SQLFreeStmt(conn->statement, SQL_CLOSE);
conn->statement = NULL;
-
+
return 0;
}
SQLFreeStmt(conn->statement, SQL_CLOSE);
conn->statement = NULL;
-
+
return 0;
}
conn->row[column] = NULL;
}
}
-
+
free(conn->row);
conn->row = NULL;
}
if(SQL_SUCCEEDED(err_handle)) {
return 0; /* on success, just return 0 */
}
-
+
error[0] = state[0] = '\0';
SQLError(conn->env, conn->dbc, conn->statement, state, &errornum,
ERROR("rlm_sql_unixodbc: SQL down %s %s\n", state, error);
res = RLM_SQL_RECONNECT;
break;
-
+
/* any other SQLSTATE means error */
default:
ERROR("rlm_sql_unixodbc: %s %s\n", state, error);
offsetof(sql_acct_section_t, reference), NULL, ".query"},
{"logfile", PW_TYPE_STRING_PTR,
offsetof(sql_acct_section_t, logfile), NULL, NULL},
-
+
{NULL, -1, 0, NULL, NULL}
};
*/
{"query_timeout", PW_TYPE_INTEGER,
offsetof(rlm_sql_config_t,query_timeout), NULL, NULL},
-
+
{NULL, -1, 0, NULL, NULL}
};
* needed or not
*/
sql_set_user(inst, request, NULL);
-
+
handle = sql_get_socket(inst);
if (!handle) {
return 0;
}
-
+
rlm_sql_query_log(inst, request, NULL, query);
/*
if (rlm_sql_query(&handle, inst, query)) {
goto finish;
}
-
+
numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
if (numaffected < 1) {
RDEBUG("SQL query affected no rows");
-
+
goto finish;
}
* if the output buffer was large enough.
*/
snprintf(buffer, sizeof(buffer), "%d", numaffected);
-
+
len = strlen(buffer);
if (len >= freespace){
RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->config->xlat_name);
-
+
(inst->module->sql_finish_query)(handle, inst->config);
ret = -1;
goto finish;
}
-
+
memcpy(out, buffer, len + 1); /* we did bounds checking above */
ret = len;
-
+
(inst->module->sql_finish_query)(handle, inst->config);
-
+
goto finish;
} /* else it's a SELECT statement */
if (rlm_sql_select_query(&handle, inst, query)){
ret = -1;
-
+
goto finish;
}
RDEBUG("SQL query failed");
(inst->module->sql_finish_select_query)(handle, inst->config);
ret = -1;
-
+
goto finish;
}
if (!row) {
RDEBUG("SQL query returned no results");
(inst->module->sql_finish_select_query)(handle, inst->config);
-
+
goto finish;
}
goto finish;
}
-
+
len = strlen(row[0]);
if (len >= freespace){
RDEBUG("Insufficient string space");
RDEBUG("sql_xlat finished");
(inst->module->sql_finish_select_query)(handle, inst->config);
-
+
finish:
sql_release_socket(inst, handle);
-
+
return ret;
}
if (!handle) {
return -1;
}
-
+
if (rlm_sql_select_query(&handle, inst, inst->config->client_query)){
return -1;
}
DEBUG("rlm_sql (%s): Adding client %s (%s) to %s clients list",
inst->config->xlat_name,
row[1], row[2], server ? server : "global");
-
+
/* FIXME: We should really pass a proper ctx */
c = client_from_query(NULL,
row[1], /* identifier */
if (!c) {
continue;
}
-
+
if (!client_add(NULL, c)) {
WARN("Failed to add client, possible duplicate?");
client_free(c);
continue;
}
-
+
DEBUG("rlm_sql (%s): Client \"%s\" (%s) added", c->longname, c->shortname,
inst->config->xlat_name);
}
-
+
(inst->module->sql_finish_select_query)(handle, inst->config);
sql_release_socket(inst, handle);
} else {
return 0;
}
-
+
len = radius_axlat(&expanded, request, sqluser, NULL, NULL);
if (len < 0) {
return -1;
}
-
+
vp = pairalloc(request->packet, inst->sql_user);
vp->op = T_OP_SET;
-
+
pairstrcpy(vp, expanded); /* FIXME: pairsteal */
pairadd(&request->packet->vps, vp);
if (ret < 0) {
return -1;
}
-
+
while (rlm_sql_fetch_row(&handle, inst) == 0) {
row = handle->row;
if (!row)
*/
if (sql_get_grouplist(inst, handle, request, &head) < 0) {
REDEBUG("Error retrieving group list");
-
+
return RLM_MODULE_FAIL;
}
if (!sql_group) {
REDEBUG("Error creating Sql-Group attribute");
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
/*
* Expand the group query
*/
inst) < 0) {
REDEBUG("Error generating query");
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
if (rows < 0) {
REDEBUG("Error retrieving check pairs for group %s", entry->name);
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
/*
* If we got check rows we need to process them before we decide to process the reply rows
*/
continue;
}
-
+
RDEBUG2("User found in= RLM_MODULE_OK; group %s", entry->name);
-
+
/*
* Now get the reply pairs since the paircompare matched
*/
goto finish;
}
-
+
if (sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded) < 0) {
REDEBUG("Error retrieving reply pairs for group %s", entry->name);
rcode = RLM_MODULE_FAIL;
goto finish;
}
-
+
*dofallthrough = fallthrough(reply_tmp);
-
+
pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
-
+
radius_xlat_move(request, &request->reply->vps, &reply_tmp);
reply_tmp = NULL;
-
+
radius_xlat_move(request, &request->config_items, &check_tmp);
check_tmp = NULL;
}
-
+
finish:
-
+
talloc_free(expanded);
talloc_free(head);
-
+
pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
pairfree(&check_tmp);
CONF_SECTION *cs;
char const *name = section_type_value[comp].section;
-
+
cs = cf_section_sub_find(parent, name);
if (!cs) {
INFO("rlm_sql (%s): Couldn't find configuration for "
"%s, will return NOOP for calls from this section",
inst->config->xlat_name, name);
-
+
return 0;
}
-
+
*config = talloc_zero(parent, sql_acct_section_t);
if (cf_section_parse(cs, *config, acct_section_config) < 0) {
ERROR("rlm_sql (%s): Couldn't find configuration for "
inst->config->xlat_name, name);
return -1;
}
-
+
(*config)->cs = cs;
return 0;
*/
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);
sql_groupcmp, inst);
}
}
-
+
rad_assert(inst->config->xlat_name);
/*
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.
if (!inst->sql_user) {
return -1;
}
-
+
/*
* Export these methods, too. This avoids RTDL_GLOBAL.
*/
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);
return -1;
}
}
-
+
/*
* It's up to the driver to register a destructor
*/
*/
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 &&
static rlm_rcode_t mod_authorize(void *instance, REQUEST * request)
{
int rcode = RLM_MODULE_NOTFOUND;
-
+
rlm_sql_t *inst = instance;
rlm_sql_handle_t *handle;
-
+
VALUE_PAIR *check_tmp = NULL;
VALUE_PAIR *reply_tmp = NULL;
VALUE_PAIR *user_profile = NULL;
if (radius_axlat(&expanded, request, inst->config->authorize_check_query,
sql_escape_func, inst) < 0) {
REDEBUG("Error generating query");
-
+
goto error;
}
-
+
rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded);
if (rows < 0) {
REDEBUG("SQL query error");
-
+
goto error;
}
TALLOC_FREE(expanded);
-
+
/*
* Only do this if *some* check pairs were returned
*/
if ((rows > 0) &&
- (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) {
+ (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) {
RDEBUG2("User found in radcheck table");
-
+
radius_xlat_move(request, &request->config_items, &check_tmp);
-
+
rcode = RLM_MODULE_OK;
}
-
+
/*
* We only process reply table items if check conditions were verified
*/
goto skipreply;
}
}
-
+
if (inst->config->authorize_reply_query && *inst->config->authorize_reply_query) {
/*
* Now get the reply pairs since the paircompare matched
if (radius_axlat(&expanded, request, inst->config->authorize_reply_query,
sql_escape_func, inst) < 0) {
REDEBUG("Error generating query");
-
+
goto error;
}
-
+
rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded);
if (rows < 0) {
REDEBUG("SQL query error");
goto error;
}
TALLOC_FREE(expanded);
-
+
if (rows > 0) {
if (!inst->config->read_groups) {
dofallthrough = fallthrough(reply_tmp);
}
-
+
RDEBUG2("User found in radreply table");
-
+
radius_xlat_move(request, &request->reply->vps, &reply_tmp);
-
+
rcode = RLM_MODULE_OK;
}
}
-
+
skipreply:
/*
* Check for a default_profile or for a User-Profile.
*/
user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
-
+
char const *profile = user_profile ?
user_profile->vp_strvalue :
inst->config->default_profile;
-
+
if (!profile || !*profile) {
goto release;
}
-
+
RDEBUG("Checking profile %s", profile);
-
+
if (sql_set_user(inst, request, profile) < 0) {
REDEBUG("Error setting profile");
goto error;
}
-
+
rcode = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
if (rcode != RLM_MODULE_OK) {
REDEBUG("Error processing profile groups");
goto release;
}
}
-
+
goto release;
-
+
error:
rcode = RLM_MODULE_FAIL;
-
+
release:
TALLOC_FREE(expanded);
-
+
sql_release_socket(inst, handle);
-
+
pairfree(&check_tmp);
pairfree(&reply_tmp);
-
+
return rcode;
}
char *expanded = NULL;
rad_assert(section);
-
+
if (section->reference[0] != '.') {
*p++ = '.';
}
-
+
if (radius_xlat(p, sizeof(path) - (p - path), request, section->reference, NULL, NULL) < 0) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
item = cf_reference_item(NULL, section->cs, path);
if (!item) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if (cf_item_is_section(item)){
REDEBUG("Sections are not supported as references");
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
pair = cf_itemtopair(item);
attr = cf_pair_attr(pair);
-
+
RDEBUG2("Using query template '%s'", attr);
-
+
handle = sql_get_socket(inst);
if (!handle) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
sql_set_user(inst, request, NULL);
while (true) {
if (!value) {
RDEBUG("Ignoring null query");
rcode = RLM_MODULE_NOOP;
-
+
goto finish;
}
-
+
if (radius_axlat(&expanded, request, value, sql_escape_func, inst) < 0) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if (!*expanded) {
RDEBUG("Ignoring null query");
rcode = RLM_MODULE_NOOP;
talloc_free(expanded);
-
+
goto finish;
}
-
+
rlm_sql_query_log(inst, request, section, expanded);
-
+
/*
* If rlm_sql_query cannot use the socket it'll try and
* reconnect. Reconnecting will automatically release
*/
sql_ret = rlm_sql_query(&handle, inst, expanded);
TALLOC_FREE(expanded);
-
+
if (sql_ret == RLM_SQL_RECONNECT) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
rad_assert(handle);
-
+
/*
* Assume all other errors are incidental, and just meant our
* operation failed and its not a client or SQL syntax error.
if (numaffected > 0) {
break;
}
-
+
RDEBUG("No records updated");
}
(inst->module->sql_finish_query)(handle, inst->config);
-
+
/*
* We assume all entries with the same name form a redundant
* set of queries.
*/
pair = cf_pair_find_next(section->cs, pair, attr);
-
+
if (!pair) {
RDEBUG("No additional queries configured");
-
+
rcode = RLM_MODULE_NOOP;
-
+
goto finish;
}
RDEBUG("Trying next query...");
}
-
+
(inst->module->sql_finish_query)(handle, inst->config);
finish:
* Accounting: Insert or update session data in our sql table
*/
static rlm_rcode_t mod_accounting(void *instance, REQUEST * request) {
- rlm_sql_t *inst = instance;
+ rlm_sql_t *inst = instance;
if (inst->config->accounting) {
return acct_redundant(inst, request, inst->config->accounting);
}
-
+
return RLM_MODULE_NOOP;
}
int ret;
uint32_t nas_addr = 0;
int nas_port = 0;
-
+
char *expanded = NULL;
/* If simul_count_query is not defined, we don't do any checking */
if((!request->username) || (request->username->length == '\0')) {
REDEBUG("Zero Length username not permitted");
-
+
return RLM_MODULE_INVALID;
}
talloc_free(expanded);
return RLM_MODULE_FAIL;
}
-
+
if (rlm_sql_select_query(&handle, inst, expanded)) {
rcode = RLM_MODULE_FAIL;
goto finish;
*/
if (!inst->config->simul_verify_query || (inst->config->simul_verify_query[0] == '\0')) {
rcode = RLM_MODULE_OK;
-
+
goto finish;
}
if (radius_axlat(&expanded, request, inst->config->simul_verify_query, sql_escape_func, inst) < 0) {
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if(rlm_sql_select_query(&handle, inst, expanded)) {
goto finish;
}
if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
ipno = vp->vp_ipaddr;
}
-
+
if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
call_num = vp->vp_strvalue;
}
if (!row) {
break;
}
-
+
if (!row[2]){
RDEBUG("Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if (!row[1]){
RDEBUG("Cannot zap stale entry. No session id in entry.", inst->config->xlat_name);
rcode = RLM_MODULE_FAIL;
-
+
goto finish;
}
-
+
if (row[3]) {
nas_addr = inet_addr(row[3]);
}
-
+
if (row[4]) {
nas_port = atoi(row[4]);
}
-
+
check = rad_check_ts(nas_addr, nas_port, row[2], row[1]);
if (check == 0) {
/*
* duplicate logins: return an error.
*/
REDEBUG("Failed to check the terminal server for user '%s'.", row[2]);
-
+
rcode = RLM_MODULE_FAIL;
goto finish;
}
}
finish:
-
+
(inst->module->sql_finish_select_query)(handle, inst->config);
sql_release_socket(inst, handle);
talloc_free(expanded);
*/
static rlm_rcode_t mod_post_auth(void *instance, REQUEST * request) {
rlm_sql_t *inst = instance;
-
+
if (inst->config->postauth) {
return acct_redundant(inst, request, inst->config->postauth);
}
-
+
return RLM_MODULE_NOOP;
}
*/
typedef struct sql_acct_section {
CONF_SECTION *cs;
-
+
char const *reference;
-
+
char const *logfile;
} sql_acct_section_t;
char const *query_user;
char const *default_profile;
-
+
char const *client_query;
char const *authorize_check_query;
char const *authorize_reply_query;
char const *simul_count_query;
char const *simul_verify_query;
char const *groupmemb_query;
-
+
int const do_clients;
int const read_groups;
char const *logfile;
int const deletestalesessions;
char const *allowed_chars;
int const query_timeout;
-
+
void *driver; //!< Where drivers should write a
//!< pointer to their configurations.
-
+
/*
* @todo The rest of the queries should also be moved into
* their own sections.
*/
-
+
/*
* Section configurations
*/
typedef struct rlm_sql_module_t {
char const *name;
- sql_rcode_t (*mod_instantiate)(CONF_SECTION *conf, rlm_sql_config_t *config);
+ sql_rcode_t (*mod_instantiate)(CONF_SECTION *conf, rlm_sql_config_t *config);
sql_rcode_t (*sql_socket_init)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
sql_rcode_t (*sql_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
sql_rcode_t (*sql_select_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
const DICT_ATTR *sql_user; //!< Cached pointer to SQL-User-Name
//!< dictionary attribute.
-
+
void *handle;
rlm_sql_module_t *module;
{
rlm_sql_handle_t *handle = conn;
rlm_sql_t *inst = handle->inst;
-
+
rad_assert(inst);
-
+
exec_trigger(NULL, inst->cs, "modules.sql.close", false);
-
+
return 0;
}
rlm_sql_handle_t *handle;
handle = talloc_zero(instance, rlm_sql_handle_t);
-
+
/*
* Handle requires a pointer to the SQL inst so the
* destructor has access to the module configuration.
*/
handle->inst = inst;
-
+
/*
* When something frees this handle the destructor set by
* the driver will be called first, closing any open sockets.
rcode = (inst->module->sql_socket_init)(handle, inst->config);
if (rcode == 0) {
exec_trigger(NULL, inst->cs, "modules.sql.open", false);
-
+
return handle;
}
* @todo Calls to this should eventually go away.
*/
static int mod_conn_delete(UNUSED void *instance, void *handle)
-{
+{
return talloc_free(handle);
}
fr_strerror());
return -1;
}
-
+
if (do_xlat) {
if (pairmark_xlat(vp, value) < 0) {
ERROR("rlm_sql: Error marking pair for xlat");
-
+
pairbasicfree(vp);
return -1;
}
} else {
if (pairparsevalue(vp, value) < 0) {
ERROR("rlm_sql: Error parsing value");
-
+
pairbasicfree(vp);
return -1;
}
if (!*handle || !(*handle)->conn) {
return -1;
}
-
+
/*
* We can't implement reconnect logic here, because the caller may require
* the original connection to free up queries or result sets associated with
* that connection.
*/
ret = (inst->module->sql_fetch_row)(*handle, inst->config);
-
+
if (ret < 0) {
char const *error = (inst->module->sql_error)(*handle, inst->config);
EDEBUG("rlm_sql (%s): Error fetching row: %s",
ret = -1;
goto sql_down;
}
-
+
while (1) {
DEBUG("rlm_sql (%s): Executing query: '%s'",
inst->config->xlat_name, query);
sql_down:
*handle = fr_connection_reconnect(inst->pool, *handle);
if (!*handle) return RLM_SQL_RECONNECT;
-
+
continue;
}
-
+
if (ret < 0) {
char const *error = (inst->module->sql_error)(*handle, inst->config);
ERROR("rlm_sql (%s): Database query error: %s",
inst->config->xlat_name, error ? error : "<UNKNOWN>");
}
-
+
return ret;
}
}
ret = -1;
goto sql_down;
}
-
+
while (1) {
DEBUG("rlm_sql (%s): Executing query: '%s'",
inst->config->xlat_name, query);
sql_down:
*handle = fr_connection_reconnect(inst->pool, *handle);
if (!*handle) return RLM_SQL_RECONNECT;
-
+
continue;
}
-
+
if (ret < 0) {
char const *error = (inst->module->sql_error)(*handle, inst->config);
ERROR("rlm_sql (%s): Database query error '%s'",
inst->config->xlat_name, error ? error : "<UNKNOWN>");
}
-
+
return ret;
}
}
break;
if (sql_userparse(ctx, pair, row) != 0) {
ERROR("rlm_sql (%s): Error getting data from database", inst->config->xlat_name);
-
+
(inst->module->sql_finish_select_query)(*handle, inst->config);
-
+
return -1;
}
rows++;
if (section) {
filename = section->logfile;
}
-
+
if (!filename) {
filename = inst->config->logfile;
-
+
if (!filename) {
return;
}
}
-
+
if (radius_axlat(&expanded, request, filename, NULL, NULL) < 0) {
return;
}
if (fd < 0) {
ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->config->xlat_name,
expanded, strerror(errno));
-
+
talloc_free(expanded);
return;
}
ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->config->xlat_name, expanded,
strerror(errno));
}
-
+
talloc_free(expanded);
close(fd); /* and release the lock */
}
offsetof(rlm_sqlcounter_t,reply_name), NULL, NULL },
{ "reply_name", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
offsetof(rlm_sqlcounter_t,reply_name), NULL, "Session-Timeout" },
-
+
{ NULL, -1, 0, NULL, NULL }
};
char *p;
char query[MAX_QUERY_LEN];
char *expanded = NULL;
-
+
size_t len;
len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, query);
if (len >= sizeof(query) - 1) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p = query + len;
-
+
/* first, expand %k, %b and %e in query */
len = sqlcounter_expand(p, p - query, inst->query, inst);
if (len <= 0) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p += len;
-
+
if ((p - query) < 2) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p[0] = '}';
p[1] = '\0';
VALUE_PAIR *key_vp, *check_vp;
VALUE_PAIR *reply_item;
char msg[128];
-
+
char *p;
char query[MAX_QUERY_LEN];
char *expanded = NULL;
-
+
size_t len;
/*
len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, query);
if (len >= sizeof(query) - 1) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p = query + len;
-
+
/* first, expand %k, %b and %e in query */
len = sqlcounter_expand(p, p - query, inst->query, inst);
if (len <= 0) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p += len;
-
+
if ((p - query) < 2) {
REDEBUG("Insufficient query buffer space");
-
+
return RLM_MODULE_FAIL;
}
-
+
p[0] = '}';
p[1] = '\0';
RDEBUG2("Authorized user %s, check_item=%u, counter=%u", key_vp->vp_strvalue, check_vp->vp_integer,
counter);
- RDEBUG2("Sent Reply-Item for user %s, Type=%s, value=%u", key_vp->vp_strvalue, inst->reply_name,
+ RDEBUG2("Sent Reply-Item for user %s, Type=%s, value=%u", key_vp->vp_strvalue, inst->reply_name,
reply_item->vp_integer);
}
else{
inst->reset);
rcode = RLM_MODULE_REJECT;
- RDEBUG2("Rejected user %s, check_item=%u, counter=%u", key_vp->vp_strvalue,
+ RDEBUG2("Rejected user %s, check_item=%u, counter=%u", key_vp->vp_strvalue,
check_vp->vp_integer,counter);
}
offsetof(rlm_sqlippool_t,allocate_begin), NULL, NULL},
{ "allocate_begin", PW_TYPE_STRING_PTR,
offsetof(rlm_sqlippool_t,allocate_begin), NULL, "START TRANSACTION" },
-
+
{ "allocate-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_clear), NULL, NULL},
+ offsetof(rlm_sqlippool_t,allocate_clear), NULL, NULL},
{ "allocate_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
{ "allocate-find", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_find), NULL, NULL},
+ offsetof(rlm_sqlippool_t,allocate_find), NULL, NULL},
{ "allocate_find", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
-
+
{ "allocate-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
offsetof(rlm_sqlippool_t,allocate_update), NULL, NULL },
{ "allocate_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
-
+
{ "allocate-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
offsetof(rlm_sqlippool_t,allocate_commit), NULL, NULL },
{ "allocate_commit", PW_TYPE_STRING_PTR,
offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
-
+
{ "pool-check", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,pool_check), NULL, NULL },
{ "pool_check", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,pool_check), NULL, "" },
{ "start-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_begin), NULL, NULL },
{ "start_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "START TRANSACTION" },
-
+
{ "start-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_update), NULL, NULL },
{ "start_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
{ "alive-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_update), NULL, NULL },
{ "alive_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
-
+
{ "alive-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_commit), NULL, NULL },
{ "alive_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
{ "stop-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_begin), NULL, NULL },
{ "stop_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "START TRANSACTION" },
-
- { "stop-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_clear), NULL, NULL },
+
+ { "stop-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_clear), NULL, NULL },
{ "stop_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
{ "stop-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_commit), NULL, NULL },
{ "on-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_begin), NULL, NULL },
{ "on_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "START TRANSACTION" },
-
+
{ "on-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_clear), NULL, NULL },
{ "on_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
-
+
{ "on-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_commit), NULL, NULL },
{ "on_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
{ "off-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_begin), NULL, NULL },
{ "off_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "START TRANSACTION" },
-
+
{ "off-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_clear), NULL, NULL },
{ "off_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
-
+
{ "off-commit",PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_commit), NULL, NULL },
{ "off_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
{
char query[MAX_QUERY_LEN];
char *expanded = NULL;
-
+
int ret;
/*
if (!ret){
REDEBUG("database query error in: '%s'", expanded);
talloc_free(expanded);
-
+
return 0;
}
talloc_free(expanded);
{
char query[MAX_QUERY_LEN];
char *expanded = NULL;
-
+
int rlen, retval;
/*
rad_assert(request != NULL);
*out = '\0';
-
+
/*
* Do an xlat on the provided string
*/
}
retval = data->sql_inst->sql_select_query(&handle, data->sql_inst, expanded);
talloc_free(expanded);
-
+
if (retval != 0){
REDEBUG("database query error on '%s'", query);
-
+
return 0;
}
/*
- * If we have something to log, then we log it.
+ * If we have something to log, then we log it.
* Otherwise we return the retcode as soon as possible
*/
static int do_logging(REQUEST *request, char *str, int rcode)
{
char *expanded = NULL;
-
+
if (!str || !*str) return rcode;
if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) {
}
pairmake_config("Module-Success-Message", expanded, T_OP_SET);
-
+
talloc_free(expanded);
return rcode;
grp = getgrnam(check->vp_strvalue);
if (!grp)
return -1;
-
+
retval = (pwd->pw_gid == grp->gr_gid) ? 0 : -1;
if (retval < 0) {
for (member = grp->gr_mem; *member && retval; member++) {
*/
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
-
+
HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
* MIP-RK-2 = HMAC-SSHA256(EMSK, MIP-RK-1 | usage-data | 0x01)
*/
HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
-
+
HMAC_Update(&hmac, (uint8_t const *) &mip_rk_1, rk1_len);
HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
HMAC_Final(&hmac, &mip_rk_2[0], &rk2_len);
* MIP-SPI = HMAC-SSHA256(MIP-RK, "SPI CMIP PMIP");
*/
HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha256(), NULL);
-
+
HMAC_Update(&hmac, (uint8_t const *) "SPI CMIP PMIP", 12);
HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
fa_rk = pairfind(request->reply->vps, 14, VENDORPEC_WIMAX, TAG_ANY);
if (fa_rk && (fa_rk->length <= 1)) {
HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
-
+
HMAC_Update(&hmac, (uint8_t const *) "FA-RK", 5);
HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
* @return one of the RLM_RCODE_* constants.
*/
rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, VALUE_PAIR *otp)
-{
+{
uint32_t counter;
yubikey_token_st token;
-
- const DICT_ATTR *da;
-
+
+ const DICT_ATTR *da;
+
char private_id[(YUBIKEY_UID_SIZE * 2) + 1];
VALUE_PAIR *key, *vp;
-
+
da = dict_attrbyname("Yubikey-Key");
if (!da) {
REDEBUG("Dictionary missing entry for 'Yubikey-Key'");
return RLM_MODULE_FAIL;
}
-
+
key = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY);
if (!key) {
REDEBUG("Yubikey-Key attribute not found in control list, can't decrypt OTP data");
if (key->length != YUBIKEY_KEY_SIZE) {
REDEBUG("Yubikey-Key length incorrect, expected %u got %zu", YUBIKEY_KEY_SIZE, key->length);
- return RLM_MODULE_INVALID;
+ return RLM_MODULE_INVALID;
}
-
+
yubikey_parse(otp->vp_octets + inst->id_len, key->vp_octets, &token);
/*
* Apparently this just uses byte offsets...
*/
if (!yubikey_crc_ok_p((uint8_t *) &token)) {
- REDEBUG("Decrypting OTP token data failed, rejecting");
+ REDEBUG("Decrypting OTP token data failed, rejecting");
return RLM_MODULE_REJECT;
}
-
+
RDEBUG("Token data decrypted successfully");
-
+
if (request->options && request->radlog) {
(void) fr_bin2hex((uint8_t*) &token.uid,
(char *) &private_id, YUBIKEY_UID_SIZE);
vp = pairmake(request, &request->packet->vps, "Yubikey-Private-ID", NULL, T_OP_SET);
if (!vp) {
REDEBUG("Failed creating Yubikey-Private-ID");
-
+
return RLM_MODULE_FAIL;
}
pairmemcpy(vp, token.uid, YUBIKEY_UID_SIZE);
-
+
/*
* Token timestamp
*/
vp = pairmake(request, &request->packet->vps, "Yubikey-Timestamp", NULL, T_OP_SET);
if (!vp) {
REDEBUG("Failed creating Yubikey-Timestamp");
-
+
return RLM_MODULE_FAIL;
}
vp->vp_integer = (token.tstph << 16) | token.tstpl;
vp->length = 4;
-
+
/*
* Token random
*/
vp = pairmake(request, &request->packet->vps, "Yubikey-Random", NULL, T_OP_SET);
if (!vp) {
REDEBUG("Failed creating Yubikey-Random");
-
+
return RLM_MODULE_FAIL;
}
vp->vp_integer = token.rnd;
vp->length = 4;
-
+
/*
* Combine the two counter fields together so we can do
* replay attack checks.
*/
counter = (yubikey_counter(token.ctr) << 16) | token.use;
-
+
vp = pairmake(request, &request->packet->vps, "Yubikey-Counter", NULL, T_OP_SET);
if (!vp) {
REDEBUG("Failed creating Yubikey-Counter");
-
+
return RLM_MODULE_FAIL;
}
vp->vp_integer = counter;
vp->length = 4;
-
+
/*
* Now we check for replay attacks
*/
if (counter <= vp->vp_integer) {
REDEBUG("Replay attack detected! Counter value %u, is lt or eq to last known counter value %u",
counter, vp->vp_integer);
- return RLM_MODULE_REJECT;
+ return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
*/
#ifdef HAVE_YKCLIENT
-static const CONF_PARSER validation_config[] = {
+static const CONF_PARSER validation_config[] = {
{ "client_id", PW_TYPE_INTEGER, offsetof(rlm_yubikey_t, client_id), NULL, 0},
- { "api_key", PW_TYPE_STRING_PTR, offsetof(rlm_yubikey_t, api_key), NULL, NULL},
+ { "api_key", PW_TYPE_STRING_PTR, offsetof(rlm_yubikey_t, api_key), NULL, NULL},
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static const CONF_PARSER module_config[] = {
{ "id_length", PW_TYPE_INTEGER, offsetof(rlm_yubikey_t, id_len), NULL, "12" },
{ "decrypt", PW_TYPE_BOOLEAN, offsetof(rlm_yubikey_t, decrypt), NULL, "no" },
- { "validate", PW_TYPE_BOOLEAN, offsetof(rlm_yubikey_t, validate), NULL, "no" },
+ { "validate", PW_TYPE_BOOLEAN, offsetof(rlm_yubikey_t, validate), NULL, "no" },
#ifdef HAVE_YKCLIENT
{ "validation", PW_TYPE_SUBSECTION, 0, NULL, (void const *) validation_config },
#endif
if (modhex[i << 1] == '\0') {
break;
}
-
+
/*
* We only deal with whole bytes
- */
+ */
if (modhex[(i << 1) + 1] == '\0')
return -1;
-
+
if (!(c1 = memchr(modhextab, tolower((int) modhex[i << 1]), 16)) ||
!(c2 = memchr(modhextab, tolower((int) modhex[(i << 1) + 1]), 16)))
return -1;
-
+
hex[i] = hextab[c1 - modhextab];
hex[i + 1] = hextab[c2 - modhextab];
}
* Example: "%{modhextohex:vvrbuctetdhc}" == "ffc1e0d3d260"
*/
static ssize_t modhex_to_hex_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
-{
+{
ssize_t len;
if (outlen < strlen(fmt)) {
if (len <= 0) {
*out = '\0';
REDEBUG("Modhex string invalid");
-
+
return -1;
}
-
+
return len;
}
*/
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
- rlm_yubikey_t *inst = instance;
+ rlm_yubikey_t *inst = instance;
inst->name = cf_section_name2(conf);
if (!inst->name) {
}
#endif
- if (inst->validate) {
+ if (inst->validate) {
#ifdef HAVE_YKCLIENT
CONF_SECTION *cs;
-
+
cs = cf_section_sub_find(conf, "validation");
if (!cs) {
EDEBUG("rlm_yubikey (%s): Missing validation section", inst->name);
return -1;
}
-
+
if (rlm_yubikey_ykclient_init(cs, inst) < 0) {
return -1;
}
char const *passcode;
size_t i, len;
VALUE_PAIR *vp;
-
+
/*
* Can't do yubikey auth if there's no password.
*/
}
RDEBUG2("No Clear-Text password in the request. Can't do Yubikey authentication.");
-
+
return RLM_MODULE_NOOP;
}
* modhex encoded form).
*
* <public_id (6-16 bytes)> + <aes-block (32 bytes)>
- *
+ *
*/
if (len != (inst->id_len + 32)) {
RDEBUG2("User-Password value is not the correct length, expected %u, got %zu", inst->id_len + 32, len);
- return RLM_MODULE_NOOP;
+ return RLM_MODULE_NOOP;
}
for (i = inst->id_len; i < len; i++) {
if (!is_modhex(*passcode)) {
RDEBUG2("User-Password (aes-block) value contains non modhex chars");
-
- return RLM_MODULE_NOOP;
+
+ return RLM_MODULE_NOOP;
}
}
vp = radius_paircreate(request, &request->config_items, PW_AUTH_TYPE, 0);
vp->vp_integer = dval->value;
}
-
+
/*
* Split out the Public ID in case another module in authorize
* needs to verify it's associated with the user.
vp = pairmake(request, &request->packet->vps, "Yubikey-Public-ID", NULL, T_OP_SET);
if (!vp) {
REDEBUG("Failed creating Yubikey-Public-ID");
-
+
return RLM_MODULE_FAIL;
}
-
+
pairstrcpy(vp, passcode);
}
rlm_yubikey_t *inst = instance;
char const *passcode;
size_t i, len;
-
+
/*
* Can't do yubikey auth if there's no password.
*/
REDEBUG("No Clear-Text password in the request. Can't do Yubikey authentication.");
return RLM_MODULE_INVALID;
}
-
+
passcode = request->password->vp_strvalue;
len = request->password->length;
/*
*/
if (len != (inst->id_len + 32)) {
REDEBUG("User-Password value is not the correct length, expected %u, got %zu", inst->id_len + 32, len);
- return RLM_MODULE_INVALID;
+ return RLM_MODULE_INVALID;
}
for (i = inst->id_len; i < len; i++) {
if (!is_modhex(*passcode)) {
RDEBUG2("User-Password (aes-block) value contains non modhex chars");
- return RLM_MODULE_INVALID;
+ return RLM_MODULE_INVALID;
}
}
-
+
#ifdef HAVE_YUBIKEY
if (inst->decrypt) {
rcode = rlm_yubikey_decrypt(inst, request, request->password);
int decrypt; //!< Decrypt the OTP string using the yubikey library.
int validate; //!< Validate the OTP string using the ykclient library.
char const **uris; //!< Yubicloud URLs to validate the token against.
-
+
#ifdef HAVE_YKCLIENT
unsigned int client_id; //!< Validation API client ID.
char *api_key; //!< Validation API signing key.
status = ykclient_handle_init(inst->ykc, &yandle);
if (status != YKCLIENT_OK) {
EDEBUG("rlm_yubikey (%s): %s", inst->name, ykclient_strerror(status));
-
+
return NULL;
}
-
+
return yandle;
}
static int mod_socket_delete(UNUSED void *instance, void *handle)
{
ykclient_handle_t *yandle = handle;
-
+
ykclient_handle_done(&yandle);
-
+
return true;
}
{
ykclient_rc status;
CONF_SECTION *servers;
-
+
char prefix[100];
-
+
int count = 0;
if (!inst->client_id) {
- EDEBUG("rlm_yubikey (%s): client_id must be set when validation is enabled", inst->name);
-
+ EDEBUG("rlm_yubikey (%s): client_id must be set when validation is enabled", inst->name);
+
return -1;
}
-
+
if (!inst->api_key) {
EDEBUG("rlm_yubikey (%s): api_key must be set when validation is enabled", inst->name);
-
+
return -1;
}
DEBUG("rlm_yubikey (%s): Initialising ykclient", inst->name);
-
+
status = ykclient_global_init();
if (status != YKCLIENT_OK) {
yk_error:
EDEBUG("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name);
-
+
return -1;
}
-
+
status = ykclient_init(&inst->ykc);
if (status != YKCLIENT_OK) {
goto yk_error;
}
-
+
servers = cf_section_sub_find(conf, "servers");
if (servers) {
CONF_PAIR *uri, *first;
if (!uri) {
goto init;
}
-
+
while (uri) {
count++;
uri = cf_pair_find_next(servers, uri, "uri");
}
inst->uris = talloc_zero_array(inst, char const *, count);
-
+
uri = first;
count = 0;
while (uri) {
}
}
}
-
+
init:
status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key);
if (status != YKCLIENT_OK) {
- EDEBUG("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name);
-
+ EDEBUG("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name);
+
return -1;
}
-
+
snprintf(prefix, sizeof(prefix), "rlm_yubikey (%s)", inst->name);
inst->conn_pool = fr_connection_pool_init(conf, inst, mod_socket_create, NULL, mod_socket_delete, prefix);
if (!inst->conn_pool) {
ykclient_done(&inst->ykc);
-
+
return -1;
}
-
+
return 0;
}
fr_connection_pool_delete(inst->conn_pool);
ykclient_done(&inst->ykc);
ykclient_global_done();
-
+
return 0;
}
rlm_rcode_t rcode = RLM_MODULE_OK;
ykclient_rc status;
ykclient_handle_t *yandle;
-
+
yandle = fr_connection_get(inst->conn_pool);
if (!yandle) {
return RLM_MODULE_FAIL;
}
-
+
/*
* The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
* requests when their easy handle is removed from the multistack.
*
*/
ykclient_handle_cleanup(yandle);
-
+
status = ykclient_request_process(inst->ykc, yandle, otp->vp_strvalue);
if (status != YKCLIENT_OK) {
REDEBUG("%s", ykclient_strerror(status));
-
+
switch (status) {
case YKCLIENT_BAD_OTP:
case YKCLIENT_REPLAYED_OTP:
rcode = RLM_MODULE_REJECT;
break;
-
+
case YKCLIENT_NO_SUCH_CLIENT:
rcode = RLM_MODULE_NOTFOUND;
break;
-
+
default:
rcode = RLM_MODULE_FAIL;
}
}
-
+
fr_connection_release(inst->conn_pool, yandle);
-
+
return rcode;
}
#endif