/* ** Copyright 2000-2004 University of Illinois Board of Trustees ** Copyright 2000-2004 Mark D. Roth ** All rights reserved. ** ** url.c - FTP URL parsing code ** ** Mark D. Roth */ #include #include #include #ifdef STDC_HEADERS # include #endif /* decode "%xx" hex encodings in string and write the decoded version to buf */ static int _url_decode(char *string, char *buf, size_t bufsize) { char cbuf[] = "x"; char *cp; unsigned int c; buf[0] = '\0'; while ((cp = strchr(string, '%')) != NULL) { *cp++ = '\0'; if (sscanf(cp, "%2x", &c) != 1) { errno = EINVAL; return -1; } if (strlcat(buf, string, bufsize) > bufsize) { errno = ENAMETOOLONG; return -1; } cbuf[0] = c; if (strlcat(buf, cbuf, bufsize) > bufsize) { errno = ENAMETOOLONG; return -1; } string = cp + 2; } if (strlcat(buf, string, bufsize) > bufsize) { errno = ENAMETOOLONG; return -1; } return 0; } /* parse RFC-1738 style URL and fill in caller-supplied fields */ int ftp_url_parse(char *url, struct ftp_url *ftpurl) { char newurl[sizeof(struct ftp_url)]; char *cp, *fieldp, *nextp; size_t sz; ftpurl->fu_hostname[0] = '\0'; ftpurl->fu_login[0] = '\0'; ftpurl->fu_passwd[0] = '\0'; ftpurl->fu_path[0] = '\0'; if (strlcpy(newurl, url, sizeof(newurl)) > sizeof(newurl)) { errno = ENAMETOOLONG; return -1; } nextp = newurl; if (strncmp("ftp://", newurl, 6) == 0) nextp += 6; fieldp = nextp; /* save type if present */ if ((cp = strrchr(fieldp, ';')) != NULL && strncmp(cp + 1, "type=", 5) == 0) { *cp++ = '\0'; switch (cp[5]) { case 'a': case 'i': case 'd': ftpurl->fu_type = cp[5]; break; default: errno = EINVAL; return -1; } } else ftpurl->fu_type = '?'; /* save path if present */ if ((nextp = strchr(fieldp, '/')) != NULL) *nextp++ = '\0'; if (nextp != NULL && *nextp != '\0') { if (_url_decode(nextp, ftpurl->fu_path, sizeof(ftpurl->fu_path)) == -1) return -1; sz = strlen(ftpurl->fu_path) - 1; if (sz > 0 && ftpurl->fu_path[sz] == '/') ftpurl->fu_path[sz] = '\0'; } else { if (strlcat(ftpurl->fu_path, ".", sizeof(ftpurl->fu_path)) > sizeof(ftpurl->fu_path)) { errno = ENAMETOOLONG; return -1; } } /* parse "user:pass@" if present */ if ((nextp = strchr(fieldp, '@')) != NULL && nextp != fieldp) { *nextp++ = '\0'; if ((cp = strchr(fieldp, ':')) != NULL) { *cp++ = '\0'; if (_url_decode(cp, ftpurl->fu_passwd, sizeof(ftpurl->fu_passwd)) == -1) return -1; } if (_url_decode(fieldp, ftpurl->fu_login, sizeof(ftpurl->fu_login)) == -1) return -1; fieldp = nextp; } /* what's left is the hostname */ if (_url_decode(fieldp, ftpurl->fu_hostname, sizeof(ftpurl->fu_hostname)) == -1) return -1; return 0; }