Merge branch 'drm-fixes-3.16' of git://people.freedesktop.org/~agd5f/linux
[cascardo/linux.git] / drivers / target / iscsi / iscsi_target_auth.c
index de77d9a..ab4915c 100644 (file)
@@ -71,6 +71,40 @@ static void chap_gen_challenge(
                        challenge_asciihex);
 }
 
+static int chap_check_algorithm(const char *a_str)
+{
+       char *tmp, *orig, *token;
+
+       tmp = kstrdup(a_str, GFP_KERNEL);
+       if (!tmp) {
+               pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
+               return CHAP_DIGEST_UNKNOWN;
+       }
+       orig = tmp;
+
+       token = strsep(&tmp, "=");
+       if (!token)
+               goto out;
+
+       if (strcmp(token, "CHAP_A")) {
+               pr_err("Unable to locate CHAP_A key\n");
+               goto out;
+       }
+       while (token) {
+               token = strsep(&tmp, ",");
+               if (!token)
+                       goto out;
+
+               if (!strncmp(token, "5", 1)) {
+                       pr_debug("Selected MD5 Algorithm\n");
+                       kfree(orig);
+                       return CHAP_DIGEST_MD5;
+               }
+       }
+out:
+       kfree(orig);
+       return CHAP_DIGEST_UNKNOWN;
+}
 
 static struct iscsi_chap *chap_server_open(
        struct iscsi_conn *conn,
@@ -79,6 +113,7 @@ static struct iscsi_chap *chap_server_open(
        char *aic_str,
        unsigned int *aic_len)
 {
+       int ret;
        struct iscsi_chap *chap;
 
        if (!(auth->naf_flags & NAF_USERID_SET) ||
@@ -93,21 +128,24 @@ static struct iscsi_chap *chap_server_open(
                return NULL;
 
        chap = conn->auth_protocol;
-       /*
-        * We only support MD5 MDA presently.
-        */
-       if (strncmp(a_str, "CHAP_A=5", 8)) {
-               pr_err("CHAP_A is not MD5.\n");
+       ret = chap_check_algorithm(a_str);
+       switch (ret) {
+       case CHAP_DIGEST_MD5:
+               pr_debug("[server] Got CHAP_A=5\n");
+               /*
+                * Send back CHAP_A set to MD5.
+               */
+               *aic_len = sprintf(aic_str, "CHAP_A=5");
+               *aic_len += 1;
+               chap->digest_type = CHAP_DIGEST_MD5;
+               pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+               break;
+       case CHAP_DIGEST_UNKNOWN:
+       default:
+               pr_err("Unsupported CHAP_A value\n");
                return NULL;
        }
-       pr_debug("[server] Got CHAP_A=5\n");
-       /*
-        * Send back CHAP_A set to MD5.
-        */
-       *aic_len = sprintf(aic_str, "CHAP_A=5");
-       *aic_len += 1;
-       chap->digest_type = CHAP_DIGEST_MD5;
-       pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+
        /*
         * Set Identifier.
         */
@@ -136,7 +174,6 @@ static int chap_server_compute_md5(
        char *nr_out_ptr,
        unsigned int *nr_out_len)
 {
-       char *endptr;
        unsigned long id;
        unsigned char id_as_uchar;
        unsigned char digest[MD5_SIGNATURE_SIZE];
@@ -282,9 +319,14 @@ static int chap_server_compute_md5(
        }
 
        if (type == HEX)
-               id = simple_strtoul(&identifier[2], &endptr, 0);
+               ret = kstrtoul(&identifier[2], 0, &id);
        else
-               id = simple_strtoul(identifier, &endptr, 0);
+               ret = kstrtoul(identifier, 0, &id);
+
+       if (ret < 0) {
+               pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
+               goto out;
+       }
        if (id > 255) {
                pr_err("chap identifier: %lu greater than 255\n", id);
                goto out;
@@ -313,6 +355,20 @@ static int chap_server_compute_md5(
                pr_err("Unable to convert incoming challenge\n");
                goto out;
        }
+       if (challenge_len > 1024) {
+               pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
+               goto out;
+       }
+       /*
+        * During mutual authentication, the CHAP_C generated by the
+        * initiator must not match the original CHAP_C generated by
+        * the target.
+        */
+       if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
+               pr_err("initiator CHAP_C matches target CHAP_C, failing"
+                      " login attempt\n");
+               goto out;
+       }
        /*
         * Generate CHAP_N and CHAP_R for mutual authentication.
         */