From 52d979e29d20be972587e655c97a550c805ae721 Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Sat, 18 Oct 2014 13:46:44 -0600 Subject: [PATCH 1/3] Add a standard API for fetching process name, uid, and gid. --- pxyconn.c | 12 +++++++----- sys.c | 37 +++++++++++++++++++++++++++++++++++++ sys.h | 2 ++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/pxyconn.c b/pxyconn.c index 956d769..9c48ddc 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -1880,11 +1880,13 @@ pxy_conn_setup(evutil_socket_t fd, goto memout; if (ctx->local_pid != -1) { - // TODO - #include - char name[MAXPATHLEN]; - proc_pidpath(ctx->local_pid, name, sizeof(name)); - log_err_printf("Matched socket to process %s\n", name); + char *name = NULL; + uid_t uid; + gid_t gid; + + if (sys_proc_info(ctx->local_pid, &name, &uid, &gid) == 0) { + log_err_printf("Matched socket to process %s (uid=%lld, gid=%lld)\n", name, (long long) uid, (long long) gid); + } } } diff --git a/sys.c b/sys.c index b6aceb8..1683e73 100644 --- a/sys.c +++ b/sys.c @@ -50,6 +50,10 @@ #include #endif /* !_SC_NPROCESSORS_ONLN */ +#if HAVE_DARWIN_LIBPROC +#include +#endif + #include /* @@ -193,6 +197,39 @@ sys_pidf_close(int fd, const char *fn) close(fd); } +/* + * Fetch process info for the given pid. + * On success, returns 0 and fills in path, uid, and gid. + * Caller must free returned path string. + * Returns -1 on failure, or if unsupported on this platform. + */ +int +sys_proc_info(pid_t pid, char **path, uid_t *uid, gid_t *gid) { +#if HAVE_DARWIN_LIBPROC + /* fetch process structure */ + struct proc_bsdinfo bsd_info; + if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &bsd_info, sizeof(bsd_info)) == -1) { + return -1; + } + + *uid = bsd_info.pbi_uid; + *gid = bsd_info.pbi_gid; + + /* fetch process path */ + *path = malloc(PROC_PIDPATHINFO_MAXSIZE); + int path_len = proc_pidpath(pid, *path, PROC_PIDPATHINFO_MAXSIZE); + if (path_len == -1) { + free(*path); + return -1; + } + + return 0; +#else + /* unsupported */ + return -1; +#endif +} + /* * Parse an ascii host/IP and port tuple into a sockaddr_storage. * On success, returns address family and fills in addr, addrlen. diff --git a/sys.h b/sys.h index 9a05f7b..f4f2f1c 100644 --- a/sys.h +++ b/sys.h @@ -41,6 +41,8 @@ int sys_pidf_open(const char *) NONNULL(1) WUNRES; int sys_pidf_write(int) WUNRES; void sys_pidf_close(int, const char *) NONNULL(2); +int sys_proc_info(pid_t, char **, uid_t *, gid_t *) WUNRES; + int sys_sockaddr_parse(struct sockaddr_storage *, socklen_t *, char *, char *, int, int) NONNULL(1,2,3,4) WUNRES; char * sys_sockaddr_str(struct sockaddr *, socklen_t) NONNULL(1) MALLOC; From 5ed49c498596995c79a5b7fda3d1ee1eb09ce8ec Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Sat, 18 Oct 2014 14:16:50 -0600 Subject: [PATCH 2/3] Implement user and group name lookup. --- pxyconn.c | 38 +++++++++++++++++++++++++++---------- sys.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sys.h | 3 +++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/pxyconn.c b/pxyconn.c index 9c48ddc..ceea6e8 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -111,8 +111,10 @@ typedef struct pxy_conn_ctx { unsigned int enomem : 1; /* 1 if out of memory */ unsigned int sni_peek_retries : 6; /* max 64 SNI parse retries */ - /* local process id, or -1 */ - pid_t local_pid; + /* local process ids, or -1 */ + pid_t pid; + uid_t uid; + gid_t gid; /* server name indicated by client in SNI TLS extension */ char *sni; @@ -136,6 +138,11 @@ typedef struct pxy_conn_ctx { char *ssl_names; char *ssl_orignames; + /* log strings from process info */ + char *exec_path; + char *user; + char *group; + /* content log context */ log_content_ctx_t logctx; @@ -176,7 +183,7 @@ pxy_conn_ctx_new(proxyspec_t *spec, opts_t *opts, ctx->spec = spec; ctx->opts = opts; ctx->fd = fd; - ctx->local_pid = -1; + ctx->pid = -1; ctx->thridx = pxy_thrmgr_attach(thrmgr, &ctx->evbase, &ctx->dnsbase); ctx->thrmgr = thrmgr; #ifdef DEBUG_PROXY @@ -233,6 +240,15 @@ pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) if (ctx->ssl_orignames) { free(ctx->ssl_orignames); } + if (ctx->exec_path) { + free(ctx->exec_path); + } + if (ctx->user) { + free(ctx->user); + } + if (ctx->group) { + free(ctx->group); + } if (ctx->origcrt) { X509_free(ctx->origcrt); } @@ -1849,7 +1865,7 @@ pxy_conn_setup(evutil_socket_t fd, /* NAT engine lookup */ ctx->addrlen = sizeof(struct sockaddr_storage); if (spec->natlookup((struct sockaddr *)&ctx->addr, - &ctx->addrlen, &ctx->local_pid, fd, + &ctx->addrlen, &ctx->pid, fd, peeraddr, peeraddrlen) == -1) { log_err_printf("Connection not found in NAT " "state table, aborting connection\n"); @@ -1879,13 +1895,15 @@ pxy_conn_setup(evutil_socket_t fd, if (!ctx->src_str) goto memout; - if (ctx->local_pid != -1) { - char *name = NULL; - uid_t uid; - gid_t gid; + if (ctx->pid != -1) { + if (sys_proc_info(ctx->pid, &ctx->exec_path, &ctx->uid, &ctx->gid) == 0) { + ctx->user = sys_user_str(ctx->uid); + ctx->group = sys_group_str(ctx->gid); + if (!ctx->user || !ctx->group) { + goto memout; + } - if (sys_proc_info(ctx->local_pid, &name, &uid, &gid) == 0) { - log_err_printf("Matched socket to process %s (uid=%lld, gid=%lld)\n", name, (long long) uid, (long long) gid); + log_err_printf("Matched socket to process %s (user=%s, group=%s)\n", ctx->exec_path, ctx->user, ctx->group); } } } diff --git a/sys.c b/sys.c index 1683e73..3d54f68 100644 --- a/sys.c +++ b/sys.c @@ -230,6 +230,62 @@ sys_proc_info(pid_t pid, char **path, uid_t *uid, gid_t *gid) { #endif } +/* + * Converts a local uid into a printable string representation. + * Returns an allocated buffer which must be freed by caller, or NULL on error. + */ +char * +sys_user_str(uid_t uid) +{ + int bufsize; + if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) { + log_err_printf("failed to get password bufsize: %s\n", + strerror(errno)); + return NULL; + } + + char buffer[bufsize]; + struct passwd pwd, *result = NULL; + if (getpwuid_r(uid, &pwd, buffer, bufsize, &result) != 0 || !result) { + /* no entry found; return the integer representation */ + char *name; + if (asprintf(&name, "%llu", (long long) uid) == -1) { + return NULL; + } + return name; + } + + return strdup(pwd.pw_name); +} + +/* + * Converts a local gid into a printable string representation. + * Returns an allocated buffer which must be freed by caller, or NULL on error. + */ +char * +sys_group_str(gid_t gid) +{ + int bufsize; + if ((bufsize = sysconf(_SC_GETGR_R_SIZE_MAX)) == -1) { + log_err_printf("failed to get group bufsize: %s\n", + strerror(errno)); + return NULL; + } + + char buffer[bufsize]; + struct group grp, *result = NULL; + if (getgrgid_r(gid, &grp, buffer, bufsize, &result) != 0 || !result) { + /* no entry found; return the integer representation */ + char *name; + if (asprintf(&name, "%llu", (long long) gid) == -1) { + return NULL; + } + return name; + } + + return strdup(grp.gr_name); +} + /* * Parse an ascii host/IP and port tuple into a sockaddr_storage. * On success, returns address family and fills in addr, addrlen. diff --git a/sys.h b/sys.h index f4f2f1c..537ab1b 100644 --- a/sys.h +++ b/sys.h @@ -43,6 +43,9 @@ void sys_pidf_close(int, const char *) NONNULL(2); int sys_proc_info(pid_t, char **, uid_t *, gid_t *) WUNRES; +char * sys_user_str(uid_t) WUNRES MALLOC; +char * sys_group_str(gid_t) WUNRES MALLOC; + int sys_sockaddr_parse(struct sockaddr_storage *, socklen_t *, char *, char *, int, int) NONNULL(1,2,3,4) WUNRES; char * sys_sockaddr_str(struct sockaddr *, socklen_t) NONNULL(1) MALLOC; From efca8d73c9384e5015f7c7815cdefdf12f121718 Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Fri, 7 Nov 2014 16:38:50 -0700 Subject: [PATCH 3/3] Remove debugging statement. --- pxyconn.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pxyconn.c b/pxyconn.c index 246546f..9946d96 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -1977,8 +1977,6 @@ pxy_conn_setup(evutil_socket_t fd, if (!ctx->user || !ctx->group) { goto memout; } - - log_err_printf("Matched socket to process %s (user=%s, group=%s)\n", ctx->exec_path, ctx->user, ctx->group); } } }