aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pcap-int.h4
-rw-r--r--pcap-rpcap.c94
-rw-r--r--pcap.c30
-rw-r--r--pcap/pcap.h14
4 files changed, 118 insertions, 24 deletions
diff --git a/pcap-int.h b/pcap-int.h
index acb038e4..f1b97ce6 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -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);
diff --git a/pcap.c b/pcap.c
index cad84a75..92ec0706 100644
--- a/pcap.c
+++ b/pcap.c
@@ -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]