CIFS: Make cifs_convert_address() take a const src pointer and a length
David Howells [Thu, 22 Jul 2010 17:33:01 +0000 (18:33 +0100)]
Make cifs_convert_address() take a const src pointer and a length so that all
the strlen() calls in their can be cut out and to make it unnecessary to modify
the src string.

Also return the data length from dns_resolve_server_name_to_ip() so that a
strlen() can be cut out of cifs_compose_mount_options() too.

Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dns_resolve.c
fs/cifs/netmisc.c

index dc1ed50..d6ced7a 100644 (file)
@@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
        }
 
        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",
                          __func__, *devname, rc);
                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
         * the original sb_mountdata
         */
-       md_len = strlen(sb_mountdata) + strlen(srvIP) +
-               strlen(ref->node_name) + 12;
+       md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12;
        mountdata = kzalloc(md_len+1, GFP_KERNEL);
        if (mountdata == NULL) {
                rc = -ENOMEM;
index 2eaebbd..1f54508 100644 (file)
@@ -86,8 +86,8 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        struct TCP_Server_Info *server);
-extern int cifs_convert_address(struct sockaddr *dst, char *src);
-extern int cifs_fill_sockaddr(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, const char *src, int len,
                                unsigned short int port);
 extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
index 2a43a0a..95c2ea6 100644 (file)
@@ -1543,6 +1543,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        if (volume_info->UNCip && volume_info->UNC) {
                rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
                                        volume_info->UNCip,
+                                       strlen(volume_info->UNCip),
                                        volume_info->port);
                if (!rc) {
                        /* we failed translating address */
index 3ad7f43..aa967e7 100644 (file)
@@ -40,11 +40,11 @@ static const struct cred *dns_resolver_cache;
  *             0 - name is not IP
  */
 static int
-is_ip(char *name)
+is_ip(const char *name, int len)
 {
        struct sockaddr_storage ss;
 
-       return cifs_convert_address((struct sockaddr *)&ss, name);
+       return cifs_convert_address((struct sockaddr *)&ss, name, len);
 }
 
 static int
@@ -54,6 +54,10 @@ dns_resolver_instantiate(struct key *key, const void *data,
        int rc = 0;
        char *ip;
 
+       /* make sure this looks like an address */
+       if (!is_ip(data, datalen))
+               return -EINVAL;
+
        ip = kmalloc(datalen + 1, GFP_KERNEL);
        if (!ip)
                return -ENOMEM;
@@ -61,12 +65,6 @@ dns_resolver_instantiate(struct key *key, const void *data,
        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;
 
@@ -93,7 +91,7 @@ struct key_type key_type_dns_resolver = {
  *     unc - server UNC
  * output:
  *     *ip_addr - pointer to server ip, caller responcible for freeing it.
- * return 0 on success
+ * return the length of the returned string on success
  */
 int
 dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
@@ -131,7 +129,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
        memcpy(name, unc+2, len);
        name[len] = 0;
 
-       if (is_ip(name)) {
+       if (is_ip(name, len)) {
                cFYI(1, "%s: it is IP, skipping dns upcall: %s",
                                        __func__, name);
                data = name;
@@ -164,7 +162,7 @@ skip_upcall:
                                                        name,
                                                        *ip_addr
                                        );
-                       rc = 0;
+                       rc = len;
                } else {
                        rc = -ENOMEM;
                }
index c6721ee..f978511 100644 (file)
@@ -140,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
  * Returns 0 on failure.
  */
 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;
 
        /* calculate length by finding first slash or NULL */
        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)
-               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)
                ret = 1;
        return ret;
@@ -165,37 +166,39 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
  * Returns 0 on failure.
  */
 int
-cifs_convert_address(struct sockaddr *dst, char *src)
+cifs_convert_address(struct sockaddr *dst, const char *src, int len)
 {
-       int rc;
-       char *pct, *endp;
+       int rc, alen, slen;
+       const char *pct;
+       char *endp, scope_id[13];
        struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
        struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
 
        /* 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;
                return 1;
        }
 
-       /* temporarily terminate string */
-       pct = strchr(src, '%');
-       if (pct)
-               *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++ = '%';
+       /* attempt to exclude the scope ID from the address part */
+       pct = memchr(src, '%', len);
+       alen = pct ? pct - src : len;
 
+       rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
        if (!rc)
                return rc;
 
        s6->sin6_family = AF_INET6;
        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);
-               if (!*pct || *endp)
+               if (endp != scope_id + slen)
                        return 0;
        }
 
@@ -203,10 +206,10 @@ cifs_convert_address(struct sockaddr *dst, char *src)
 }
 
 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)
 {
-       if (!cifs_convert_address(dst, src))
+       if (!cifs_convert_address(dst, src, len))
                return 0;
 
        switch (dst->sa_family) {