Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: [DNS RESOLVER] Minor typo correction DNS: Fixes for the DNS query module cifs: Include linux/err.h for IS_ERR and PTR_ERR DNS: Make AFS go to the DNS for AFSDB records for unknown cells DNS: Separate out CIFS DNS Resolver code cifs: account for new creduid=0x%x parameter in spnego upcall string cifs: reduce false positives with inode aliasing serverino autodisable CIFS: Make cifs_convert_address() take a const src pointer and a length cifs: show features compiled in as part of DebugData cifs: update README Fix up trivial conflicts in fs/cifs/cifsfs.c due to workqueue changes
This commit is contained in:
commit
1fc7995d19
|
@ -0,0 +1,146 @@
|
||||||
|
===================
|
||||||
|
DNS Resolver Module
|
||||||
|
===================
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
- Overview.
|
||||||
|
- Compilation.
|
||||||
|
- Setting up.
|
||||||
|
- Usage.
|
||||||
|
- Mechanism.
|
||||||
|
- Debugging.
|
||||||
|
|
||||||
|
|
||||||
|
========
|
||||||
|
OVERVIEW
|
||||||
|
========
|
||||||
|
|
||||||
|
The DNS resolver module provides a way for kernel services to make DNS queries
|
||||||
|
by way of requesting a key of key type dns_resolver. These queries are
|
||||||
|
upcalled to userspace through /sbin/request-key.
|
||||||
|
|
||||||
|
These routines must be supported by userspace tools dns.upcall, cifs.upcall and
|
||||||
|
request-key. It is under development and does not yet provide the full feature
|
||||||
|
set. The features it does support include:
|
||||||
|
|
||||||
|
(*) Implements the dns_resolver key_type to contact userspace.
|
||||||
|
|
||||||
|
It does not yet support the following AFS features:
|
||||||
|
|
||||||
|
(*) Dns query support for AFSDB resource record.
|
||||||
|
|
||||||
|
This code is extracted from the CIFS filesystem.
|
||||||
|
|
||||||
|
|
||||||
|
===========
|
||||||
|
COMPILATION
|
||||||
|
===========
|
||||||
|
|
||||||
|
The module should be enabled by turning on the kernel configuration options:
|
||||||
|
|
||||||
|
CONFIG_DNS_RESOLVER - tristate "DNS Resolver support"
|
||||||
|
|
||||||
|
|
||||||
|
==========
|
||||||
|
SETTING UP
|
||||||
|
==========
|
||||||
|
|
||||||
|
To set up this facility, the /etc/request-key.conf file must be altered so that
|
||||||
|
/sbin/request-key can appropriately direct the upcalls. For example, to handle
|
||||||
|
basic dname to IPv4/IPv6 address resolution, the following line should be
|
||||||
|
added:
|
||||||
|
|
||||||
|
#OP TYPE DESC CO-INFO PROGRAM ARG1 ARG2 ARG3 ...
|
||||||
|
#====== ============ ======= ======= ==========================
|
||||||
|
create dns_resolver * * /usr/sbin/cifs.upcall %k
|
||||||
|
|
||||||
|
To direct a query for query type 'foo', a line of the following should be added
|
||||||
|
before the more general line given above as the first match is the one taken.
|
||||||
|
|
||||||
|
create dns_resolver foo:* * /usr/sbin/dns.foo %k
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=====
|
||||||
|
USAGE
|
||||||
|
=====
|
||||||
|
|
||||||
|
To make use of this facility, one of the following functions that are
|
||||||
|
implemented in the module can be called after doing:
|
||||||
|
|
||||||
|
#include <linux/dns_resolver.h>
|
||||||
|
|
||||||
|
(1) int dns_query(const char *type, const char *name, size_t namelen,
|
||||||
|
const char *options, char **_result, time_t *_expiry);
|
||||||
|
|
||||||
|
This is the basic access function. It looks for a cached DNS query and if
|
||||||
|
it doesn't find it, it upcalls to userspace to make a new DNS query, which
|
||||||
|
may then be cached. The key description is constructed as a string of the
|
||||||
|
form:
|
||||||
|
|
||||||
|
[<type>:]<name>
|
||||||
|
|
||||||
|
where <type> optionally specifies the particular upcall program to invoke,
|
||||||
|
and thus the type of query to do, and <name> specifies the string to be
|
||||||
|
looked up. The default query type is a straight hostname to IP address
|
||||||
|
set lookup.
|
||||||
|
|
||||||
|
The name parameter is not required to be a NUL-terminated string, and its
|
||||||
|
length should be given by the namelen argument.
|
||||||
|
|
||||||
|
The options parameter may be NULL or it may be a set of options
|
||||||
|
appropriate to the query type.
|
||||||
|
|
||||||
|
The return value is a string appropriate to the query type. For instance,
|
||||||
|
for the default query type it is just a list of comma-separated IPv4 and
|
||||||
|
IPv6 addresses. The caller must free the result.
|
||||||
|
|
||||||
|
The length of the result string is returned on success, and a negative
|
||||||
|
error code is returned otherwise. -EKEYREJECTED will be returned if the
|
||||||
|
DNS lookup failed.
|
||||||
|
|
||||||
|
If _expiry is non-NULL, the expiry time (TTL) of the result will be
|
||||||
|
returned also.
|
||||||
|
|
||||||
|
|
||||||
|
=========
|
||||||
|
MECHANISM
|
||||||
|
=========
|
||||||
|
|
||||||
|
The dnsresolver module registers a key type called "dns_resolver". Keys of
|
||||||
|
this type are used to transport and cache DNS lookup results from userspace.
|
||||||
|
|
||||||
|
When dns_query() is invoked, it calls request_key() to search the local
|
||||||
|
keyrings for a cached DNS result. If that fails to find one, it upcalls to
|
||||||
|
userspace to get a new result.
|
||||||
|
|
||||||
|
Upcalls to userspace are made through the request_key() upcall vector, and are
|
||||||
|
directed by means of configuration lines in /etc/request-key.conf that tell
|
||||||
|
/sbin/request-key what program to run to instantiate the key.
|
||||||
|
|
||||||
|
The upcall handler program is responsible for querying the DNS, processing the
|
||||||
|
result into a form suitable for passing to the keyctl_instantiate_key()
|
||||||
|
routine. This then passes the data to dns_resolver_instantiate() which strips
|
||||||
|
off and processes any options included in the data, and then attaches the
|
||||||
|
remainder of the string to the key as its payload.
|
||||||
|
|
||||||
|
The upcall handler program should set the expiry time on the key to that of the
|
||||||
|
lowest TTL of all the records it has extracted a result from. This means that
|
||||||
|
the key will be discarded and recreated when the data it holds has expired.
|
||||||
|
|
||||||
|
dns_query() returns a copy of the value attached to the key, or an error if
|
||||||
|
that is indicated instead.
|
||||||
|
|
||||||
|
See <file:Documentation/keys-request-key.txt> for further information about
|
||||||
|
request-key function.
|
||||||
|
|
||||||
|
|
||||||
|
=========
|
||||||
|
DEBUGGING
|
||||||
|
=========
|
||||||
|
|
||||||
|
Debugging messages can be turned on dynamically by writing a 1 into the
|
||||||
|
following file:
|
||||||
|
|
||||||
|
/sys/module/dnsresolver/parameters/debug
|
|
@ -2,6 +2,7 @@ config AFS_FS
|
||||||
tristate "Andrew File System support (AFS) (EXPERIMENTAL)"
|
tristate "Andrew File System support (AFS) (EXPERIMENTAL)"
|
||||||
depends on INET && EXPERIMENTAL
|
depends on INET && EXPERIMENTAL
|
||||||
select AF_RXRPC
|
select AF_RXRPC
|
||||||
|
select DNS_RESOLVER
|
||||||
help
|
help
|
||||||
If you say Y here, you will get an experimental Andrew File System
|
If you say Y here, you will get an experimental Andrew File System
|
||||||
driver. It currently only supports unsecured read-only AFS access.
|
driver. It currently only supports unsecured read-only AFS access.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/key.h>
|
#include <linux/key.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/dns_resolver.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <keys/rxrpc-type.h>
|
#include <keys/rxrpc-type.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
@ -36,6 +37,8 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
|
||||||
struct key *key;
|
struct key *key;
|
||||||
size_t namelen;
|
size_t namelen;
|
||||||
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
|
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
|
||||||
|
char *dvllist = NULL, *_vllist = NULL;
|
||||||
|
char delimiter = ':';
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("%s,%s", name, vllist);
|
_enter("%s,%s", name, vllist);
|
||||||
|
@ -43,8 +46,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
|
||||||
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
|
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
|
||||||
|
|
||||||
namelen = strlen(name);
|
namelen = strlen(name);
|
||||||
if (namelen > AFS_MAXCELLNAME)
|
if (namelen > AFS_MAXCELLNAME) {
|
||||||
|
_leave(" = -ENAMETOOLONG");
|
||||||
return ERR_PTR(-ENAMETOOLONG);
|
return ERR_PTR(-ENAMETOOLONG);
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate and initialise a cell record */
|
/* allocate and initialise a cell record */
|
||||||
cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
|
cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
|
||||||
|
@ -64,15 +69,31 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
|
||||||
INIT_LIST_HEAD(&cell->vl_list);
|
INIT_LIST_HEAD(&cell->vl_list);
|
||||||
spin_lock_init(&cell->vl_lock);
|
spin_lock_init(&cell->vl_lock);
|
||||||
|
|
||||||
|
/* if the ip address is invalid, try dns query */
|
||||||
|
if (!vllist || strlen(vllist) < 7) {
|
||||||
|
ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
_leave(" = %d", ret);
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
_vllist = dvllist;
|
||||||
|
|
||||||
|
/* change the delimiter for user-space reply */
|
||||||
|
delimiter = ',';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_vllist = vllist;
|
||||||
|
}
|
||||||
|
|
||||||
/* fill in the VL server list from the rest of the string */
|
/* fill in the VL server list from the rest of the string */
|
||||||
do {
|
do {
|
||||||
unsigned a, b, c, d;
|
unsigned a, b, c, d;
|
||||||
|
|
||||||
next = strchr(vllist, ':');
|
next = strchr(_vllist, delimiter);
|
||||||
if (next)
|
if (next)
|
||||||
*next++ = 0;
|
*next++ = 0;
|
||||||
|
|
||||||
if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
|
if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
|
||||||
goto bad_address;
|
goto bad_address;
|
||||||
|
|
||||||
if (a > 255 || b > 255 || c > 255 || d > 255)
|
if (a > 255 || b > 255 || c > 255 || d > 255)
|
||||||
|
@ -81,7 +102,7 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
|
||||||
cell->vl_addrs[cell->vl_naddrs++].s_addr =
|
cell->vl_addrs[cell->vl_naddrs++].s_addr =
|
||||||
htonl((a << 24) | (b << 16) | (c << 8) | d);
|
htonl((a << 24) | (b << 16) | (c << 8) | d);
|
||||||
|
|
||||||
} while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
|
} while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
|
||||||
|
|
||||||
/* create a key to represent an anonymous user */
|
/* create a key to represent an anonymous user */
|
||||||
memcpy(keyname, "afs@", 4);
|
memcpy(keyname, "afs@", 4);
|
||||||
|
@ -110,6 +131,7 @@ bad_address:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
error:
|
error:
|
||||||
key_put(cell->anonymous_key);
|
key_put(cell->anonymous_key);
|
||||||
|
kfree(dvllist);
|
||||||
kfree(cell);
|
kfree(cell);
|
||||||
_leave(" = %d", ret);
|
_leave(" = %d", ret);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
@ -201,14 +223,12 @@ int afs_cell_init(char *rootcell)
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = strchr(rootcell, ':');
|
cp = strchr(rootcell, ':');
|
||||||
if (!cp) {
|
if (!cp)
|
||||||
printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
|
_debug("kAFS: no VL server IP addresses specified");
|
||||||
_leave(" = -EINVAL");
|
else
|
||||||
return -EINVAL;
|
*cp++ = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate a cell record for the root cell */
|
/* allocate a cell record for the root cell */
|
||||||
*cp++ = 0;
|
|
||||||
new_root = afs_cell_create(rootcell, cp);
|
new_root = afs_cell_create(rootcell, cp);
|
||||||
if (IS_ERR(new_root)) {
|
if (IS_ERR(new_root)) {
|
||||||
_leave(" = %ld", PTR_ERR(new_root));
|
_leave(" = %ld", PTR_ERR(new_root));
|
||||||
|
|
|
@ -70,14 +70,14 @@ config CIFS_WEAK_PW_HASH
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config CIFS_UPCALL
|
config CIFS_UPCALL
|
||||||
bool "Kerberos/SPNEGO advanced session setup"
|
bool "Kerberos/SPNEGO advanced session setup"
|
||||||
depends on CIFS && KEYS
|
depends on CIFS && KEYS
|
||||||
help
|
select DNS_RESOLVER
|
||||||
Enables an upcall mechanism for CIFS which accesses
|
help
|
||||||
userspace helper utilities to provide SPNEGO packaged (RFC 4178)
|
Enables an upcall mechanism for CIFS which accesses userspace helper
|
||||||
Kerberos tickets which are needed to mount to certain secure servers
|
utilities to provide SPNEGO packaged (RFC 4178) Kerberos tickets
|
||||||
(for which more secure Kerberos authentication is required). If
|
which are needed to mount to certain secure servers (for which more
|
||||||
unsure, say N.
|
secure Kerberos authentication is required). If unsure, say N.
|
||||||
|
|
||||||
config CIFS_XATTR
|
config CIFS_XATTR
|
||||||
bool "CIFS extended attributes"
|
bool "CIFS extended attributes"
|
||||||
|
@ -121,6 +121,7 @@ config CIFS_DEBUG2
|
||||||
config CIFS_DFS_UPCALL
|
config CIFS_DFS_UPCALL
|
||||||
bool "DFS feature support"
|
bool "DFS feature support"
|
||||||
depends on CIFS && KEYS
|
depends on CIFS && KEYS
|
||||||
|
select DNS_RESOLVER
|
||||||
help
|
help
|
||||||
Distributed File System (DFS) support is used to access shares
|
Distributed File System (DFS) support is used to access shares
|
||||||
transparently in an enterprise name space, even if the share
|
transparently in an enterprise name space, even if the share
|
||||||
|
|
|
@ -568,8 +568,9 @@ module can be displayed via modinfo.
|
||||||
Misc /proc/fs/cifs Flags and Debug Info
|
Misc /proc/fs/cifs Flags and Debug Info
|
||||||
=======================================
|
=======================================
|
||||||
Informational pseudo-files:
|
Informational pseudo-files:
|
||||||
DebugData Displays information about active CIFS sessions
|
DebugData Displays information about active CIFS sessions and
|
||||||
and shares, as well as the cifs.ko version.
|
shares, features enabled as well as the cifs.ko
|
||||||
|
version.
|
||||||
Stats Lists summary resource usage information as well as per
|
Stats Lists summary resource usage information as well as per
|
||||||
share statistics, if CONFIG_CIFS_STATS in enabled
|
share statistics, if CONFIG_CIFS_STATS in enabled
|
||||||
in the kernel configuration.
|
in the kernel configuration.
|
||||||
|
|
|
@ -119,6 +119,31 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||||
"Display Internal CIFS Data Structures for Debugging\n"
|
"Display Internal CIFS Data Structures for Debugging\n"
|
||||||
"---------------------------------------------------\n");
|
"---------------------------------------------------\n");
|
||||||
seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
|
seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
|
||||||
|
seq_printf(m, "Features: ");
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
seq_printf(m, "dfs");
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_FSCACHE
|
||||||
|
seq_printf(m, "fscache");
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||||
|
seq_printf(m, "lanman");
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_POSIX
|
||||||
|
seq_printf(m, "posix");
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
|
seq_printf(m, "spnego");
|
||||||
|
seq_putc(m, ' ');
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_XATTR
|
||||||
|
seq_printf(m, "xattr");
|
||||||
|
#endif
|
||||||
|
seq_putc(m, '\n');
|
||||||
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||||
seq_printf(m, "Servers:");
|
seq_printf(m, "Servers:");
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||||
if (rc != 0) {
|
if (rc < 0) {
|
||||||
cERROR(1, "%s: Failed to resolve server part of %s to IP: %d",
|
cERROR(1, "%s: Failed to resolve server part of %s to IP: %d",
|
||||||
__func__, *devname, rc);
|
__func__, *devname, rc);
|
||||||
goto compose_mount_options_err;
|
goto compose_mount_options_err;
|
||||||
|
@ -150,8 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
* assuming that we have 'unc=' and 'ip=' in
|
* assuming that we have 'unc=' and 'ip=' in
|
||||||
* the original sb_mountdata
|
* the original sb_mountdata
|
||||||
*/
|
*/
|
||||||
md_len = strlen(sb_mountdata) + strlen(srvIP) +
|
md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12;
|
||||||
strlen(ref->node_name) + 12;
|
|
||||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||||
if (mountdata == NULL) {
|
if (mountdata == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
|
|
@ -84,6 +84,9 @@ struct key_type cifs_spnego_key_type = {
|
||||||
/* strlen of ";uid=0x" */
|
/* strlen of ";uid=0x" */
|
||||||
#define UID_KEY_LEN 7
|
#define UID_KEY_LEN 7
|
||||||
|
|
||||||
|
/* strlen of ";creduid=0x" */
|
||||||
|
#define CREDUID_KEY_LEN 11
|
||||||
|
|
||||||
/* strlen of ";user=" */
|
/* strlen of ";user=" */
|
||||||
#define USER_KEY_LEN 6
|
#define USER_KEY_LEN 6
|
||||||
|
|
||||||
|
@ -107,6 +110,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||||
IP_KEY_LEN + INET6_ADDRSTRLEN +
|
IP_KEY_LEN + INET6_ADDRSTRLEN +
|
||||||
MAX_MECH_STR_LEN +
|
MAX_MECH_STR_LEN +
|
||||||
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||||
|
CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||||
USER_KEY_LEN + strlen(sesInfo->userName) +
|
USER_KEY_LEN + strlen(sesInfo->userName) +
|
||||||
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
#include "cifs_fs_sb.h"
|
#include "cifs_fs_sb.h"
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/key-type.h>
|
#include <linux/key-type.h>
|
||||||
#include "dns_resolve.h"
|
|
||||||
#include "cifs_spnego.h"
|
#include "cifs_spnego.h"
|
||||||
#include "fscache.h"
|
#include "fscache.h"
|
||||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||||
|
@ -934,22 +933,13 @@ init_cifs(void)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_unregister_filesystem;
|
goto out_unregister_filesystem;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
rc = cifs_init_dns_resolver();
|
|
||||||
if (rc)
|
|
||||||
goto out_unregister_key_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
out_unregister_key_type:
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
unregister_key_type(&cifs_spnego_key_type);
|
|
||||||
out_unregister_filesystem:
|
out_unregister_filesystem:
|
||||||
#endif
|
|
||||||
unregister_filesystem(&cifs_fs_type);
|
unregister_filesystem(&cifs_fs_type);
|
||||||
|
#endif
|
||||||
out_destroy_request_bufs:
|
out_destroy_request_bufs:
|
||||||
cifs_destroy_request_bufs();
|
cifs_destroy_request_bufs();
|
||||||
out_destroy_mids:
|
out_destroy_mids:
|
||||||
|
@ -971,7 +961,6 @@ exit_cifs(void)
|
||||||
cifs_fscache_unregister();
|
cifs_fscache_unregister();
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
cifs_dfs_release_automount_timer();
|
cifs_dfs_release_automount_timer();
|
||||||
cifs_exit_dns_resolver();
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
unregister_key_type(&cifs_spnego_key_type);
|
unregister_key_type(&cifs_spnego_key_type);
|
||||||
|
|
|
@ -86,8 +86,8 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
|
||||||
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
|
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
|
||||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||||
struct TCP_Server_Info *server);
|
struct TCP_Server_Info *server);
|
||||||
extern int cifs_convert_address(struct sockaddr *dst, char *src);
|
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||||
extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src,
|
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||||
unsigned short int port);
|
unsigned short int port);
|
||||||
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
|
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
|
||||||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||||
|
|
|
@ -1543,6 +1543,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||||
if (volume_info->UNCip && volume_info->UNC) {
|
if (volume_info->UNCip && volume_info->UNC) {
|
||||||
rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
|
rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
|
||||||
volume_info->UNCip,
|
volume_info->UNCip,
|
||||||
|
strlen(volume_info->UNCip),
|
||||||
volume_info->port);
|
volume_info->port);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
/* we failed translating address */
|
/* we failed translating address */
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
* Copyright (c) 2007 Igor Mammedov
|
* Copyright (c) 2007 Igor Mammedov
|
||||||
* Author(s): Igor Mammedov (niallain@gmail.com)
|
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||||
* Steve French (sfrench@us.ibm.com)
|
* Steve French (sfrench@us.ibm.com)
|
||||||
|
* Wang Lei (wang840925@gmail.com)
|
||||||
|
* David Howells (dhowells@redhat.com)
|
||||||
*
|
*
|
||||||
* Contains the CIFS DFS upcall routines used for hostname to
|
* Contains the CIFS DFS upcall routines used for hostname to
|
||||||
* IP address translation.
|
* IP address translation.
|
||||||
|
@ -24,214 +26,73 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/keyctl.h>
|
#include <linux/dns_resolver.h>
|
||||||
#include <linux/key-type.h>
|
|
||||||
#include <keys/user-type.h>
|
|
||||||
#include "dns_resolve.h"
|
#include "dns_resolve.h"
|
||||||
#include "cifsglob.h"
|
#include "cifsglob.h"
|
||||||
#include "cifsproto.h"
|
#include "cifsproto.h"
|
||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
|
|
||||||
static const struct cred *dns_resolver_cache;
|
/**
|
||||||
|
* dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
|
||||||
/* Checks if supplied name is IP address
|
* @unc: UNC path specifying the server
|
||||||
* returns:
|
* @ip_addr: Where to return the IP address.
|
||||||
* 1 - name is IP
|
*
|
||||||
* 0 - name is not IP
|
* The IP address will be returned in string form, and the caller is
|
||||||
*/
|
* responsible for freeing it.
|
||||||
static int
|
*
|
||||||
is_ip(char *name)
|
* Returns length of result on success, -ve on error.
|
||||||
{
|
|
||||||
struct sockaddr_storage ss;
|
|
||||||
|
|
||||||
return cifs_convert_address((struct sockaddr *)&ss, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
dns_resolver_instantiate(struct key *key, const void *data,
|
|
||||||
size_t datalen)
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
char *ip;
|
|
||||||
|
|
||||||
ip = kmalloc(datalen + 1, GFP_KERNEL);
|
|
||||||
if (!ip)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
memcpy(ip, data, datalen);
|
|
||||||
ip[datalen] = '\0';
|
|
||||||
|
|
||||||
/* make sure this looks like an address */
|
|
||||||
if (!is_ip(ip)) {
|
|
||||||
kfree(ip);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
key->type_data.x[0] = datalen;
|
|
||||||
key->payload.data = ip;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dns_resolver_destroy(struct key *key)
|
|
||||||
{
|
|
||||||
kfree(key->payload.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct key_type key_type_dns_resolver = {
|
|
||||||
.name = "dns_resolver",
|
|
||||||
.def_datalen = sizeof(struct in_addr),
|
|
||||||
.describe = user_describe,
|
|
||||||
.instantiate = dns_resolver_instantiate,
|
|
||||||
.destroy = dns_resolver_destroy,
|
|
||||||
.match = user_match,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Resolves server name to ip address.
|
|
||||||
* input:
|
|
||||||
* unc - server UNC
|
|
||||||
* output:
|
|
||||||
* *ip_addr - pointer to server ip, caller responcible for freeing it.
|
|
||||||
* return 0 on success
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
||||||
{
|
{
|
||||||
const struct cred *saved_cred;
|
struct sockaddr_storage ss;
|
||||||
int rc = -EAGAIN;
|
const char *hostname, *sep;
|
||||||
struct key *rkey = ERR_PTR(-EAGAIN);
|
|
||||||
char *name;
|
char *name;
|
||||||
char *data = NULL;
|
int len, rc;
|
||||||
int len;
|
|
||||||
|
|
||||||
if (!ip_addr || !unc)
|
if (!ip_addr || !unc)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* search for server name delimiter */
|
|
||||||
len = strlen(unc);
|
len = strlen(unc);
|
||||||
if (len < 3) {
|
if (len < 3) {
|
||||||
cFYI(1, "%s: unc is too short: %s", __func__, unc);
|
cFYI(1, "%s: unc is too short: %s", __func__, unc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Discount leading slashes for cifs */
|
||||||
len -= 2;
|
len -= 2;
|
||||||
name = memchr(unc+2, '\\', len);
|
hostname = unc + 2;
|
||||||
if (!name) {
|
|
||||||
|
/* Search for server name delimiter */
|
||||||
|
sep = memchr(hostname, '\\', len);
|
||||||
|
if (sep)
|
||||||
|
len = sep - unc;
|
||||||
|
else
|
||||||
cFYI(1, "%s: probably server name is whole unc: %s",
|
cFYI(1, "%s: probably server name is whole unc: %s",
|
||||||
__func__, unc);
|
__func__, unc);
|
||||||
} else {
|
|
||||||
len = (name - unc) - 2/* leading // */;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = kmalloc(len+1, GFP_KERNEL);
|
/* Try to interpret hostname as an IPv4 or IPv6 address */
|
||||||
if (!name) {
|
rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
|
||||||
rc = -ENOMEM;
|
if (rc > 0)
|
||||||
return rc;
|
goto name_is_IP_address;
|
||||||
}
|
|
||||||
memcpy(name, unc+2, len);
|
|
||||||
name[len] = 0;
|
|
||||||
|
|
||||||
if (is_ip(name)) {
|
/* Perform the upcall */
|
||||||
cFYI(1, "%s: it is IP, skipping dns upcall: %s",
|
rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL);
|
||||||
__func__, name);
|
if (rc < 0)
|
||||||
data = name;
|
cERROR(1, "%s: unable to resolve: %*.*s",
|
||||||
goto skip_upcall;
|
__func__, len, len, hostname);
|
||||||
}
|
else
|
||||||
|
cFYI(1, "%s: resolved: %*.*s to %s",
|
||||||
saved_cred = override_creds(dns_resolver_cache);
|
__func__, len, len, hostname, *ip_addr);
|
||||||
rkey = request_key(&key_type_dns_resolver, name, "");
|
|
||||||
revert_creds(saved_cred);
|
|
||||||
if (!IS_ERR(rkey)) {
|
|
||||||
if (!(rkey->perm & KEY_USR_VIEW)) {
|
|
||||||
down_read(&rkey->sem);
|
|
||||||
rkey->perm |= KEY_USR_VIEW;
|
|
||||||
up_read(&rkey->sem);
|
|
||||||
}
|
|
||||||
len = rkey->type_data.x[0];
|
|
||||||
data = rkey->payload.data;
|
|
||||||
} else {
|
|
||||||
cERROR(1, "%s: unable to resolve: %s", __func__, name);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_upcall:
|
|
||||||
if (data) {
|
|
||||||
*ip_addr = kmalloc(len + 1, GFP_KERNEL);
|
|
||||||
if (*ip_addr) {
|
|
||||||
memcpy(*ip_addr, data, len + 1);
|
|
||||||
if (!IS_ERR(rkey))
|
|
||||||
cFYI(1, "%s: resolved: %s to %s", __func__,
|
|
||||||
name,
|
|
||||||
*ip_addr
|
|
||||||
);
|
|
||||||
rc = 0;
|
|
||||||
} else {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
}
|
|
||||||
if (!IS_ERR(rkey))
|
|
||||||
key_put(rkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(name);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
|
||||||
|
|
||||||
int __init cifs_init_dns_resolver(void)
|
name_is_IP_address:
|
||||||
{
|
name = kmalloc(len + 1, GFP_KERNEL);
|
||||||
struct cred *cred;
|
if (!name)
|
||||||
struct key *keyring;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
printk(KERN_NOTICE "Registering the %s key type\n",
|
|
||||||
key_type_dns_resolver.name);
|
|
||||||
|
|
||||||
/* create an override credential set with a special thread keyring in
|
|
||||||
* which DNS requests are cached
|
|
||||||
*
|
|
||||||
* this is used to prevent malicious redirections from being installed
|
|
||||||
* with add_key().
|
|
||||||
*/
|
|
||||||
cred = prepare_kernel_cred(NULL);
|
|
||||||
if (!cred)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
memcpy(name, hostname, len);
|
||||||
keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
|
name[len] = 0;
|
||||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name);
|
||||||
KEY_USR_VIEW | KEY_USR_READ,
|
*ip_addr = name;
|
||||||
KEY_ALLOC_NOT_IN_QUOTA);
|
|
||||||
if (IS_ERR(keyring)) {
|
|
||||||
ret = PTR_ERR(keyring);
|
|
||||||
goto failed_put_cred;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
goto failed_put_key;
|
|
||||||
|
|
||||||
ret = register_key_type(&key_type_dns_resolver);
|
|
||||||
if (ret < 0)
|
|
||||||
goto failed_put_key;
|
|
||||||
|
|
||||||
/* instruct request_key() to use this special keyring as a cache for
|
|
||||||
* the results it looks up */
|
|
||||||
cred->thread_keyring = keyring;
|
|
||||||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
|
||||||
dns_resolver_cache = cred;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed_put_key:
|
|
||||||
key_put(keyring);
|
|
||||||
failed_put_cred:
|
|
||||||
put_cred(cred);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cifs_exit_dns_resolver(void)
|
|
||||||
{
|
|
||||||
key_revoke(dns_resolver_cache->thread_keyring);
|
|
||||||
unregister_key_type(&key_type_dns_resolver);
|
|
||||||
put_cred(dns_resolver_cache);
|
|
||||||
printk(KERN_NOTICE "Unregistered %s key type\n",
|
|
||||||
key_type_dns_resolver.name);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#define _DNS_RESOLVE_H
|
#define _DNS_RESOLVE_H
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
extern int __init cifs_init_dns_resolver(void);
|
|
||||||
extern void cifs_exit_dns_resolver(void);
|
|
||||||
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
|
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
|
||||||
#endif /* KERNEL */
|
#endif /* KERNEL */
|
||||||
|
|
||||||
|
|
|
@ -732,15 +732,9 @@ cifs_find_inode(struct inode *inode, void *opaque)
|
||||||
if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
|
if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/* if it's not a directory or has no dentries, then flag it */
|
||||||
* uh oh -- it's a directory. We can't use it since hardlinked dirs are
|
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
|
||||||
* verboten. Disable serverino and return it as if it were found, the
|
|
||||||
* caller can discard it, generate a uniqueid and retry the find
|
|
||||||
*/
|
|
||||||
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
|
|
||||||
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
|
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
|
||||||
cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -754,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* walk dentry list for an inode and report whether it has aliases that
|
||||||
|
* are hashed. We use this to determine if a directory inode can actually
|
||||||
|
* be used.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
inode_has_hashed_dentries(struct inode *inode)
|
||||||
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
|
||||||
|
spin_lock(&dcache_lock);
|
||||||
|
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
|
||||||
|
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
|
||||||
|
spin_unlock(&dcache_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&dcache_lock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Given fattrs, get a corresponding inode */
|
/* Given fattrs, get a corresponding inode */
|
||||||
struct inode *
|
struct inode *
|
||||||
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
|
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
|
||||||
|
@ -769,12 +784,16 @@ retry_iget5_locked:
|
||||||
|
|
||||||
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
|
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
|
||||||
if (inode) {
|
if (inode) {
|
||||||
/* was there a problematic inode number collision? */
|
/* was there a potentially problematic inode collision? */
|
||||||
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
|
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
|
||||||
iput(inode);
|
|
||||||
fattr->cf_uniqueid = iunique(sb, ROOT_I);
|
|
||||||
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
|
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
|
||||||
goto retry_iget5_locked;
|
|
||||||
|
if (inode_has_hashed_dentries(inode)) {
|
||||||
|
cifs_autodisable_serverino(CIFS_SB(sb));
|
||||||
|
iput(inode);
|
||||||
|
fattr->cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
|
goto retry_iget5_locked;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cifs_fattr_to_inode(inode, fattr);
|
cifs_fattr_to_inode(inode, fattr);
|
||||||
|
|
|
@ -140,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
|
||||||
* Returns 0 on failure.
|
* Returns 0 on failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cifs_inet_pton(const int address_family, const char *cp, void *dst)
|
cifs_inet_pton(const int address_family, const char *cp, int len, void *dst)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* calculate length by finding first slash or NULL */
|
/* calculate length by finding first slash or NULL */
|
||||||
if (address_family == AF_INET)
|
if (address_family == AF_INET)
|
||||||
ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
|
ret = in4_pton(cp, len, dst, '\\', NULL);
|
||||||
else if (address_family == AF_INET6)
|
else if (address_family == AF_INET6)
|
||||||
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
|
ret = in6_pton(cp, len, dst , '\\', NULL);
|
||||||
|
|
||||||
cFYI(DBG2, "address conversion returned %d for %s", ret, cp);
|
cFYI(DBG2, "address conversion returned %d for %*.*s",
|
||||||
|
ret, len, len, cp);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -165,37 +166,39 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
|
||||||
* Returns 0 on failure.
|
* Returns 0 on failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cifs_convert_address(struct sockaddr *dst, char *src)
|
cifs_convert_address(struct sockaddr *dst, const char *src, int len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc, alen, slen;
|
||||||
char *pct, *endp;
|
const char *pct;
|
||||||
|
char *endp, scope_id[13];
|
||||||
struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
|
struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
|
||||||
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
|
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
|
||||||
|
|
||||||
/* IPv4 address */
|
/* IPv4 address */
|
||||||
if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
|
if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) {
|
||||||
s4->sin_family = AF_INET;
|
s4->sin_family = AF_INET;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* temporarily terminate string */
|
/* attempt to exclude the scope ID from the address part */
|
||||||
pct = strchr(src, '%');
|
pct = memchr(src, '%', len);
|
||||||
if (pct)
|
alen = pct ? pct - src : len;
|
||||||
*pct = '\0';
|
|
||||||
|
|
||||||
rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
|
|
||||||
|
|
||||||
/* repair temp termination (if any) and make pct point to scopeid */
|
|
||||||
if (pct)
|
|
||||||
*pct++ = '%';
|
|
||||||
|
|
||||||
|
rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
s6->sin6_family = AF_INET6;
|
s6->sin6_family = AF_INET6;
|
||||||
if (pct) {
|
if (pct) {
|
||||||
|
/* grab the scope ID */
|
||||||
|
slen = len - (alen + 1);
|
||||||
|
if (slen <= 0 || slen > 12)
|
||||||
|
return 0;
|
||||||
|
memcpy(scope_id, pct + 1, slen);
|
||||||
|
scope_id[slen] = '\0';
|
||||||
|
|
||||||
s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
|
s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
|
||||||
if (!*pct || *endp)
|
if (endp != scope_id + slen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,10 +206,10 @@ cifs_convert_address(struct sockaddr *dst, char *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cifs_fill_sockaddr(struct sockaddr *dst, char *src,
|
cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||||
const unsigned short int port)
|
const unsigned short int port)
|
||||||
{
|
{
|
||||||
if (!cifs_convert_address(dst, src))
|
if (!cifs_convert_address(dst, src, len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (dst->sa_family) {
|
switch (dst->sa_family) {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* DNS resolver key type
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Wang Lei. All Rights Reserved.
|
||||||
|
* Written by Wang Lei (wang840925@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _KEYS_DNS_RESOLVER_TYPE_H
|
||||||
|
#define _KEYS_DNS_RESOLVER_TYPE_H
|
||||||
|
|
||||||
|
#include <linux/key-type.h>
|
||||||
|
|
||||||
|
extern struct key_type key_type_dns_resolver;
|
||||||
|
|
||||||
|
extern int request_dns_resolver_key(const char *description,
|
||||||
|
const char *callout_info,
|
||||||
|
char **data);
|
||||||
|
|
||||||
|
#endif /* _KEYS_DNS_RESOLVER_TYPE_H */
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* DNS Resolver upcall management for CIFS DFS and AFS
|
||||||
|
* Handles host name to IP address resolution and DNS query for AFSDB RR.
|
||||||
|
*
|
||||||
|
* Copyright (c) International Business Machines Corp., 2008
|
||||||
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||||
|
* Wang Lei (wang840925@gmail.com)
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_DNS_RESOLVER_H
|
||||||
|
#define _LINUX_DNS_RESOLVER_H
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
extern int dns_query(const char *type, const char *name, size_t namelen,
|
||||||
|
const char *options, char **_result, time_t *_expiry);
|
||||||
|
|
||||||
|
#endif /* KERNEL */
|
||||||
|
|
||||||
|
#endif /* _LINUX_DNS_RESOLVER_H */
|
|
@ -213,6 +213,7 @@ source "net/phonet/Kconfig"
|
||||||
source "net/ieee802154/Kconfig"
|
source "net/ieee802154/Kconfig"
|
||||||
source "net/sched/Kconfig"
|
source "net/sched/Kconfig"
|
||||||
source "net/dcb/Kconfig"
|
source "net/dcb/Kconfig"
|
||||||
|
source "net/dns_resolver/Kconfig"
|
||||||
|
|
||||||
config RPS
|
config RPS
|
||||||
boolean
|
boolean
|
||||||
|
|
|
@ -67,3 +67,4 @@ ifeq ($(CONFIG_NET),y)
|
||||||
obj-$(CONFIG_SYSCTL) += sysctl_net.o
|
obj-$(CONFIG_SYSCTL) += sysctl_net.o
|
||||||
endif
|
endif
|
||||||
obj-$(CONFIG_WIMAX) += wimax/
|
obj-$(CONFIG_WIMAX) += wimax/
|
||||||
|
obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#
|
||||||
|
# Configuration for DNS Resolver
|
||||||
|
#
|
||||||
|
config DNS_RESOLVER
|
||||||
|
tristate "DNS Resolver support"
|
||||||
|
depends on NET && KEYS
|
||||||
|
help
|
||||||
|
Saying Y here will include support for the DNS Resolver key type
|
||||||
|
which can be used to make upcalls to perform DNS lookups in
|
||||||
|
userspace.
|
||||||
|
|
||||||
|
DNS Resolver is used to query DNS server for information. Examples
|
||||||
|
being resolving a UNC hostname element to an IP address for CIFS or
|
||||||
|
performing a DNS query for AFSDB records so that AFS can locate a
|
||||||
|
cell's volume location database servers.
|
||||||
|
|
||||||
|
DNS Resolver is used by the CIFS and AFS modules, and would support
|
||||||
|
SMB2 later. DNS Resolver is supported by the userspace upcall
|
||||||
|
helper "/sbin/dns.resolver" via /etc/request-key.conf.
|
||||||
|
|
||||||
|
See <file:Documentation/networking/dns_resolver.txt> for further
|
||||||
|
information.
|
||||||
|
|
||||||
|
To compile this as a module, choose M here: the module will be called
|
||||||
|
dnsresolver.
|
||||||
|
|
||||||
|
If unsure, say N.
|
|
@ -0,0 +1,7 @@
|
||||||
|
#
|
||||||
|
# Makefile for the Linux DNS Resolver.
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o
|
||||||
|
|
||||||
|
dns_resolver-objs := dns_key.o dns_query.o
|
|
@ -0,0 +1,211 @@
|
||||||
|
/* Key type used to cache DNS lookups made by the kernel
|
||||||
|
*
|
||||||
|
* See Documentation/networking/dns_resolver.txt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Igor Mammedov
|
||||||
|
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||||
|
* Steve French (sfrench@us.ibm.com)
|
||||||
|
* Wang Lei (wang840925@gmail.com)
|
||||||
|
* David Howells (dhowells@redhat.com)
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/keyctl.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <keys/dns_resolver-type.h>
|
||||||
|
#include <keys/user-type.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("DNS Resolver");
|
||||||
|
MODULE_AUTHOR("Wang Lei");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
unsigned dns_resolver_debug;
|
||||||
|
module_param_named(debug, dns_resolver_debug, uint, S_IWUSR | S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
|
||||||
|
|
||||||
|
const struct cred *dns_resolver_cache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instantiate a user defined key for dns_resolver.
|
||||||
|
*
|
||||||
|
* The data must be a NUL-terminated string, with the NUL char accounted in
|
||||||
|
* datalen.
|
||||||
|
*
|
||||||
|
* If the data contains a '#' characters, then we take the clause after each
|
||||||
|
* one to be an option of the form 'key=value'. The actual data of interest is
|
||||||
|
* the string leading up to the first '#'. For instance:
|
||||||
|
*
|
||||||
|
* "ip1,ip2,...#foo=bar"
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
|
||||||
|
{
|
||||||
|
struct user_key_payload *upayload;
|
||||||
|
int ret;
|
||||||
|
size_t result_len = 0;
|
||||||
|
const char *data = _data, *opt;
|
||||||
|
|
||||||
|
kenter("%%%d,%s,'%s',%zu",
|
||||||
|
key->serial, key->description, data, datalen);
|
||||||
|
|
||||||
|
if (datalen <= 1 || !data || data[datalen - 1] != '\0')
|
||||||
|
return -EINVAL;
|
||||||
|
datalen--;
|
||||||
|
|
||||||
|
/* deal with any options embedded in the data */
|
||||||
|
opt = memchr(data, '#', datalen);
|
||||||
|
if (!opt) {
|
||||||
|
kdebug("no options currently supported");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_len = datalen;
|
||||||
|
ret = key_payload_reserve(key, result_len);
|
||||||
|
if (ret < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
|
||||||
|
if (!upayload) {
|
||||||
|
kleave(" = -ENOMEM");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
upayload->datalen = result_len;
|
||||||
|
memcpy(upayload->data, data, result_len);
|
||||||
|
upayload->data[result_len] = '\0';
|
||||||
|
rcu_assign_pointer(key->payload.data, upayload);
|
||||||
|
|
||||||
|
kleave(" = 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The description is of the form "[<type>:]<domain_name>"
|
||||||
|
*
|
||||||
|
* The domain name may be a simple name or an absolute domain name (which
|
||||||
|
* should end with a period). The domain name is case-independent.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dns_resolver_match(const struct key *key, const void *description)
|
||||||
|
{
|
||||||
|
int slen, dlen, ret = 0;
|
||||||
|
const char *src = key->description, *dsp = description;
|
||||||
|
|
||||||
|
kenter("%s,%s", src, dsp);
|
||||||
|
|
||||||
|
if (!src || !dsp)
|
||||||
|
goto no_match;
|
||||||
|
|
||||||
|
if (strcasecmp(src, dsp) == 0)
|
||||||
|
goto matched;
|
||||||
|
|
||||||
|
slen = strlen(src);
|
||||||
|
dlen = strlen(dsp);
|
||||||
|
if (slen <= 0 || dlen <= 0)
|
||||||
|
goto no_match;
|
||||||
|
if (src[slen - 1] == '.')
|
||||||
|
slen--;
|
||||||
|
if (dsp[dlen - 1] == '.')
|
||||||
|
dlen--;
|
||||||
|
if (slen != dlen || strncasecmp(src, dsp, slen) != 0)
|
||||||
|
goto no_match;
|
||||||
|
|
||||||
|
matched:
|
||||||
|
ret = 1;
|
||||||
|
no_match:
|
||||||
|
kleave(" = %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct key_type key_type_dns_resolver = {
|
||||||
|
.name = "dns_resolver",
|
||||||
|
.instantiate = dns_resolver_instantiate,
|
||||||
|
.match = dns_resolver_match,
|
||||||
|
.revoke = user_revoke,
|
||||||
|
.destroy = user_destroy,
|
||||||
|
.describe = user_describe,
|
||||||
|
.read = user_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init init_dns_resolver(void)
|
||||||
|
{
|
||||||
|
struct cred *cred;
|
||||||
|
struct key *keyring;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
printk(KERN_NOTICE "Registering the %s key type\n",
|
||||||
|
key_type_dns_resolver.name);
|
||||||
|
|
||||||
|
/* create an override credential set with a special thread keyring in
|
||||||
|
* which DNS requests are cached
|
||||||
|
*
|
||||||
|
* this is used to prevent malicious redirections from being installed
|
||||||
|
* with add_key().
|
||||||
|
*/
|
||||||
|
cred = prepare_kernel_cred(NULL);
|
||||||
|
if (!cred)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
|
||||||
|
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||||
|
KEY_USR_VIEW | KEY_USR_READ,
|
||||||
|
KEY_ALLOC_NOT_IN_QUOTA);
|
||||||
|
if (IS_ERR(keyring)) {
|
||||||
|
ret = PTR_ERR(keyring);
|
||||||
|
goto failed_put_cred;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto failed_put_key;
|
||||||
|
|
||||||
|
ret = register_key_type(&key_type_dns_resolver);
|
||||||
|
if (ret < 0)
|
||||||
|
goto failed_put_key;
|
||||||
|
|
||||||
|
/* instruct request_key() to use this special keyring as a cache for
|
||||||
|
* the results it looks up */
|
||||||
|
cred->thread_keyring = keyring;
|
||||||
|
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||||||
|
dns_resolver_cache = cred;
|
||||||
|
|
||||||
|
kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed_put_key:
|
||||||
|
key_put(keyring);
|
||||||
|
failed_put_cred:
|
||||||
|
put_cred(cred);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit exit_dns_resolver(void)
|
||||||
|
{
|
||||||
|
key_revoke(dns_resolver_cache->thread_keyring);
|
||||||
|
unregister_key_type(&key_type_dns_resolver);
|
||||||
|
put_cred(dns_resolver_cache);
|
||||||
|
printk(KERN_NOTICE "Unregistered %s key type\n",
|
||||||
|
key_type_dns_resolver.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(init_dns_resolver)
|
||||||
|
module_exit(exit_dns_resolver)
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,160 @@
|
||||||
|
/* Upcall routine, designed to work as a key type and working through
|
||||||
|
* /sbin/request-key to contact userspace when handling DNS queries.
|
||||||
|
*
|
||||||
|
* See Documentation/networking/dns_resolver.txt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Igor Mammedov
|
||||||
|
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||||
|
* Steve French (sfrench@us.ibm.com)
|
||||||
|
* Wang Lei (wang840925@gmail.com)
|
||||||
|
* David Howells (dhowells@redhat.com)
|
||||||
|
*
|
||||||
|
* The upcall wrapper used to make an arbitrary DNS query.
|
||||||
|
*
|
||||||
|
* This function requires the appropriate userspace tool dns.upcall to be
|
||||||
|
* installed and something like the following lines should be added to the
|
||||||
|
* /etc/request-key.conf file:
|
||||||
|
*
|
||||||
|
* create dns_resolver * * /sbin/dns.upcall %k
|
||||||
|
*
|
||||||
|
* For example to use this module to query AFSDB RR:
|
||||||
|
*
|
||||||
|
* create dns_resolver afsdb:* * /sbin/dns.afsdb %k
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/dns_resolver.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <keys/dns_resolver-type.h>
|
||||||
|
#include <keys/user-type.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dns_query - Query the DNS
|
||||||
|
* @type: Query type (or NULL for straight host->IP lookup)
|
||||||
|
* @name: Name to look up
|
||||||
|
* @namelen: Length of name
|
||||||
|
* @options: Request options (or NULL if no options)
|
||||||
|
* @_result: Where to place the returned data.
|
||||||
|
* @_expiry: Where to store the result expiry time (or NULL)
|
||||||
|
*
|
||||||
|
* The data will be returned in the pointer at *result, and the caller is
|
||||||
|
* responsible for freeing it.
|
||||||
|
*
|
||||||
|
* The description should be of the form "[<query_type>:]<domain_name>", and
|
||||||
|
* the options need to be appropriate for the query type requested. If no
|
||||||
|
* query_type is given, then the query is a straight hostname to IP address
|
||||||
|
* lookup.
|
||||||
|
*
|
||||||
|
* The DNS resolution lookup is performed by upcalling to userspace by way of
|
||||||
|
* requesting a key of type dns_resolver.
|
||||||
|
*
|
||||||
|
* Returns the size of the result on success, -ve error code otherwise.
|
||||||
|
*/
|
||||||
|
int dns_query(const char *type, const char *name, size_t namelen,
|
||||||
|
const char *options, char **_result, time_t *_expiry)
|
||||||
|
{
|
||||||
|
struct key *rkey;
|
||||||
|
struct user_key_payload *upayload;
|
||||||
|
const struct cred *saved_cred;
|
||||||
|
size_t typelen, desclen;
|
||||||
|
char *desc, *cp;
|
||||||
|
int ret, len;
|
||||||
|
|
||||||
|
kenter("%s,%*.*s,%zu,%s",
|
||||||
|
type, (int)namelen, (int)namelen, name, namelen, options);
|
||||||
|
|
||||||
|
if (!name || namelen == 0 || !_result)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* construct the query key description as "[<type>:]<name>" */
|
||||||
|
typelen = 0;
|
||||||
|
desclen = 0;
|
||||||
|
if (type) {
|
||||||
|
typelen = strlen(type);
|
||||||
|
if (typelen < 1)
|
||||||
|
return -EINVAL;
|
||||||
|
desclen += typelen + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!namelen)
|
||||||
|
namelen = strlen(name);
|
||||||
|
if (namelen < 3)
|
||||||
|
return -EINVAL;
|
||||||
|
desclen += namelen + 1;
|
||||||
|
|
||||||
|
desc = kmalloc(desclen, GFP_KERNEL);
|
||||||
|
if (!desc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cp = desc;
|
||||||
|
if (type) {
|
||||||
|
memcpy(cp, type, typelen);
|
||||||
|
cp += typelen;
|
||||||
|
*cp++ = ':';
|
||||||
|
}
|
||||||
|
memcpy(cp, name, namelen);
|
||||||
|
cp += namelen;
|
||||||
|
*cp = '\0';
|
||||||
|
|
||||||
|
if (!options)
|
||||||
|
options = "";
|
||||||
|
kdebug("call request_key(,%s,%s)", desc, options);
|
||||||
|
|
||||||
|
/* make the upcall, using special credentials to prevent the use of
|
||||||
|
* add_key() to preinstall malicious redirections
|
||||||
|
*/
|
||||||
|
saved_cred = override_creds(dns_resolver_cache);
|
||||||
|
rkey = request_key(&key_type_dns_resolver, desc, options);
|
||||||
|
revert_creds(saved_cred);
|
||||||
|
kfree(desc);
|
||||||
|
if (IS_ERR(rkey)) {
|
||||||
|
ret = PTR_ERR(rkey);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
down_read(&rkey->sem);
|
||||||
|
rkey->perm |= KEY_USR_VIEW;
|
||||||
|
|
||||||
|
ret = key_validate(rkey);
|
||||||
|
if (ret < 0)
|
||||||
|
goto put;
|
||||||
|
|
||||||
|
upayload = rcu_dereference_protected(rkey->payload.data,
|
||||||
|
lockdep_is_held(&rkey->sem));
|
||||||
|
len = upayload->datalen;
|
||||||
|
|
||||||
|
ret = -ENOMEM;
|
||||||
|
*_result = kmalloc(len + 1, GFP_KERNEL);
|
||||||
|
if (!*_result)
|
||||||
|
goto put;
|
||||||
|
|
||||||
|
memcpy(*_result, upayload->data, len + 1);
|
||||||
|
if (_expiry)
|
||||||
|
*_expiry = rkey->expiry;
|
||||||
|
|
||||||
|
ret = len;
|
||||||
|
put:
|
||||||
|
up_read(&rkey->sem);
|
||||||
|
key_put(rkey);
|
||||||
|
out:
|
||||||
|
kleave(" = %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dns_query);
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Wang Lei
|
||||||
|
* Author(s): Wang Lei (wang840925@gmail.com). All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Internal DNS Rsolver stuff
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dns_key.c
|
||||||
|
*/
|
||||||
|
extern const struct cred *dns_resolver_cache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* debug tracing
|
||||||
|
*/
|
||||||
|
extern unsigned dns_resolver_debug;
|
||||||
|
|
||||||
|
#define kdebug(FMT, ...) \
|
||||||
|
do { \
|
||||||
|
if (unlikely(dns_resolver_debug)) \
|
||||||
|
printk(KERN_DEBUG "[%-6.6s] "FMT"\n", \
|
||||||
|
current->comm, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kenter(FMT, ...) kdebug("==> %s("FMT")", __func__, ##__VA_ARGS__)
|
||||||
|
#define kleave(FMT, ...) kdebug("<== %s()"FMT"", __func__, ##__VA_ARGS__)
|
Loading…
Reference in New Issue