The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_unpack.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 44998f5247f88bfeee655290e560307cf556519d $
19  * @file rlm_unpack.c
20  * @brief Unpack binary data
21  *
22  * @copyright 2014 The FreeRADIUS server project
23  * @copyright 2014 Alan DeKok (aland@freeradius.org)
24  */
25 RCSID("$Id: 44998f5247f88bfeee655290e560307cf556519d $")
26 
27 #include <freeradius-devel/server/base.h>
28 #include <freeradius-devel/server/module_rlm.h>
29 #include <freeradius-devel/unlang/xlat_func.h>
30 #include <freeradius-devel/util/base16.h>
31 
32 #include <ctype.h>
33 
35  { .required = true, .single = true, .type = FR_TYPE_VOID },
36  { .required = true, .single = true, .type = FR_TYPE_UINT32 },
37  { .required = true, .single = true, .type = FR_TYPE_STRING },
38  { .single = true, .type = FR_TYPE_VOID },
40 };
41 
42 /** Unpack data
43  *
44  * Example:
45 @verbatim
46 %unpack(%{Class}, 0, integer)
47 @endverbatim
48  * Expands Class, treating octet at offset 0 (bytes 0-3) as an "integer".
49  *
50  * @ingroup xlat_functions
51  */
52 static xlat_action_t unpack_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
53  UNUSED xlat_ctx_t const *xctx, request_t *request,
54  fr_value_box_list_t *in)
55 {
56  size_t len, input_len, offset;
58  uint8_t const *input;
59  uint8_t blob[256];
60  uint32_t repeat = 1, count = 1;
61  fr_value_box_t *data_vb = fr_value_box_list_head(in);
62  fr_value_box_t *offset_vb = fr_value_box_list_next(in, data_vb);
63  fr_value_box_t *type_vb = fr_value_box_list_next(in, offset_vb);
64  fr_value_box_t *repeat_vb = fr_value_box_list_next(in, type_vb);
65  fr_value_box_t *vb;
66  ssize_t used;
67 
68  if ((data_vb->type != FR_TYPE_OCTETS) && (data_vb->type != FR_TYPE_STRING)) {
69  REDEBUG("unpack requires the input attribute to be 'string' or 'octets'");
70  return XLAT_ACTION_FAIL;
71  }
72 
73  if ((data_vb->type == FR_TYPE_STRING) && (data_vb->vb_length > 1) &&
74  (data_vb->vb_strvalue[0] == '0') && (data_vb->vb_strvalue[1] == 'x')) {
75  /*
76  * Hex data.
77  */
78  len = strlen(data_vb->vb_strvalue + 2);
79  if (len > 0) {
81 
82  input = blob;
83  input_len = fr_base16_decode(&err, &FR_DBUFF_TMP(blob, sizeof(blob)),
84  &FR_SBUFF_IN(data_vb->vb_strvalue + 2, len), true);
85  if (err) {
86  REDEBUG("Invalid hex string in '%s'", data_vb->vb_strvalue);
87  return XLAT_ACTION_FAIL;
88  }
89  } else {
90  REDEBUG("Zero length hex string in '%s'", data_vb->vb_strvalue);
91  return XLAT_ACTION_FAIL;
92  }
93  } else if (data_vb->type == FR_TYPE_STRING) {
94  input = (uint8_t const *)data_vb->vb_strvalue;
95  input_len = data_vb->vb_length;
96  } else {
97  input = data_vb->vb_octets;
98  input_len = data_vb->vb_length;
99  }
100 
101  offset = offset_vb->vb_uint32;
102 
103  if (offset >= input_len) {
104  REDEBUG("unpack offset %zu is larger than input data length %zu", offset, input_len);
105  return XLAT_ACTION_FAIL;
106  }
107 
108  /* coverity[dereference] */
109  type = fr_type_from_str(type_vb->vb_strvalue);
110  if (fr_type_is_null(type)) {
111  REDEBUG("Invalid data type '%s'", type_vb->vb_strvalue);
112  return XLAT_ACTION_FAIL;
113  }
114 
115  if (repeat_vb) {
116  if ((repeat_vb->type == FR_TYPE_STRING) && (strcmp(repeat_vb->vb_strvalue, "*") == 0)) {
117  repeat = UINT32_MAX;
118  } else {
119  if (fr_value_box_cast_in_place(repeat_vb, repeat_vb, FR_TYPE_UINT32, NULL) < 0) {
120  REDEBUG("Invalid value for limit");
121  return XLAT_ACTION_FAIL;
122  }
123  repeat = repeat_vb->vb_uint32;
124  }
125  }
126 
127  while (true) {
128  MEM(vb = fr_value_box_alloc_null(ctx));
129 
130  /*
131  * Call the generic routines to get data from the
132  * "network" buffer.
133  */
134  used = fr_value_box_from_network(ctx, vb, type, NULL,
135  &FR_DBUFF_TMP(input + offset, input_len - offset),
136  input_len - offset, data_vb->tainted);
137  if (used < 0) {
138  RPEDEBUG("Failed decoding %s", type_vb->vb_strvalue);
139  talloc_free(vb);
140  return XLAT_ACTION_FAIL;
141  }
142 
143  fr_dcursor_append(out, vb);
144  if (count == repeat) break;
145 
146  offset += used;
147  if (offset + used > input_len) break;
148  count++;
149  }
150 
151  return XLAT_ACTION_DONE;
152 }
153 
154 /*
155  * Register the xlats
156  */
157 static int mod_load(void)
158 {
159  xlat_t *xlat;
160 
161  if (unlikely(!(xlat = xlat_func_register(NULL, "unpack", unpack_xlat, FR_TYPE_VOID)))) return -1;
164 
165  return 0;
166 }
167 
168 static void mod_unload(void)
169 {
170  xlat_func_unregister("unpack");
171 }
172 
173 /*
174  * The module name should be the only globally exported symbol.
175  * That is, everything else should be 'static'.
176  *
177  * If the module needs to temporarily modify it's instantiation
178  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
179  * The server will then take care of ensuring that the module
180  * is single-threaded.
181  */
182 extern module_rlm_t rlm_unpack;
184  .common = {
185  .magic = MODULE_MAGIC_INIT,
186  .name = "unpack",
187  .flags = MODULE_TYPE_THREAD_SAFE,
188  .onload = mod_load,
189  .unload = mod_unload
190  }
191 };
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition: base16.h:95
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static fr_slen_t err
Definition: dict.h:645
static fr_slen_t in
Definition: dict.h:645
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
static xlat_action_t unpack_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Unpack data.
Definition: rlm_unpack.c:52
#define RPEDEBUG(fmt,...)
Definition: log.h:376
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
fr_sbuff_parse_error_t
Definition: merged_model.c:45
static size_t used
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
#define REDEBUG(fmt,...)
Definition: radclient.h:52
static int mod_load(void)
Definition: rlm_unpack.c:157
module_rlm_t rlm_unpack
Definition: rlm_unpack.c:183
static xlat_arg_parser_t const unpack_xlat_args[]
Definition: rlm_unpack.c:34
static void mod_unload(void)
Definition: rlm_unpack.c:168
#define FR_SBUFF_IN(_start, _len_or_end)
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: module.h:49
return count
Definition: module.c:175
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
#define fr_type_is_null(_x)
Definition: types.h:326
static fr_type_t fr_type_from_str(char const *type)
Return the constant value representing a type.
Definition: types.h:443
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition: value.c:1709
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition: value.c:3521
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
static size_t char ** out
Definition: value.h:984
An xlat calling ctx.
Definition: xlat_ctx.h:42
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition: xlat_func.c:415
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195
void xlat_func_unregister(char const *name)
Unregister an xlat function.
Definition: xlat_func.c:531
@ XLAT_FUNC_FLAG_PURE
Definition: xlat_func.h:38