diff options
-rw-r--r-- | pcap-int.h | 4 | ||||
-rw-r--r-- | pcap-rpcap.c | 94 | ||||
-rw-r--r-- | pcap.c | 30 | ||||
-rw-r--r-- | pcap/pcap.h | 14 |
4 files changed, 118 insertions, 24 deletions
@@ -651,9 +651,9 @@ int pcap_strcasecmp(const char *, const char *); * rpcaps://). */ int pcap_createsrcstr_ex(char *, int, const char *, const char *, - const char *, unsigned char, char *); + const char *, const char *, unsigned char, char *); int pcap_parsesrcstr_ex(const char *, int *, char *, char *, - char *, unsigned char *, char *); + char *, char *, unsigned char *, char *); #ifdef YYDEBUG extern int pcap_debug; diff --git a/pcap-rpcap.c b/pcap-rpcap.c index 66c43559..a4dc945c 100644 --- a/pcap-rpcap.c +++ b/pcap-rpcap.c @@ -2140,6 +2140,79 @@ novers: return -1; } +/* non-alphanumeric unreserved characters plus sub-delims (RFC3986) */ +static const char userinfo_allowed_symbols[] = "-._~!&'()*+,;="; + +/* + * This function is a thin wrapper around rpcap_doauth which will use an auth + * struct created from a username and password parsed out of the userinfo + * portion of a URI. + */ +static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8 *ver, const char *userinfo, char *errbuf) +{ + struct pcap_rmtauth auth; + const char *ptr; + char *buf, username[256], password[256]; + + auth.type = RPCAP_RMTAUTH_PWD; + auth.username = username; + auth.password = password; + buf = username; + + username[0] = password[0] = '\0'; + + if ((ptr = userinfo) != NULL) + { + for (int pos = -1; (buf[++pos] = *ptr) != '\0'; ++ptr) + { + /* handle %xx encoded characters */ + if (*ptr == '%') + { + /* the pedantic thing to do here would be throwing an error on + * a sequence like `%hi', however a lot of common tools just accept + * such malarkey, so... probably it will be fine? */ + if (sscanf(ptr, "%%%02hhx", (unsigned char *)(buf+pos)) == 1) + ptr += 2; + /* other implemntations aside, rejecting null bytes seems prudent */ + if (buf[pos] == '\0') + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid escape `%%00` in userinfo"); + return -1; + } + } + else if (*ptr == ':' && buf == username) + { + /* terminate username string and switch to password string */ + buf[pos] = '\0'; + buf = password; + pos = -1; + } + /* constrain to characters allowed by RFC3986 */ + else if (*ptr >= 'A' && *ptr <= 'Z') + continue; + else if (*ptr >= 'a' && *ptr <= 'z') + continue; + else if (*ptr >= '0' && *ptr <= '9') + continue; + else if (*ptr < ' ' || *ptr > '~') + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid character `\\%o` in userinfo", *ptr); + return -1; + } + else if (strchr(userinfo_allowed_symbols, *ptr) == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid character `%c` in userinfo", *ptr); + return -1; + } + } + + return rpcap_doauth(sockctrl, ssl, ver, &auth, errbuf); + } + + return rpcap_doauth(sockctrl, ssl, ver, NULL, errbuf); +} + + /* We don't currently support non-blocking mode. */ static int pcap_getnonblock_rpcap(pcap_t *p) @@ -2164,15 +2237,18 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, char *iface, char *errbuf) { int type; + int auth_result; + char userinfo[512]; /* 256 characters each for username and password */ struct activehosts *activeconn; /* active connection, if there is one */ int error; /* 1 if rpcap_remoteact_getsock got an error */ + userinfo[0] = '\0'; /* * Determine the type of the source (NULL, file, local, remote). * You must have a valid source string even if we're in active mode, * because otherwise the call to the following function will fail. */ - if (pcap_parsesrcstr_ex(source, &type, host, port, iface, uses_sslp, + if (pcap_parsesrcstr_ex(source, &type, userinfo, host, port, iface, uses_sslp, errbuf) == -1) return -1; @@ -2277,8 +2353,18 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, #endif } - if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth, - errbuf) == -1) + if (auth == NULL && *userinfo != '\0') + { + auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp, protocol_versionp, + userinfo, errbuf); + } + else + { + auth_result = rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth, + errbuf); + } + + if (auth_result == -1) { #ifdef HAVE_OPENSSL if (*sslp) @@ -2622,7 +2708,7 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i /* Create the new device identifier */ if (pcap_createsrcstr_ex(tmpstring2, PCAP_SRC_IFREMOTE, - host, port, tmpstring, uses_ssl, errbuf) == -1) + NULL, host, port, tmpstring, uses_ssl, errbuf) == -1) goto error; dev->name = strdup(tmpstring2); @@ -2063,8 +2063,8 @@ pcap_parse_source(const char *source, char **schemep, char **userinfop, } int -pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port, - const char *name, unsigned char uses_ssl, char *errbuf) +pcap_createsrcstr_ex(char *source, int type, const char *userinfo, const char *host, + const char *port, const char *name, unsigned char uses_ssl, char *errbuf) { switch (type) { @@ -2084,6 +2084,11 @@ pcap_createsrcstr_ex(char *source, int type, const char *host, const char *port, (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING), PCAP_BUF_SIZE); if (host != NULL && *host != '\0') { + if (userinfo != NULL && *userinfo != '\0') { + pcap_strlcat(source, userinfo, PCAP_BUF_SIZE); + pcap_strlcat(source, "@", PCAP_BUF_SIZE); + } + if (strchr(host, ':') != NULL) { /* * The host name contains a colon, so it's @@ -2133,16 +2138,18 @@ int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf) { - return (pcap_createsrcstr_ex(source, type, host, port, name, 0, errbuf)); + return (pcap_createsrcstr_ex(source, type, NULL, host, port, name, 0, errbuf)); } int -pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port, - char *name, unsigned char *uses_ssl, char *errbuf) +pcap_parsesrcstr_ex(const char *source, int *type, char *userinfo, char *host, + char *port, char *name, unsigned char *uses_ssl, char *errbuf) { char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath; /* Initialization stuff */ + if (userinfo) + *userinfo = '\0'; if (host) *host = '\0'; if (port) @@ -2191,13 +2198,10 @@ pcap_parsesrcstr_ex(const char *source, int *type, char *host, char *port, * pcap_parse_source() has already handled the case of * rpcap[s]://device */ - if (host && tmphost) { - if (tmpuserinfo) - snprintf(host, PCAP_BUF_SIZE, "%s@%s", - tmpuserinfo, tmphost); - else - pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE); - } + if (userinfo && tmpuserinfo) + pcap_strlcpy(userinfo, tmpuserinfo, PCAP_BUF_SIZE); + if (host && tmphost) + pcap_strlcpy(host, tmphost, PCAP_BUF_SIZE); if (port && tmpport) pcap_strlcpy(port, tmpport, PCAP_BUF_SIZE); if (name && tmppath) @@ -2248,7 +2252,7 @@ int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf) { - return (pcap_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf)); + return (pcap_parsesrcstr_ex(source, type, NULL, host, port, name, NULL, errbuf)); } #endif diff --git a/pcap/pcap.h b/pcap/pcap.h index 3a819f04..ae114b5a 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -924,18 +924,21 @@ PCAP_API const char *pcap_lib_version(void); #define PCAP_SRC_IFREMOTE 4 /* interface on a remote host, using RPCAP */ /* - * The formats allowed by pcap_open() are the following: + * The formats allowed by pcap_open() are the following (optional parts in []): * - file://path_and_filename [opens a local file] * - rpcap://devicename [opens the selected device available on the local host, without using the RPCAP protocol] - * - rpcap://host/devicename [opens the selected device available on a remote host] - * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + * - rpcap://[username:password@]host[:port]/devicename [opens the selected device available on a remote host] + * - username and password, if present, will be used to authenticate to the remote host + * - port, if present, will specify a port for RPCAP rather than using the default * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged] * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged] * - * The formats allowed by the pcap_findalldevs_ex() are the following: + * The formats allowed by the pcap_findalldevs_ex() are the following (optional parts in []): * - file://folder/ [lists all the files in the given folder] * - rpcap:// [lists all local adapters] - * - rpcap://host:port/ [lists the devices available on a remote host] + * - rpcap://[username:password@]host[:port]/ [lists the devices available on a remote host] + * - username and password, if present, will be used to authenticate to the remote host + * - port, if present, will specify a port for RPCAP rather than using the default * * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable * SSL (if it has been compiled in). @@ -952,6 +955,7 @@ PCAP_API const char *pcap_lib_version(void); * Here you find some allowed examples: * - rpcap://host.foo.bar/devicename [everything literal, no port number] * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + * - rpcap://root:hunter2@host.foo.bar/devicename [everything literal, with username/password] * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] |