The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_idn.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: 2a81a4fb3bcc34c3f7b450aa3f06a2628d63fd3f $
19  * @file rlm_idn.c
20  * @brief Internationalized Domain Name encoding for DNS aka IDNA aka RFC3490
21  *
22  * @copyright 2013 Brian S. Julin (bjulin@clarku.edu)
23  */
24 RCSID("$Id: 2a81a4fb3bcc34c3f7b450aa3f06a2628d63fd3f $")
25 
26 #include <freeradius-devel/server/base.h>
27 #include <freeradius-devel/server/module_rlm.h>
28 #include <freeradius-devel/unlang/xlat_func.h>
29 
30 #include <idna.h>
31 
32 /*
33  * Structure for module configuration
34  */
35 typedef struct {
38 } rlm_idn_t;
39 
40 /*
41  * The primary use case for this module is DNS-safe encoding of realms
42  * appearing in requests for a DDDS scheme. Some notes on that usage
43  * scenario:
44  *
45  * RFC2865 5.1 User-Name may be one of:
46  *
47  * 1) UTF-8 text: in which case this conversion is needed
48  *
49  * 2) realm part of an NAI: in which case this conversion should do nothing
50  * since only ASCII digits, ASCII alphas, ASCII dots, and ASCII hyphens
51  * are allowed.
52  *
53  * 3) "A name in ASN.1 form used in Public Key authentication systems.":
54  * I count four things in that phrase that are rather ... vague.
55  * However, most X.509 docs yell at you to IDNA internationalized
56  * domain names to IA5String, so if it is coming from inside an X.509
57  * certificate IDNA should be idempotent in the encode direction.
58  *
59  * Except for that last loophole, which we will leave up to the user
60  * to sort out, we should be safe in processing the realm as UTF-8.
61  */
62 
63 
64 /*
65  * A mapping of configuration file names to internal variables.
66  */
67 static const conf_parser_t mod_config[] = {
68  /*
69  * If a STRINGPREP profile other than NAMEPREP is ever desired,
70  * we can implement an option, and it will default to NAMEPREP settings.
71  * ...and if we want raw punycode or to tweak Bootstring parameters,
72  * we can do similar things. All defaults should result in IDNA
73  * ToASCII with the use_std3_ascii_rules flag set, allow_unassigned unset,
74  * because that is the foreseeable use case.
75  *
76  * Note that doing anything much different will require choosing the
77  * appropriate libidn API functions, as we currently call the IDNA
78  * convenience functions.
79  *
80  * Also note that right now we do not provide ToUnicode, which may or
81  * may not be useful as an xlat... depends on how the results need to
82  * be used.
83  */
84 
85  { FR_CONF_OFFSET("allow_unassigned", rlm_idn_t, allow_unassigned), .dflt = "no" },
86  { FR_CONF_OFFSET("use_std3_ascii_rules", rlm_idn_t, use_std3_ascii_rules), .dflt = "yes" },
88 };
89 
90 static xlat_arg_parser_t const xlat_idna_arg[] = {
91  { .required = true, .concat = true, .type = FR_TYPE_STRING },
93 };
94 
95 /** Convert domain name to ASCII punycode
96  *
97 @verbatim
98 %idn(<domain>)
99 @endverbatim
100  *
101  * @ingroup xlat_functions
102  */
103 static xlat_action_t xlat_idna(TALLOC_CTX *ctx, fr_dcursor_t *out,
104  xlat_ctx_t const *xctx,
105  request_t *request, fr_value_box_list_t *in)
106 {
107  rlm_idn_t const *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_idn_t);
108  char *idna = NULL;
109  int res;
110  size_t len;
111  int flags = 0;
112  fr_value_box_t *arg = fr_value_box_list_head(in);
113  fr_value_box_t *vb;
114 
115  if (inst->use_std3_ascii_rules) {
116  flags |= IDNA_USE_STD3_ASCII_RULES;
117  }
118  if (inst->allow_unassigned) {
119  flags |= IDNA_ALLOW_UNASSIGNED;
120  }
121 
122  res = idna_to_ascii_8z(arg->vb_strvalue, &idna, flags);
123  if (res) {
124  if (idna) {
125  free (idna); /* Docs unclear, be safe. */
126  }
127 
128  REDEBUG("%s", idna_strerror(res));
129  return XLAT_ACTION_FAIL;
130  }
131 
132  len = strlen(idna);
133 
134  /* 253 is max DNS length */
135  if (len > 253) {
136  /* Never provide a truncated result, as it may be queried. */
137  REDEBUG("Conversion was truncated");
138 
139  free(idna);
140  return XLAT_ACTION_FAIL;
141  }
142 
143  MEM(vb = fr_value_box_alloc_null(ctx));
144  MEM(fr_value_box_strdup(ctx, vb, NULL, idna, false) >= 0);
145  fr_dcursor_append(out, vb);
146  free(idna);
147 
148  return XLAT_ACTION_DONE;
149 }
150 
151 static int mod_bootstrap(module_inst_ctx_t const *mctx)
152 {
153  xlat_t *xlat;
154 
155  xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, NULL, xlat_idna, FR_TYPE_STRING);
158 
159  return 0;
160 }
161 
162 extern module_rlm_t rlm_idn;
164  .common = {
165  .magic = MODULE_MAGIC_INIT,
166  .name = "idn",
167  .inst_size = sizeof(rlm_idn_t),
168  .config = mod_config,
169  .bootstrap = mod_bootstrap
170  }
171 };
#define RCSID(id)
Definition: build.h:481
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:406
static fr_slen_t in
Definition: dict.h:821
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
static xlat_action_t xlat_idna(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Convert domain name to ASCII punycode.
Definition: rlm_idn.c:103
free(array)
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition: module_rlm.c:257
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
static const conf_parser_t config[]
Definition: base.c:183
#define REDEBUG(fmt,...)
Definition: radclient.h:52
bool use_std3_ascii_rules
Definition: rlm_idn.c:36
module_rlm_t rlm_idn
Definition: rlm_idn.c:163
static xlat_arg_parser_t const xlat_idna_arg[]
Definition: rlm_idn.c:90
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: rlm_idn.c:151
bool allow_unassigned
Definition: rlm_idn.c:37
static const conf_parser_t mod_config[]
Definition: rlm_idn.c:67
void * data
Module's instance data.
Definition: module.h:271
void * boot
Data allocated during the boostrap phase.
Definition: module.h:274
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
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
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition: value.c:3927
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:632
static size_t char ** out
Definition: value.h:997
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition: xlat_ctx.h:52
An xlat calling ctx.
Definition: xlat_ctx.h:49
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:402
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:365
@ XLAT_FUNC_FLAG_PURE
Definition: xlat_func.h:38