linux/fs/cifs/dns_resolve.c
<<
>>
Prefs
   1/*
   2 *  fs/cifs/dns_resolve.c
   3 *
   4 *   Copyright (c) 2007 Igor Mammedov
   5 *   Author(s): Igor Mammedov (niallain@gmail.com)
   6 *              Steve French (sfrench@us.ibm.com)
   7 *
   8 *   Contains the CIFS DFS upcall routines used for hostname to
   9 *   IP address translation.
  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
  26#include <keys/user-type.h>
  27#include "dns_resolve.h"
  28#include "cifsglob.h"
  29#include "cifsproto.h"
  30#include "cifs_debug.h"
  31
  32/* Checks if supplied name is IP address
  33 * returns:
  34 *              1 - name is IP
  35 *              0 - name is not IP
  36 */
  37static int
  38is_ip(char *name)
  39{
  40        struct sockaddr_storage ss;
  41
  42        return cifs_convert_address(name, &ss);
  43}
  44
  45static int
  46dns_resolver_instantiate(struct key *key, const void *data,
  47                size_t datalen)
  48{
  49        int rc = 0;
  50        char *ip;
  51
  52        ip = kmalloc(datalen + 1, GFP_KERNEL);
  53        if (!ip)
  54                return -ENOMEM;
  55
  56        memcpy(ip, data, datalen);
  57        ip[datalen] = '\0';
  58
  59        /* make sure this looks like an address */
  60        if (!is_ip(ip)) {
  61                kfree(ip);
  62                return -EINVAL;
  63        }
  64
  65        key->type_data.x[0] = datalen;
  66        key->payload.data = ip;
  67
  68        return rc;
  69}
  70
  71static void
  72dns_resolver_destroy(struct key *key)
  73{
  74        kfree(key->payload.data);
  75}
  76
  77struct key_type key_type_dns_resolver = {
  78        .name        = "dns_resolver",
  79        .def_datalen = sizeof(struct in_addr),
  80        .describe    = user_describe,
  81        .instantiate = dns_resolver_instantiate,
  82        .destroy     = dns_resolver_destroy,
  83        .match       = user_match,
  84};
  85
  86/* Resolves server name to ip address.
  87 * input:
  88 *      unc - server UNC
  89 * output:
  90 *      *ip_addr - pointer to server ip, caller responcible for freeing it.
  91 * return 0 on success
  92 */
  93int
  94dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
  95{
  96        int rc = -EAGAIN;
  97        struct key *rkey = ERR_PTR(-EAGAIN);
  98        char *name;
  99        char *data = NULL;
 100        int len;
 101
 102        if (!ip_addr || !unc)
 103                return -EINVAL;
 104
 105        /* search for server name delimiter */
 106        len = strlen(unc);
 107        if (len < 3) {
 108                cFYI(1, ("%s: unc is too short: %s", __func__, unc));
 109                return -EINVAL;
 110        }
 111        len -= 2;
 112        name = memchr(unc+2, '\\', len);
 113        if (!name) {
 114                cFYI(1, ("%s: probably server name is whole unc: %s",
 115                                        __func__, unc));
 116        } else {
 117                len = (name - unc) - 2/* leading // */;
 118        }
 119
 120        name = kmalloc(len+1, GFP_KERNEL);
 121        if (!name) {
 122                rc = -ENOMEM;
 123                return rc;
 124        }
 125        memcpy(name, unc+2, len);
 126        name[len] = 0;
 127
 128        if (is_ip(name)) {
 129                cFYI(1, ("%s: it is IP, skipping dns upcall: %s",
 130                                        __func__, name));
 131                data = name;
 132                goto skip_upcall;
 133        }
 134
 135        rkey = request_key(&key_type_dns_resolver, name, "");
 136        if (!IS_ERR(rkey)) {
 137                len = rkey->type_data.x[0];
 138                data = rkey->payload.data;
 139        } else {
 140                cERROR(1, ("%s: unable to resolve: %s", __func__, name));
 141                goto out;
 142        }
 143
 144skip_upcall:
 145        if (data) {
 146                *ip_addr = kmalloc(len + 1, GFP_KERNEL);
 147                if (*ip_addr) {
 148                        memcpy(*ip_addr, data, len + 1);
 149                        if (!IS_ERR(rkey))
 150                                cFYI(1, ("%s: resolved: %s to %s", __func__,
 151                                                        name,
 152                                                        *ip_addr
 153                                        ));
 154                        rc = 0;
 155                } else {
 156                        rc = -ENOMEM;
 157                }
 158                if (!IS_ERR(rkey))
 159                        key_put(rkey);
 160        }
 161
 162out:
 163        kfree(name);
 164        return rc;
 165}
 166
 167
 168