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

Diff for /src/usr.bin/ssh/misc.c between version 1.113 and 1.114

version 1.113, 2017/08/18 05:48:04 version 1.114, 2017/10/21 23:06:24
Line 375 
Line 375 
  * Search for next delimiter between hostnames/addresses and ports.   * Search for next delimiter between hostnames/addresses and ports.
  * Argument may be modified (for termination).   * Argument may be modified (for termination).
  * Returns *cp if parsing succeeds.   * Returns *cp if parsing succeeds.
  * *cp is set to the start of the next delimiter, if one was found.   * *cp is set to the start of the next field, if one was found.
    * The delimiter char, if present, is stored in delim.
  * If this is the last field, *cp is set to NULL.   * If this is the last field, *cp is set to NULL.
  */   */
 char *  static char *
 hpdelim(char **cp)  hpdelim2(char **cp, char *delim)
 {  {
         char *s, *old;          char *s, *old;
   
Line 402 
Line 403 
   
         case ':':          case ':':
         case '/':          case '/':
                   if (delim != NULL)
                           *delim = *s;
                 *s = '\0';      /* terminate */                  *s = '\0';      /* terminate */
                 *cp = s + 1;                  *cp = s + 1;
                 break;                  break;
Line 414 
Line 417 
 }  }
   
 char *  char *
   hpdelim(char **cp)
   {
           return hpdelim2(cp, NULL);
   }
   
   char *
 cleanhostname(char *host)  cleanhostname(char *host)
 {  {
         if (*host == '[' && host[strlen(host) - 1] == ']') {          if (*host == '[' && host[strlen(host) - 1] == ']') {
Line 447 
Line 456 
 }  }
   
 /*  /*
    * Parse a [user@]host:[path] string.
    * Caller must free returned user, host and path.
    * Any of the pointer return arguments may be NULL (useful for syntax checking).
    * If user was not specified then *userp will be set to NULL.
    * If host was not specified then *hostp will be set to NULL.
    * If path was not specified then *pathp will be set to ".".
    * Returns 0 on success, -1 on failure.
    */
   int
   parse_user_host_path(const char *s, char **userp, char **hostp, char **pathp)
   {
           char *user = NULL, *host = NULL, *path = NULL;
           char *sdup, *tmp;
           int ret = -1;
   
           if (userp != NULL)
                   *userp = NULL;
           if (hostp != NULL)
                   *hostp = NULL;
           if (pathp != NULL)
                   *pathp = NULL;
   
           sdup = tmp = xstrdup(s);
   
           /* Check for remote syntax: [user@]host:[path] */
           if ((tmp = colon(sdup)) == NULL)
                   goto out;
   
           /* Extract optional path */
           *tmp++ = '\0';
           if (*tmp == '\0')
                   tmp = ".";
           path = xstrdup(tmp);
   
           /* Extract optional user and mandatory host */
           tmp = strrchr(sdup, '@');
           if (tmp != NULL) {
                   *tmp++ = '\0';
                   host = xstrdup(cleanhostname(tmp));
                   if (*sdup != '\0')
                           user = xstrdup(sdup);
           } else {
                   host = xstrdup(cleanhostname(sdup));
                   user = NULL;
           }
   
           /* Success */
           if (userp != NULL) {
                   *userp = user;
                   user = NULL;
           }
           if (hostp != NULL) {
                   *hostp = host;
                   host = NULL;
           }
           if (pathp != NULL) {
                   *pathp = path;
                   path = NULL;
           }
           ret = 0;
   out:
           free(sdup);
           free(user);
           free(host);
           free(path);
           return ret;
   }
   
   /*
  * Parse a [user@]host[:port] string.   * Parse a [user@]host[:port] string.
  * Caller must free returned user and host.   * Caller must free returned user and host.
  * Any of the pointer return arguments may be NULL (useful for syntax checking).   * Any of the pointer return arguments may be NULL (useful for syntax checking).
Line 471 
Line 549 
         if ((sdup = tmp = strdup(s)) == NULL)          if ((sdup = tmp = strdup(s)) == NULL)
                 return -1;                  return -1;
         /* Extract optional username */          /* Extract optional username */
         if ((cp = strchr(tmp, '@')) != NULL) {          if ((cp = strrchr(tmp, '@')) != NULL) {
                 *cp = '\0';                  *cp = '\0';
                 if (*tmp == '\0')                  if (*tmp == '\0')
                         goto out;                          goto out;
Line 507 
Line 585 
         return ret;          return ret;
 }  }
   
   /*
    * Converts a two-byte hex string to decimal.
    * Returns the decimal value or -1 for invalid input.
    */
   static int
   hexchar(const char *s)
   {
           unsigned char result[2];
           int i;
   
           for (i = 0; i < 2; i++) {
                   if (s[i] >= '0' && s[i] <= '9')
                           result[i] = (unsigned char)(s[i] - '0');
                   else if (s[i] >= 'a' && s[i] <= 'f')
                           result[i] = (unsigned char)(s[i] - 'a') + 10;
                   else if (s[i] >= 'A' && s[i] <= 'F')
                           result[i] = (unsigned char)(s[i] - 'A') + 10;
                   else
                           return -1;
           }
           return (result[0] << 4) | result[1];
   }
   
   /*
    * Decode an url-encoded string.
    * Returns a newly allocated string on success or NULL on failure.
    */
   static char *
   urldecode(const char *src)
   {
           char *ret, *dst;
           int ch;
   
           ret = xmalloc(strlen(src) + 1);
           for (dst = ret; *src != '\0'; src++) {
                   switch (*src) {
                   case '+':
                           *dst++ = ' ';
                           break;
                   case '%':
                           if (!isxdigit((unsigned char)src[1]) ||
                               !isxdigit((unsigned char)src[2]) ||
                               (ch = hexchar(src + 1)) == -1) {
                                   free(ret);
                                   return NULL;
                           }
                           *dst++ = ch;
                           src += 2;
                           break;
                   default:
                           *dst++ = *src;
                           break;
                   }
           }
           *dst = '\0';
   
           return ret;
   }
   
   /*
    * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
    * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
    * Either user or path may be url-encoded (but not host or port).
    * Caller must free returned user, host and path.
    * Any of the pointer return arguments may be NULL (useful for syntax checking)
    * but the scheme must always be specified.
    * If user was not specified then *userp will be set to NULL.
    * If port was not specified then *portp will be -1.
    * If path was not specified then *pathp will be set to NULL.
    * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
    */
   int
   parse_uri(const char *scheme, const char *uri, char **userp, char **hostp,
       int *portp, char **pathp)
   {
           char *uridup, *cp, *tmp, ch;
           char *user = NULL, *host = NULL, *path = NULL;
           int port = -1, ret = -1;
           size_t len;
   
           len = strlen(scheme);
           if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0)
                   return 1;
           uri += len + 3;
   
           if (userp != NULL)
                   *userp = NULL;
           if (hostp != NULL)
                   *hostp = NULL;
           if (portp != NULL)
                   *portp = -1;
           if (pathp != NULL)
                   *pathp = NULL;
   
           uridup = tmp = xstrdup(uri);
   
           /* Extract optional ssh-info (username + connection params) */
           if ((cp = strchr(tmp, '@')) != NULL) {
                   char *delim;
   
                   *cp = '\0';
                   /* Extract username and connection params */
                   if ((delim = strchr(tmp, ';')) != NULL) {
                           /* Just ignore connection params for now */
                           *delim = '\0';
                   }
                   if (*tmp == '\0') {
                           /* Empty username */
                           goto out;
                   }
                   if ((user = urldecode(tmp)) == NULL)
                           goto out;
                   tmp = cp + 1;
           }
   
           /* Extract mandatory hostname */
           if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0')
                   goto out;
           host = xstrdup(cleanhostname(cp));
           if (!valid_domain(host, 0, NULL))
                   goto out;
   
           if (tmp != NULL && *tmp != '\0') {
                   if (ch == ':') {
                           /* Convert and verify port. */
                           if ((cp = strchr(tmp, '/')) != NULL)
                                   *cp = '\0';
                           if ((port = a2port(tmp)) <= 0)
                                   goto out;
                           tmp = cp ? cp + 1 : NULL;
                   }
                   if (tmp != NULL && *tmp != '\0') {
                           /* Extract optional path */
                           if ((path = urldecode(tmp)) == NULL)
                                   goto out;
                   }
           }
   
           /* Success */
           if (userp != NULL) {
                   *userp = user;
                   user = NULL;
           }
           if (hostp != NULL) {
                   *hostp = host;
                   host = NULL;
           }
           if (portp != NULL)
                   *portp = port;
           if (pathp != NULL) {
                   *pathp = path;
                   path = NULL;
           }
           ret = 0;
    out:
           free(uridup);
           free(user);
           free(host);
           free(path);
           return ret;
   }
   
 /* function to assist building execv() arguments */  /* function to assist building execv() arguments */
 void  void
 addargs(arglist *args, char *fmt, ...)  addargs(arglist *args, char *fmt, ...)
Line 1666 
Line 1906 
         snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);          snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
 }  }
   
   /*
    * Check and optionally lowercase a domain name, also removes trailing '.'
    * Returns 1 on success and 0 on failure, storing an error message in errstr.
    */
   int
   valid_domain(char *name, int makelower, const char **errstr)
   {
           size_t i, l = strlen(name);
           u_char c, last = '\0';
           static char errbuf[256];
   
           if (l == 0) {
                   strlcpy(errbuf, "empty domain name", sizeof(errbuf));
                   goto bad;
           }
           if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) {
                   snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" "
                       "starts with invalid character", name);
                   goto bad;
           }
           for (i = 0; i < l; i++) {
                   c = tolower((u_char)name[i]);
                   if (makelower)
                           name[i] = (char)c;
                   if (last == '.' && c == '.') {
                           snprintf(errbuf, sizeof(errbuf), "domain name "
                               "\"%.100s\" contains consecutive separators", name);
                           goto bad;
                   }
                   if (c != '.' && c != '-' && !isalnum(c) &&
                       c != '_') /* technically invalid, but common */ {
                           snprintf(errbuf, sizeof(errbuf), "domain name "
                               "\"%.100s\" contains invalid characters", name);
                           goto bad;
                   }
                   last = c;
           }
           if (name[l - 1] == '.')
                   name[l - 1] = '\0';
           if (errstr != NULL)
                   *errstr = NULL;
           return 1;
   bad:
           if (errstr != NULL)
                   *errstr = errbuf;
           return 0;
   }

Legend:
Removed from v.1.113  
changed lines
  Added in v.1.114