All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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: 9d65b517a4875a8fb3d9c34804cabdc0ebc476e5 $
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: 9d65b517a4875a8fb3d9c34804cabdc0ebc476e5 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 
29 #include <idna.h>
30 
31 /*
32  * Structure for module configuration
33  */
34 typedef struct rlm_idn_t {
35  char const *xlat_name;
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 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 forseeable 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", PW_TYPE_BOOLEAN, rlm_idn_t, allow_unassigned), .dflt = "no" },
86  { FR_CONF_OFFSET("use_std3_ascii_rules", PW_TYPE_BOOLEAN, rlm_idn_t, use_std3_ascii_rules), .dflt = "yes" },
88 };
89 
90 static ssize_t xlat_idna(char **out, size_t outlen,
91  void const *mod_inst, UNUSED void const *xlat_inst,
92  REQUEST *request, char const *fmt)
93 {
94  rlm_idn_t const *inst = mod_inst;
95  char *idna = NULL;
96  int res;
97  size_t len;
98  int flags = 0;
99 
100  if (inst->use_std3_ascii_rules) {
101  flags |= IDNA_USE_STD3_ASCII_RULES;
102  }
103  if (inst->allow_unassigned) {
104  flags |= IDNA_ALLOW_UNASSIGNED;
105  }
106 
107  res = idna_to_ascii_8z(fmt, &idna, flags);
108  if (res) {
109  if (idna) {
110  free (idna); /* Docs unclear, be safe. */
111  }
112 
113  REDEBUG("%s", idna_strerror(res));
114  return -1;
115  }
116 
117  len = strlen(idna);
118 
119  /* 253 is max DNS length */
120  if (!((len < (outlen - 1)) && (len <= 253))) {
121  /* Never provide a truncated result, as it may be queried. */
122  REDEBUG("Conversion was truncated");
123 
124  free(idna);
125  return -1;
126 
127  }
128 
129  strlcpy(*out, idna, outlen);
130  free(idna);
131 
132  return len;
133 }
134 
135 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
136 {
137  rlm_idn_t *inst = instance;
138  char const *xlat_name;
139 
140  xlat_name = cf_section_name2(conf);
141  if (!xlat_name) {
142  xlat_name = cf_section_name1(conf);
143  }
144 
145  inst->xlat_name = xlat_name;
146 
147  xlat_register(inst, inst->xlat_name, xlat_idna, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
148 
149  return 0;
150 }
151 
152 extern module_t rlm_idn;
153 module_t rlm_idn = {
155  .name = "idn",
156  .type = RLM_TYPE_THREAD_SAFE,
157  .inst_size = sizeof(rlm_idn_t),
158  .config = mod_config,
159  .bootstrap = mod_bootstrap
160 };
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
Metadata exported by the module.
Definition: modules.h:134
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
static const CONF_PARSER mod_config[]
Definition: rlm_idn.c:67
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
#define inst
struct rlm_idn_t rlm_idn_t
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
module_t rlm_idn
Definition: rlm_idn.c:153
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
char const * xlat_name
Definition: rlm_idn.c:35
A truth value.
Definition: radius.h:56
bool allow_unassigned
Definition: rlm_idn.c:37
static rs_t * conf
Definition: radsniff.c:46
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
#define REDEBUG(fmt,...)
Definition: log.h:254
bool use_std3_ascii_rules
Definition: rlm_idn.c:36
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
static ssize_t xlat_idna(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_idn.c:90
#define RCSID(id)
Definition: build.h:135
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Definition: rlm_idn.c:135
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601