[BACK]Return to auth-rsa.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/Attic/auth-rsa.c between version 1.11 and 1.12

version 1.11, 1999/11/22 21:02:38 version 1.12, 1999/11/23 22:25:52
Line 44 
Line 44 
 /* The .ssh/authorized_keys file contains public keys, one per line, in the  /* The .ssh/authorized_keys file contains public keys, one per line, in the
    following format:     following format:
      options bits e n comment       options bits e n comment
    where bits, e and n are decimal numbers,     where bits, e and n are decimal numbers,
    and comment is any string of characters up to newline.  The maximum     and comment is any string of characters up to newline.  The maximum
    length of a line is 8000 characters.  See the documentation for a     length of a line is 8000 characters.  See the documentation for a
    description of the options.     description of the options.
Line 57 
Line 57 
 int  int
 auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)  auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
 {  {
   BIGNUM *challenge, *encrypted_challenge, *aux;          BIGNUM *challenge, *encrypted_challenge, *aux;
   RSA *pk;          RSA *pk;
   BN_CTX *ctx = BN_CTX_new();          BN_CTX *ctx = BN_CTX_new();
   unsigned char buf[32], mdbuf[16], response[16];          unsigned char buf[32], mdbuf[16], response[16];
   MD5_CTX md;          MD5_CTX md;
   unsigned int i;          unsigned int i;
   int plen, len;          int plen, len;
   
   encrypted_challenge = BN_new();          encrypted_challenge = BN_new();
   challenge = BN_new();          challenge = BN_new();
   aux = BN_new();          aux = BN_new();
   
   /* Generate a random challenge. */          /* Generate a random challenge. */
   BN_rand(challenge, 256, 0, 0);          BN_rand(challenge, 256, 0, 0);
   BN_mod(challenge, challenge, n, ctx);          BN_mod(challenge, challenge, n, ctx);
   
   /* Create the public key data structure. */  
   pk = RSA_new();  
   pk->e = BN_new();  
   BN_copy(pk->e, e);  
   pk->n = BN_new();  
   BN_copy(pk->n, n);  
   
   /* Encrypt the challenge with the public key. */          /* Create the public key data structure. */
   rsa_public_encrypt(encrypted_challenge, challenge, pk);          pk = RSA_new();
   RSA_free(pk);          pk->e = BN_new();
           BN_copy(pk->e, e);
           pk->n = BN_new();
           BN_copy(pk->n, n);
   
   /* Send the encrypted challenge to the client. */          /* Encrypt the challenge with the public key. */
   packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);          rsa_public_encrypt(encrypted_challenge, challenge, pk);
   packet_put_bignum(encrypted_challenge);          RSA_free(pk);
   packet_send();  
   packet_write_wait();  
   
   /* The response is MD5 of decrypted challenge plus session id. */          /* Send the encrypted challenge to the client. */
   len = BN_num_bytes(challenge);          packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
   if (len <= 0 || len > 32)          packet_put_bignum(encrypted_challenge);
     fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);          packet_send();
   memset(buf, 0, 32);          packet_write_wait();
   BN_bn2bin(challenge, buf + 32 - len);  
   MD5_Init(&md);  
   MD5_Update(&md, buf, 32);  
   MD5_Update(&md, session_id, 16);  
   MD5_Final(mdbuf, &md);  
   
   /* We will no longer need these. */          /* The response is MD5 of decrypted challenge plus session id. */
   BN_clear_free(encrypted_challenge);          len = BN_num_bytes(challenge);
   BN_clear_free(challenge);          if (len <= 0 || len > 32)
   BN_clear_free(aux);                  fatal("auth_rsa_challenge_dialog: bad challenge length %d", len);
   BN_CTX_free(ctx);          memset(buf, 0, 32);
           BN_bn2bin(challenge, buf + 32 - len);
   /* Wait for a response. */          MD5_Init(&md);
   packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);          MD5_Update(&md, buf, 32);
   packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);          MD5_Update(&md, session_id, 16);
   for (i = 0; i < 16; i++)          MD5_Final(mdbuf, &md);
     response[i] = packet_get_char();  
   
   /* Verify that the response is the original challenge. */          /* We will no longer need these. */
   if (memcmp(response, mdbuf, 16) != 0)          BN_clear_free(encrypted_challenge);
     {          BN_clear_free(challenge);
       /* Wrong answer. */          BN_clear_free(aux);
       return 0;          BN_CTX_free(ctx);
     }  
   
   /* Correct answer. */          /* Wait for a response. */
   return 1;          packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE);
           packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE);
           for (i = 0; i < 16; i++)
                   response[i] = packet_get_char();
   
           /* Verify that the response is the original challenge. */
           if (memcmp(response, mdbuf, 16) != 0) {
                   /* Wrong answer. */
                   return 0;
           }
           /* Correct answer. */
           return 1;
 }  }
   
 /* Performs the RSA authentication dialog with the client.  This returns  /* Performs the RSA authentication dialog with the client.  This returns
Line 131 
Line 129 
 int  int
 auth_rsa(struct passwd *pw, BIGNUM *client_n)  auth_rsa(struct passwd *pw, BIGNUM *client_n)
 {  {
   extern ServerOptions options;          extern ServerOptions options;
   char line[8192], file[1024];          char line[8192], file[1024];
   int authenticated;          int authenticated;
   unsigned int bits;          unsigned int bits;
   FILE *f;          FILE *f;
   unsigned long linenum = 0;          unsigned long linenum = 0;
   struct stat st;          struct stat st;
   BIGNUM *e, *n;          BIGNUM *e, *n;
   
   /* Temporarily use the user's uid. */          /* Temporarily use the user's uid. */
   temporarily_use_uid(pw->pw_uid);          temporarily_use_uid(pw->pw_uid);
   
   /* The authorized keys. */          /* The authorized keys. */
   snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,          snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
     SSH_USER_PERMITTED_KEYS);                   SSH_USER_PERMITTED_KEYS);
   
   /* Fail quietly if file does not exist */  
   if (stat(file, &st) < 0)  
     {  
       /* Restore the privileged uid. */  
       restore_uid();  
       return 0;  
     }  
   
   /* Open the file containing the authorized keys. */          /* Fail quietly if file does not exist */
   f = fopen(file, "r");          if (stat(file, &st) < 0) {
   if (!f)                  /* Restore the privileged uid. */
     {                  restore_uid();
       /* Restore the privileged uid. */                  return 0;
       restore_uid();          }
       packet_send_debug("Could not open %.900s for reading.", file);          /* Open the file containing the authorized keys. */
       packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");          f = fopen(file, "r");
       return 0;          if (!f) {
     }                  /* Restore the privileged uid. */
                   restore_uid();
                   packet_send_debug("Could not open %.900s for reading.", file);
                   packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
                   return 0;
           }
           if (options.strict_modes) {
                   int fail = 0;
                   char buf[1024];
                   /* Check open file in order to avoid open/stat races */
                   if (fstat(fileno(f), &st) < 0 ||
                       (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
                       (st.st_mode & 022) != 0) {
                           snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
                                    "bad ownership or modes for '%s'.", pw->pw_name, file);
                           fail = 1;
                   } else {
                           /* Check path to SSH_USER_PERMITTED_KEYS */
                           int i;
                           static const char *check[] = {
                                   "", SSH_USER_DIR, NULL
                           };
                           for (i = 0; check[i]; i++) {
                                   snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
                                   if (stat(line, &st) < 0 ||
                                       (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
                                       (st.st_mode & 022) != 0) {
                                           snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
                                                    "bad ownership or modes for '%s'.", pw->pw_name, line);
                                           fail = 1;
                                           break;
                                   }
                           }
                   }
                   if (fail) {
                           log(buf);
                           packet_send_debug(buf);
                           restore_uid();
                           return 0;
                   }
           }
           /* Flag indicating whether authentication has succeeded. */
           authenticated = 0;
   
   if (options.strict_modes) {          /* Initialize mp-int variables. */
     int fail=0;          e = BN_new();
     char buf[1024];          n = BN_new();
     /* Check open file in order to avoid open/stat races */  
     if (fstat(fileno(f), &st) < 0 ||  
         (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
         (st.st_mode & 022) != 0) {  
       snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "  
                "bad ownership or modes for '%s'.", pw->pw_name, file);  
       fail=1;  
     }else{  
       /* Check path to SSH_USER_PERMITTED_KEYS */  
       int i;  
       static const char *check[] = {  
             "", SSH_USER_DIR, NULL  
       };  
       for (i=0; check[i]; i++) {  
         snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);  
         if (stat(line, &st) < 0 ||  
             (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
             (st.st_mode & 022) != 0) {  
           snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "  
                    "bad ownership or modes for '%s'.", pw->pw_name, line);  
           fail=1;  
           break;  
         }  
       }  
     }  
     if (fail) {  
       log(buf);  
       packet_send_debug(buf);  
       restore_uid();  
       return 0;  
     }  
   }  
   
   /* Flag indicating whether authentication has succeeded. */          /* Go though the accepted keys, looking for the current key.  If
   authenticated = 0;             found, perform a challenge-response dialog to verify that the
              user really has the corresponding private key. */
   /* Initialize mp-int variables. */          while (fgets(line, sizeof(line), f)) {
   e = BN_new();                  char *cp;
   n = BN_new();                  char *options;
   
   /* Go though the accepted keys, looking for the current key.  If found,                  linenum++;
      perform a challenge-response dialog to verify that the user really has  
      the corresponding private key. */  
   while (fgets(line, sizeof(line), f))  
     {  
       char *cp;  
       char *options;  
   
       linenum++;                  /* Skip leading whitespace. */
                   for (cp = line; *cp == ' ' || *cp == '\t'; cp++);
   
       /* Skip leading whitespace. */                  /* Skip empty and comment lines. */
       for (cp = line; *cp == ' ' || *cp == '\t'; cp++)                  if (!*cp || *cp == '\n' || *cp == '#')
         ;                          continue;
   
       /* Skip empty and comment lines. */                  /* Check if there are options for this key, and if so,
       if (!*cp || *cp == '\n' || *cp == '#')                     save their starting address and skip the option part
         continue;                     for now.  If there are no options, set the starting
                      address to NULL. */
                   if (*cp < '0' || *cp > '9') {
                           int quoted = 0;
                           options = cp;
                           for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
                                   if (*cp == '\\' && cp[1] == '"')
                                           cp++;   /* Skip both */
                                   else if (*cp == '"')
                                           quoted = !quoted;
                           }
                   } else
                           options = NULL;
   
       /* Check if there are options for this key, and if so, save their                  /* Parse the key from the line. */
          starting address and skip the option part for now.  If there are no                  if (!auth_rsa_read_key(&cp, &bits, e, n)) {
          options, set the starting address to NULL. */                          debug("%.100s, line %lu: bad key syntax",
       if (*cp < '0' || *cp > '9')                                SSH_USER_PERMITTED_KEYS, linenum);
         {                          packet_send_debug("%.100s, line %lu: bad key syntax",
           int quoted = 0;                                            SSH_USER_PERMITTED_KEYS, linenum);
           options = cp;                          continue;
           for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++)                  }
             {                  /* cp now points to the comment part. */
               if (*cp == '\\' && cp[1] == '"')  
                 cp++; /* Skip both */  
               else  
                 if (*cp == '"')  
                   quoted = !quoted;  
             }  
         }  
       else  
         options = NULL;  
   
       /* Parse the key from the line. */  
       if (!auth_rsa_read_key(&cp, &bits, e, n))  
         {  
           debug("%.100s, line %lu: bad key syntax",  
                 SSH_USER_PERMITTED_KEYS, linenum);  
           packet_send_debug("%.100s, line %lu: bad key syntax",  
                             SSH_USER_PERMITTED_KEYS, linenum);  
           continue;  
         }  
       /* cp now points to the comment part. */  
   
       /* check the real bits  */                  /* check the real bits  */
       if (bits != BN_num_bits(n))                  if (bits != BN_num_bits(n))
         error("Warning: error in %s, line %ld: keysize mismatch: "                          error("Warning: error in %s, line %ld: keysize mismatch: "
               "actual size %d vs. announced %d.",                                "actual size %d vs. announced %d.",
               file, linenum, BN_num_bits(n), bits);                                file, linenum, BN_num_bits(n), bits);
   
       /* Check if the we have found the desired key (identified by its                  /* Check if the we have found the desired key (identified by its modulus). */
          modulus). */                  if (BN_cmp(n, client_n) != 0)
       if (BN_cmp(n, client_n) != 0)                          continue;       /* Wrong key. */
         continue; /* Wrong key. */  
   
       /* We have found the desired key. */                  /* We have found the desired key. */
   
       /* Perform the challenge-response dialog for this key. */                  /* Perform the challenge-response dialog for this key. */
       if (!auth_rsa_challenge_dialog(e, n))                  if (!auth_rsa_challenge_dialog(e, n)) {
         {                          /* Wrong response. */
           /* Wrong response. */                          verbose("Wrong response to RSA authentication challenge.");
           verbose("Wrong response to RSA authentication challenge.");                          packet_send_debug("Wrong response to RSA authentication challenge.");
           packet_send_debug("Wrong response to RSA authentication challenge.");                          continue;
           continue;                  }
         }                  /* Correct response.  The client has been successfully
                      authenticated. Note that we have not yet processed the
                      options; this will be reset if the options cause the
                      authentication to be rejected. */
                   authenticated = 1;
   
       /* Correct response.  The client has been successfully authenticated.                  /* RSA part of authentication was accepted.  Now process the options. */
          Note that we have not yet processed the options; this will be reset                  if (options) {
          if the options cause the authentication to be rejected. */                          while (*options && *options != ' ' && *options != '\t') {
       authenticated = 1;                                  cp = "no-port-forwarding";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           packet_send_debug("Port forwarding disabled.");
                                           no_port_forwarding_flag = 1;
                                           options += strlen(cp);
                                           goto next_option;
                                   }
                                   cp = "no-agent-forwarding";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           packet_send_debug("Agent forwarding disabled.");
                                           no_agent_forwarding_flag = 1;
                                           options += strlen(cp);
                                           goto next_option;
                                   }
                                   cp = "no-X11-forwarding";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           packet_send_debug("X11 forwarding disabled.");
                                           no_x11_forwarding_flag = 1;
                                           options += strlen(cp);
                                           goto next_option;
                                   }
                                   cp = "no-pty";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           packet_send_debug("Pty allocation disabled.");
                                           no_pty_flag = 1;
                                           options += strlen(cp);
                                           goto next_option;
                                   }
                                   cp = "command=\"";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           int i;
                                           options += strlen(cp);
                                           forced_command = xmalloc(strlen(options) + 1);
                                           i = 0;
                                           while (*options) {
                                                   if (*options == '"')
                                                           break;
                                                   if (*options == '\\' && options[1] == '"') {
                                                           options += 2;
                                                           forced_command[i++] = '"';
                                                           continue;
                                                   }
                                                   forced_command[i++] = *options++;
                                           }
                                           if (!*options) {
                                                   debug("%.100s, line %lu: missing end quote",
                                                         SSH_USER_PERMITTED_KEYS, linenum);
                                                   packet_send_debug("%.100s, line %lu: missing end quote",
                                                                     SSH_USER_PERMITTED_KEYS, linenum);
                                                   continue;
                                           }
                                           forced_command[i] = 0;
                                           packet_send_debug("Forced command: %.900s", forced_command);
                                           options++;
                                           goto next_option;
                                   }
                                   cp = "environment=\"";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           int i;
                                           char *s;
                                           struct envstring *new_envstring;
                                           options += strlen(cp);
                                           s = xmalloc(strlen(options) + 1);
                                           i = 0;
                                           while (*options) {
                                                   if (*options == '"')
                                                           break;
                                                   if (*options == '\\' && options[1] == '"') {
                                                           options += 2;
                                                           s[i++] = '"';
                                                           continue;
                                                   }
                                                   s[i++] = *options++;
                                           }
                                           if (!*options) {
                                                   debug("%.100s, line %lu: missing end quote",
                                                         SSH_USER_PERMITTED_KEYS, linenum);
                                                   packet_send_debug("%.100s, line %lu: missing end quote",
                                                                     SSH_USER_PERMITTED_KEYS, linenum);
                                                   continue;
                                           }
                                           s[i] = 0;
                                           packet_send_debug("Adding to environment: %.900s", s);
                                           debug("Adding to environment: %.900s", s);
                                           options++;
                                           new_envstring = xmalloc(sizeof(struct envstring));
                                           new_envstring->s = s;
                                           new_envstring->next = custom_environment;
                                           custom_environment = new_envstring;
                                           goto next_option;
                                   }
                                   cp = "from=\"";
                                   if (strncmp(options, cp, strlen(cp)) == 0) {
                                           char *patterns = xmalloc(strlen(options) + 1);
                                           int i;
                                           options += strlen(cp);
                                           i = 0;
                                           while (*options) {
                                                   if (*options == '"')
                                                           break;
                                                   if (*options == '\\' && options[1] == '"') {
                                                           options += 2;
                                                           patterns[i++] = '"';
                                                           continue;
                                                   }
                                                   patterns[i++] = *options++;
                                           }
                                           if (!*options) {
                                                   debug("%.100s, line %lu: missing end quote",
                                                         SSH_USER_PERMITTED_KEYS, linenum);
                                                   packet_send_debug("%.100s, line %lu: missing end quote",
                                                                     SSH_USER_PERMITTED_KEYS, linenum);
                                                   continue;
                                           }
                                           patterns[i] = 0;
                                           options++;
                                           if (!match_hostname(get_canonical_hostname(), patterns,
                                                        strlen(patterns)) &&
                                               !match_hostname(get_remote_ipaddr(), patterns,
                                                        strlen(patterns))) {
                                                   log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",
                                                       pw->pw_name, get_canonical_hostname(),
                                                       get_remote_ipaddr());
                                                   packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
                                                   get_canonical_hostname());
                                                   xfree(patterns);
                                                   authenticated = 0;
                                                   break;
                                           }
                                           xfree(patterns);
                                           /* Host name matches. */
                                           goto next_option;
                                   }
                   bad_option:
                                   /* Unknown option. */
                                   log("Bad options in %.100s file, line %lu: %.50s",
                                       SSH_USER_PERMITTED_KEYS, linenum, options);
                                   packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
                                                     SSH_USER_PERMITTED_KEYS, linenum, options);
                                   authenticated = 0;
                                   break;
   
       /* RSA part of authentication was accepted.  Now process the options. */                  next_option:
       if (options)                                  /* Skip the comma, and move to the next option
         {                                     (or break out if there are no more). */
           while (*options && *options != ' ' && *options != '\t')                                  if (!*options)
             {                                          fatal("Bugs in auth-rsa.c option processing.");
               cp = "no-port-forwarding";                                  if (*options == ' ' || *options == '\t')
               if (strncmp(options, cp, strlen(cp)) == 0)                                          break;  /* End of options. */
                 {                                  if (*options != ',')
                   packet_send_debug("Port forwarding disabled.");                                          goto bad_option;
                   no_port_forwarding_flag = 1;                                  options++;
                   options += strlen(cp);                                  /* Process the next option. */
                   goto next_option;                                  continue;
                 }  
               cp = "no-agent-forwarding";  
               if (strncmp(options, cp, strlen(cp)) == 0)  
                 {  
                   packet_send_debug("Agent forwarding disabled.");  
                   no_agent_forwarding_flag = 1;  
                   options += strlen(cp);  
                   goto next_option;  
                 }  
               cp = "no-X11-forwarding";  
               if (strncmp(options, cp, strlen(cp)) == 0)  
                 {  
                   packet_send_debug("X11 forwarding disabled.");  
                   no_x11_forwarding_flag = 1;  
                   options += strlen(cp);  
                   goto next_option;  
                 }  
               cp = "no-pty";  
               if (strncmp(options, cp, strlen(cp)) == 0)  
                 {  
                   packet_send_debug("Pty allocation disabled.");  
                   no_pty_flag = 1;  
                   options += strlen(cp);  
                   goto next_option;  
                 }  
               cp = "command=\"";  
               if (strncmp(options, cp, strlen(cp)) == 0)  
                 {  
                   int i;  
                   options += strlen(cp);  
                   forced_command = xmalloc(strlen(options) + 1);  
                   i = 0;  
                   while (*options)  
                     {  
                       if (*options == '"')  
                         break;  
                       if (*options == '\\' && options[1] == '"')  
                         {  
                           options += 2;  
                           forced_command[i++] = '"';  
                           continue;  
                         }                          }
                       forced_command[i++] = *options++;  
                     }  
                   if (!*options)  
                     {  
                       debug("%.100s, line %lu: missing end quote",  
                             SSH_USER_PERMITTED_KEYS, linenum);  
                       packet_send_debug("%.100s, line %lu: missing end quote",  
                                         SSH_USER_PERMITTED_KEYS, linenum);  
                       continue;  
                     }  
                   forced_command[i] = 0;  
                   packet_send_debug("Forced command: %.900s", forced_command);  
                   options++;  
                   goto next_option;  
                 }                  }
               cp = "environment=\"";                  /* Break out of the loop if authentication was successful;
               if (strncmp(options, cp, strlen(cp)) == 0)                     otherwise continue searching. */
                 {                  if (authenticated)
                   int i;  
                   char *s;  
                   struct envstring *new_envstring;  
                   options += strlen(cp);  
                   s = xmalloc(strlen(options) + 1);  
                   i = 0;  
                   while (*options)  
                     {  
                       if (*options == '"')  
                         break;                          break;
                       if (*options == '\\' && options[1] == '"')  
                         {  
                           options += 2;  
                           s[i++] = '"';  
                           continue;  
                         }  
                       s[i++] = *options++;  
                     }  
                   if (!*options)  
                     {  
                       debug("%.100s, line %lu: missing end quote",  
                             SSH_USER_PERMITTED_KEYS, linenum);  
                       packet_send_debug("%.100s, line %lu: missing end quote",  
                                         SSH_USER_PERMITTED_KEYS, linenum);  
                       continue;  
                     }  
                   s[i] = 0;  
                   packet_send_debug("Adding to environment: %.900s", s);  
                   debug("Adding to environment: %.900s", s);  
                   options++;  
                   new_envstring = xmalloc(sizeof(struct envstring));  
                   new_envstring->s = s;  
                   new_envstring->next = custom_environment;  
                   custom_environment = new_envstring;  
                   goto next_option;  
                 }  
               cp = "from=\"";  
               if (strncmp(options, cp, strlen(cp)) == 0)  
                 {  
                   char *patterns = xmalloc(strlen(options) + 1);  
                   int i;  
                   options += strlen(cp);  
                   i = 0;  
                   while (*options)  
                     {  
                       if (*options == '"')  
                         break;  
                       if (*options == '\\' && options[1] == '"')  
                         {  
                           options += 2;  
                           patterns[i++] = '"';  
                           continue;  
                         }  
                       patterns[i++] = *options++;  
                     }  
                   if (!*options)  
                     {  
                       debug("%.100s, line %lu: missing end quote",  
                             SSH_USER_PERMITTED_KEYS, linenum);  
                       packet_send_debug("%.100s, line %lu: missing end quote",  
                                         SSH_USER_PERMITTED_KEYS, linenum);  
                       continue;  
                     }  
                   patterns[i] = 0;  
                   options++;  
                   if (!match_hostname(get_canonical_hostname(), patterns,  
                                      strlen(patterns)) &&  
                       !match_hostname(get_remote_ipaddr(), patterns,  
                                       strlen(patterns)))  
                     {  
                       log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).",  
                           pw->pw_name, get_canonical_hostname(),  
                           get_remote_ipaddr());  
                       packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",  
                                         get_canonical_hostname());  
                       xfree(patterns);  
                       authenticated = 0;  
                       break;  
                     }  
                   xfree(patterns);  
                   /* Host name matches. */  
                   goto next_option;  
                 }  
             bad_option:  
               /* Unknown option. */  
               log("Bad options in %.100s file, line %lu: %.50s",  
                   SSH_USER_PERMITTED_KEYS, linenum, options);  
               packet_send_debug("Bad options in %.100s file, line %lu: %.50s",  
                                 SSH_USER_PERMITTED_KEYS, linenum, options);  
               authenticated = 0;  
               break;  
   
             next_option:  
               /* Skip the comma, and move to the next option (or break out  
                  if there are no more). */  
               if (!*options)  
                 fatal("Bugs in auth-rsa.c option processing.");  
               if (*options == ' ' || *options == '\t')  
                 break; /* End of options. */  
               if (*options != ',')  
                 goto bad_option;  
               options++;  
               /* Process the next option. */  
               continue;  
             }  
         }          }
   
       /* Break out of the loop if authentication was successful; otherwise          /* Restore the privileged uid. */
          continue searching. */          restore_uid();
       if (authenticated)  
         break;  
     }  
   
   /* Restore the privileged uid. */          /* Close the file. */
   restore_uid();          fclose(f);
   
   /* Close the file. */          /* Clear any mp-int variables. */
   fclose(f);          BN_clear_free(n);
           BN_clear_free(e);
   /* Clear any mp-int variables. */  
   BN_clear_free(n);  
   BN_clear_free(e);  
   
   if (authenticated)          if (authenticated)
     packet_send_debug("RSA authentication accepted.");                  packet_send_debug("RSA authentication accepted.");
   
   /* Return authentication result. */          /* Return authentication result. */
   return authenticated;          return authenticated;
 }  }

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12