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.
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.
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
20 * @brief Internationalized Domain Name encoding for DNS aka IDNA aka RFC3490
22 * @copyright 2013 Brian S. Julin <bjulin@clarku.edu>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
32 * Structure for module configuration
34 typedef struct rlm_idn_t {
35 char const *xlat_name;
36 bool use_std3_ascii_rules;
37 bool allow_unassigned;
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
45 * RFC2865 5.1 User-Name may be one of:
47 * 1) UTF-8 text: in which case this conversion is needed
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
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.
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.
65 * A mapping of configuration file names to internal variables.
67 static const CONF_PARSER mod_config[] = {
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.
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.
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
85 { "allow_unassigned", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, allow_unassigned), "no" },
86 { "use_std3_ascii_rules", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, use_std3_ascii_rules), "yes" },
88 { NULL, -1, 0, NULL, NULL }
91 static ssize_t xlat_idna(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
93 rlm_idn_t *inst = instance;
99 if (inst->use_std3_ascii_rules) {
100 flags |= IDNA_USE_STD3_ASCII_RULES;
102 if (inst->allow_unassigned) {
103 flags |= IDNA_ALLOW_UNASSIGNED;
106 res = idna_to_ascii_8z(fmt, &idna, flags);
109 free (idna); /* Docs unclear, be safe. */
112 REDEBUG("%s", idna_strerror(res));
118 /* 253 is max DNS length */
119 if (!((len < (freespace - 1)) && (len <= 253))) {
120 /* Never provide a truncated result, as it may be queried. */
121 REDEBUG("Conversion was truncated");
128 strlcpy(out, idna, freespace);
134 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
136 rlm_idn_t *inst = instance;
137 char const *xlat_name;
139 xlat_name = cf_section_name2(conf);
141 xlat_name = cf_section_name1(conf);
144 inst->xlat_name = xlat_name;
146 xlat_register(inst->xlat_name, xlat_idna, NULL, inst);
151 extern module_t rlm_idn;
153 .magic = RLM_MODULE_INIT,
155 .type = RLM_TYPE_THREAD_SAFE,
156 .inst_size = sizeof(rlm_idn_t),
157 .config = mod_config,
158 .bootstrap = mod_bootstrap