Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dns_query.c
Go to the documentation of this file.
1 /* Upcall routine, designed to work as a key type and working through
2  * /sbin/request-key to contact userspace when handling DNS queries.
3  *
4  * See Documentation/networking/dns_resolver.txt
5  *
6  * Copyright (c) 2007 Igor Mammedov
7  * Author(s): Igor Mammedov ([email protected])
8  * Steve French ([email protected])
9  * Wang Lei ([email protected])
10  * David Howells ([email protected])
11  *
12  * The upcall wrapper used to make an arbitrary DNS query.
13  *
14  * This function requires the appropriate userspace tool dns.upcall to be
15  * installed and something like the following lines should be added to the
16  * /etc/request-key.conf file:
17  *
18  * create dns_resolver * * /sbin/dns.upcall %k
19  *
20  * For example to use this module to query AFSDB RR:
21  *
22  * create dns_resolver afsdb:* * /sbin/dns.afsdb %k
23  *
24  * This library is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU Lesser General Public License as published
26  * by the Free Software Foundation; either version 2.1 of the License, or
27  * (at your option) any later version.
28  *
29  * This library is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
32  * the GNU Lesser General Public License for more details.
33  *
34  * You should have received a copy of the GNU Lesser General Public License
35  * along with this library; if not, write to the Free Software
36  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37  */
38 
39 #include <linux/module.h>
40 #include <linux/slab.h>
41 #include <linux/dns_resolver.h>
42 #include <linux/err.h>
43 #include <keys/dns_resolver-type.h>
44 #include <keys/user-type.h>
45 
46 #include "internal.h"
47 
70 int dns_query(const char *type, const char *name, size_t namelen,
71  const char *options, char **_result, time_t *_expiry)
72 {
73  struct key *rkey;
74  struct user_key_payload *upayload;
75  const struct cred *saved_cred;
76  size_t typelen, desclen;
77  char *desc, *cp;
78  int ret, len;
79 
80  kenter("%s,%*.*s,%zu,%s",
81  type, (int)namelen, (int)namelen, name, namelen, options);
82 
83  if (!name || namelen == 0 || !_result)
84  return -EINVAL;
85 
86  /* construct the query key description as "[<type>:]<name>" */
87  typelen = 0;
88  desclen = 0;
89  if (type) {
90  typelen = strlen(type);
91  if (typelen < 1)
92  return -EINVAL;
93  desclen += typelen + 1;
94  }
95 
96  if (!namelen)
97  namelen = strlen(name);
98  if (namelen < 3)
99  return -EINVAL;
100  desclen += namelen + 1;
101 
102  desc = kmalloc(desclen, GFP_KERNEL);
103  if (!desc)
104  return -ENOMEM;
105 
106  cp = desc;
107  if (type) {
108  memcpy(cp, type, typelen);
109  cp += typelen;
110  *cp++ = ':';
111  }
112  memcpy(cp, name, namelen);
113  cp += namelen;
114  *cp = '\0';
115 
116  if (!options)
117  options = "";
118  kdebug("call request_key(,%s,%s)", desc, options);
119 
120  /* make the upcall, using special credentials to prevent the use of
121  * add_key() to preinstall malicious redirections
122  */
123  saved_cred = override_creds(dns_resolver_cache);
124  rkey = request_key(&key_type_dns_resolver, desc, options);
125  revert_creds(saved_cred);
126  kfree(desc);
127  if (IS_ERR(rkey)) {
128  ret = PTR_ERR(rkey);
129  goto out;
130  }
131 
132  down_read(&rkey->sem);
133  rkey->perm |= KEY_USR_VIEW;
134 
135  ret = key_validate(rkey);
136  if (ret < 0)
137  goto put;
138 
139  /* If the DNS server gave an error, return that to the caller */
140  ret = rkey->type_data.x[0];
141  if (ret)
142  goto put;
143 
144  upayload = rcu_dereference_protected(rkey->payload.data,
145  lockdep_is_held(&rkey->sem));
146  len = upayload->datalen;
147 
148  ret = -ENOMEM;
149  *_result = kmalloc(len + 1, GFP_KERNEL);
150  if (!*_result)
151  goto put;
152 
153  memcpy(*_result, upayload->data, len + 1);
154  if (_expiry)
155  *_expiry = rkey->expiry;
156 
157  ret = len;
158 put:
159  up_read(&rkey->sem);
160  key_put(rkey);
161 out:
162  kleave(" = %d", ret);
163  return ret;
164 }