All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_dhcp.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: 3260f2e68b17b6fdf57eabfc809e1526354f9e1b $
19  * @file rlm_dhcp.c
20  * @brief Will contain dhcp listener code.
21  *
22  * @copyright 2012 The FreeRADIUS server project
23  */
24 RCSID("$Id: 3260f2e68b17b6fdf57eabfc809e1526354f9e1b $")
25 
26 #include <freeradius-devel/libradius.h>
27 
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/modules.h>
30 #include <freeradius-devel/dhcp.h>
31 
32 #include <ctype.h>
33 
34 #define PW_DHCP_PARAMETER_REQUEST_LIST 55
35 
36 /*
37  * Define a structure for our module configuration.
38  *
39  * These variables do not need to be in a structure, but it's
40  * a lot cleaner to do so, and a pointer to the structure can
41  * be used as the instance handle.
42  */
43 typedef struct rlm_dhcp_t {
44  int nothing;
45 } rlm_dhcp_t;
46 
47 
48 /*
49  * Allow single attribute values to be retrieved from the dhcp.
50  */
51 static ssize_t dhcp_options_xlat(char **out, size_t outlen,
52  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
53  REQUEST *request, char const *fmt)
54 {
55  vp_cursor_t cursor, src_cursor;
56  vp_tmpl_t src;
57  VALUE_PAIR *vp, *head = NULL;
58  int decoded = 0;
59  ssize_t slen;
60 
61  while (isspace((int) *fmt)) fmt++;
62 
63  slen = tmpl_from_attr_str(&src, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
64  if (slen <= 0) {
65  REMARKER(fmt, slen, fr_strerror());
66  error:
67  return -1;
68  }
69 
70  if (src.type != TMPL_TYPE_ATTR) {
71  REDEBUG("dhcp_options cannot operate on a %s", fr_int2str(tmpl_names, src.type, "<INVALID>"));
72  goto error;
73  }
74 
75  if (src.tmpl_da->type != PW_TYPE_OCTETS) {
76  REDEBUG("dhcp_options got a %s attribute needed octets",
77  fr_int2str(dict_attr_types, src.tmpl_da->type, "<INVALID>"));
78  goto error;
79  }
80 
81  fr_cursor_init(&cursor, &head);
82 
83  for (vp = tmpl_cursor_init(NULL, &src_cursor, request, &src);
84  vp;
85  vp = tmpl_cursor_next(&src_cursor, &src)) {
86  uint8_t const *p = vp->vp_octets, *end = p + vp->vp_length;
87  size_t len;
88  VALUE_PAIR *vps = NULL;
89  vp_cursor_t options_cursor;
90 
91  fr_cursor_init(&options_cursor, &vps);
92  /*
93  * Loop over all the options data
94  */
95  while (p < end) {
96  len = fr_dhcp_decode_option(request->packet, &options_cursor,
97  fr_dict_root(fr_dict_internal), p, end - p, NULL);
98  if (len <= 0) {
99  RWDEBUG("DHCP option decoding failed: %s", fr_strerror());
100  fr_pair_list_free(&head);
101  goto error;
102  }
103  p += len;
104  }
105  fr_cursor_merge(&cursor, vps);
106  }
107 
108  for (vp = fr_cursor_first(&cursor);
109  vp;
110  vp = fr_cursor_next(&cursor)) {
111  rdebug_pair(L_DBG_LVL_2, request, vp, "dhcp_options: ");
112  decoded++;
113  }
114 
115  fr_pair_list_move(request->packet, &(request->packet->vps), &head);
116 
117  /* Free any unmoved pairs */
118  fr_pair_list_free(&head);
119 
120  snprintf(*out, outlen, "%i", decoded);
121 
122  return strlen(*out);
123 }
124 
125 static ssize_t dhcp_xlat(char **out, size_t outlen,
126  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
127  REQUEST *request, char const *fmt)
128 {
129  vp_cursor_t cursor;
130  VALUE_PAIR *vp;
131  uint8_t binbuf[255];
132  ssize_t len;
133 
134  while (isspace((int) *fmt)) fmt++;
135 
136  if ((radius_copy_vp(request, &vp, request, fmt) < 0) || !vp) return 0;
137  fr_cursor_init(&cursor, &vp);
138 
139  len = fr_dhcp_encode_option(binbuf, sizeof(binbuf), &cursor, NULL);
140  talloc_free(vp);
141  if (len <= 0) {
142  REDEBUG("DHCP option encoding failed: %s", fr_strerror());
143 
144  return -1;
145  }
146 
147  if ((size_t)((len * 2) + 1) > outlen) {
148  REDEBUG("DHCP option encoding failed: Output buffer exhausted, needed %zd bytes, have %zd bytes",
149  (len * 2) + 1, outlen);
150 
151  return -1;
152  }
153 
154  return fr_bin2hex(*out, binbuf, len);
155 }
156 
157 
158 /*
159  * Instantiate the module.
160  */
161 static int mod_bootstrap(UNUSED CONF_SECTION *conf, void *instance)
162 {
163  rlm_dhcp_t *inst = instance;
164  fr_dict_attr_t const *da;
165 
166  xlat_register(inst, "dhcp_options", dhcp_options_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
167  xlat_register(inst, "dhcp", dhcp_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
168 
169  /*
170  * Fixup dictionary entry for DHCP-Paramter-Request-List adding all the options
171  */
173  if (da) {
174  fr_dict_attr_t const *value;
175  int i;
176 
177  /* No padding or termination options */
178  DEBUG3("Adding values for %s", da->name);
179  for (i = 1; i < 255; i++) {
180  value = fr_dict_attr_by_num(NULL, DHCP_MAGIC_VENDOR, i);
181  if (!value) {
182  DEBUG3("No DHCP RFC space attribute at %i", i);
183  continue;
184  }
185 
186  DEBUG3("Adding %s value %i %s", da->name, i, value->name);
187  if (fr_dict_enum_add(NULL, da->name, value->name, i) < 0) {
188  DEBUG3("Failed adding value: %s", fr_strerror());
189  }
190  }
191  }
192 
193  return 0;
194 }
195 
196 
197 /*
198  * The module name should be the only globally exported symbol.
199  * That is, everything else should be 'static'.
200  *
201  * If the module needs to temporarily modify it's instantiation
202  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
203  * The server will then take care of ensuring that the module
204  * is single-threaded.
205  */
206 extern module_t rlm_dhcp;
207 module_t rlm_dhcp = {
209  .name = "dhcp",
210  .inst_size = sizeof(rlm_dhcp_t),
211  .bootstrap = mod_bootstrap,
212 };
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
static ssize_t dhcp_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_dhcp.c:125
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
VALUE_PAIR * fr_cursor_first(vp_cursor_t *cursor)
Rewind cursor to the start of the list.
Definition: cursor.c:105
#define DEBUG3(fmt,...)
Definition: log.h:177
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
void rdebug_pair(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a single valuepair to stderr or error log.
Definition: pair.c:739
Metadata exported by the module.
Definition: modules.h:134
Dictionary attribute.
Definition: dict.h:77
Dictionary attribute.
Definition: tmpl.h:133
int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
Copy VP(s) from the specified request.
Definition: pair.c:842
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
Definition: log.h:306
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx)
ssize_t fr_dhcp_decode_option(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t len, void *decoder_ctx)
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
#define inst
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
VALUE_PAIR * tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
Initialise a vp_cursor_t to the VALUE_PAIR specified by a vp_tmpl_t.
Definition: tmpl.c:1990
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
Definition: cursor.c:394
ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:877
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
int fr_dict_enum_add(fr_dict_t *dict, char const *attr, char const *alias, int value)
Definition: dict.c:1153
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
static ssize_t dhcp_options_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_dhcp.c:51
The current request.
Definition: tmpl.h:113
tmpl_type_t type
What type of value tmpl refers to.
Definition: tmpl.h:188
static rs_t * conf
Definition: radsniff.c:46
#define PW_DHCP_PARAMETER_REQUEST_LIST
Definition: rlm_dhcp.c:34
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
int nothing
Definition: rlm_dhcp.c:44
module_t rlm_dhcp
Definition: rlm_dhcp.c:207
void fr_pair_list_move(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from)
Move pairs from source list to destination list respecting operator.
Definition: pair.c:1508
char name[1]
Attribute name.
Definition: dict.h:89
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define REDEBUG(fmt,...)
Definition: log.h:254
#define DHCP_MAGIC_VENDOR
Definition: dhcp.h:97
static int mod_bootstrap(UNUSED CONF_SECTION *conf, void *instance)
Definition: rlm_dhcp.c:161
struct rlm_dhcp_t rlm_dhcp_t
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
#define RWDEBUG(fmt,...)
Definition: log.h:251
VALUE_PAIR * tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
Returns the next VALUE_PAIR specified by vpt.
Definition: tmpl.c:2128
#define RCSID(id)
Definition: build.h:135
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
A source or sink of value data.
Definition: tmpl.h:187
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
const FR_NAME_NUMBER tmpl_names[]
Map tmpl_type_t values to descriptive strings.
Definition: tmpl.c:36
Raw octets.
Definition: radius.h:38