1 /* Key type used to cache DNS lookups made by the kernel 2 * 3 * See Documentation/networking/dns_resolver.txt 4 * 5 * Copyright (c) 2007 Igor Mammedov 6 * Author(s): Igor Mammedov (niallain@gmail.com) 7 * Steve French (sfrench@us.ibm.com) 8 * Wang Lei (wang840925@gmail.com) 9 * David Howells (dhowells@redhat.com) 10 * 11 * This library is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License as published 13 * by the Free Software Foundation; either version 2.1 of the License, or 14 * (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 19 * the GNU Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * along with this library; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 */ 25 #include <linux/module.h> 26 #include <linux/moduleparam.h> 27 #include <linux/slab.h> 28 #include <linux/string.h> 29 #include <linux/kernel.h> 30 #include <linux/keyctl.h> 31 #include <linux/err.h> 32 #include <keys/dns_resolver-type.h> 33 #include <keys/user-type.h> 34 #include "internal.h" 35 36 MODULE_DESCRIPTION("DNS Resolver"); 37 MODULE_AUTHOR("Wang Lei"); 38 MODULE_LICENSE("GPL"); 39 40 unsigned dns_resolver_debug; 41 module_param_named(debug, dns_resolver_debug, uint, S_IWUSR | S_IRUGO); 42 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); 43 44 const struct cred *dns_resolver_cache; 45 46 /* 47 * Instantiate a user defined key for dns_resolver. 48 * 49 * The data must be a NUL-terminated string, with the NUL char accounted in 50 * datalen. 51 * 52 * If the data contains a '#' characters, then we take the clause after each 53 * one to be an option of the form 'key=value'. The actual data of interest is 54 * the string leading up to the first '#'. For instance: 55 * 56 * "ip1,ip2,...#foo=bar" 57 */ 58 static int 59 dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) 60 { 61 struct user_key_payload *upayload; 62 int ret; 63 size_t result_len = 0; 64 const char *data = _data, *opt; 65 66 kenter("%%%d,%s,'%s',%zu", 67 key->serial, key->description, data, datalen); 68 69 if (datalen <= 1 || !data || data[datalen - 1] != '\0') 70 return -EINVAL; 71 datalen--; 72 73 /* deal with any options embedded in the data */ 74 opt = memchr(data, '#', datalen); 75 if (!opt) { 76 kdebug("no options currently supported"); 77 return -EINVAL; 78 } 79 80 result_len = datalen; 81 ret = key_payload_reserve(key, result_len); 82 if (ret < 0) 83 return -EINVAL; 84 85 upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); 86 if (!upayload) { 87 kleave(" = -ENOMEM"); 88 return -ENOMEM; 89 } 90 91 upayload->datalen = result_len; 92 memcpy(upayload->data, data, result_len); 93 upayload->data[result_len] = '\0'; 94 rcu_assign_pointer(key->payload.data, upayload); 95 96 kleave(" = 0"); 97 return 0; 98 } 99 100 /* 101 * The description is of the form "[<type>:]<domain_name>" 102 * 103 * The domain name may be a simple name or an absolute domain name (which 104 * should end with a period). The domain name is case-independent. 105 */ 106 static int 107 dns_resolver_match(const struct key *key, const void *description) 108 { 109 int slen, dlen, ret = 0; 110 const char *src = key->description, *dsp = description; 111 112 kenter("%s,%s", src, dsp); 113 114 if (!src || !dsp) 115 goto no_match; 116 117 if (strcasecmp(src, dsp) == 0) 118 goto matched; 119 120 slen = strlen(src); 121 dlen = strlen(dsp); 122 if (slen <= 0 || dlen <= 0) 123 goto no_match; 124 if (src[slen - 1] == '.') 125 slen--; 126 if (dsp[dlen - 1] == '.') 127 dlen--; 128 if (slen != dlen || strncasecmp(src, dsp, slen) != 0) 129 goto no_match; 130 131 matched: 132 ret = 1; 133 no_match: 134 kleave(" = %d", ret); 135 return ret; 136 } 137 138 struct key_type key_type_dns_resolver = { 139 .name = "dns_resolver", 140 .instantiate = dns_resolver_instantiate, 141 .match = dns_resolver_match, 142 .revoke = user_revoke, 143 .destroy = user_destroy, 144 .describe = user_describe, 145 .read = user_read, 146 }; 147 148 static int __init init_dns_resolver(void) 149 { 150 struct cred *cred; 151 struct key *keyring; 152 int ret; 153 154 printk(KERN_NOTICE "Registering the %s key type\n", 155 key_type_dns_resolver.name); 156 157 /* create an override credential set with a special thread keyring in 158 * which DNS requests are cached 159 * 160 * this is used to prevent malicious redirections from being installed 161 * with add_key(). 162 */ 163 cred = prepare_kernel_cred(NULL); 164 if (!cred) 165 return -ENOMEM; 166 167 keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred, 168 (KEY_POS_ALL & ~KEY_POS_SETATTR) | 169 KEY_USR_VIEW | KEY_USR_READ, 170 KEY_ALLOC_NOT_IN_QUOTA); 171 if (IS_ERR(keyring)) { 172 ret = PTR_ERR(keyring); 173 goto failed_put_cred; 174 } 175 176 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); 177 if (ret < 0) 178 goto failed_put_key; 179 180 ret = register_key_type(&key_type_dns_resolver); 181 if (ret < 0) 182 goto failed_put_key; 183 184 /* instruct request_key() to use this special keyring as a cache for 185 * the results it looks up */ 186 cred->thread_keyring = keyring; 187 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; 188 dns_resolver_cache = cred; 189 190 kdebug("DNS resolver keyring: %d\n", key_serial(keyring)); 191 return 0; 192 193 failed_put_key: 194 key_put(keyring); 195 failed_put_cred: 196 put_cred(cred); 197 return ret; 198 } 199 200 static void __exit exit_dns_resolver(void) 201 { 202 key_revoke(dns_resolver_cache->thread_keyring); 203 unregister_key_type(&key_type_dns_resolver); 204 put_cred(dns_resolver_cache); 205 printk(KERN_NOTICE "Unregistered %s key type\n", 206 key_type_dns_resolver.name); 207 } 208 209 module_init(init_dns_resolver) 210 module_exit(exit_dns_resolver) 211 MODULE_LICENSE("GPL"); 212