This commit adds a new key-value pair, 'punix_file_group=<user group>', to the 'other_config' column in the 'Controller' table. This new config allows user to change the punix socket file's group ownership, so that non-root process can also connect to ovs bridge.
Signed-off-by: Alex Wang <al...@nicira.com> --- lib/socket-util-unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/socket-util.h | 7 +++++ vswitchd/bridge.c | 17 ++++++++++++ vswitchd/vswitch.xml | 16 +++++++++++ 4 files changed, 110 insertions(+) diff --git a/lib/socket-util-unix.c b/lib/socket-util-unix.c index afab195..40105cb 100644 --- a/lib/socket-util-unix.c +++ b/lib/socket-util-unix.c @@ -19,6 +19,7 @@ #include <errno.h> #include <fcntl.h> #include <net/if.h> +#include <grp.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> @@ -49,6 +50,75 @@ VLOG_DEFINE_THIS_MODULE(socket_util_unix); * space for a null terminator. */ #define MAX_UN_LEN (sizeof(((struct sockaddr_un *) 0)->sun_path) - 1) +/* Given 'group_name', returns true if the corresponding 'group' + * is found and saves the group id into 'gid'. Returns false if + * cannot find 'group'. */ +static bool +query_group_gid(const char *group_name, gid_t *gid) +{ + struct group group; + struct group *result; + size_t buflen; + char *buf; + + if (!group_name) { + return false; + } + + buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + buf = xmalloc(buflen * sizeof *buf); + getgrnam_r(group_name, &group, buf, buflen, &result); + + if (!result) { + VLOG_ERR("cannot retrieve group info for specified group " + "(%s) : %s", + group_name, + errno ? ovs_strerror(errno) : "group not found"); + } else { + *gid = result->gr_gid; + } + free(buf); + + return result; +} + +/* Sets the unix domain socket file's group ownership to 'group'. */ +void +unix_socket_set_file_group(const char *path, const char *group) +{ + struct stat info; + gid_t gid = 0; + + if (stat(path, &info)) { + VLOG_WARN("set (%s) group fails : cannot find file (%s)", + path, path); + return; + } + + if (!query_group_gid(group ? group : "root", &gid)) { + VLOG_WARN("set (%s) group fails : cannot find group (%s)", + path, group ? group : "root"); + return; + } + + /* Returns if current group id is same as desired group id. */ + if (gid == info.st_gid) { + return; + } else { + /* Changes group ownership to 'gid'. */ + if (chown(path, -1, gid)) { + VLOG_WARN("chown (%s) group to (%s) fails: %s", + path, group ? group : "root", ovs_strerror(errno)); + return; + } + if (chmod(path, 0770)) { + VLOG_WARN("chmod (%s) permission to 0700 fails: %s", + path, ovs_strerror(errno)); + return; + } + } +} + void xpipe(int fds[2]) { diff --git a/lib/socket-util.h b/lib/socket-util.h index 8015c7f..77c251c 100644 --- a/lib/socket-util.h +++ b/lib/socket-util.h @@ -81,6 +81,7 @@ void xpipe_nonblocking(int fds[2]); int drain_rcvbuf(int fd); +void unix_socket_set_file_group(const char *path, const char *group); int make_unix_socket(int style, bool nonblock, const char *bind_path, const char *connect_path); int get_unix_name_len(socklen_t sun_len); @@ -95,6 +96,12 @@ int af_inet_ifreq_ioctl(const char *name, struct ifreq *, #endif #ifdef _WIN32 +static inline void unix_socket_set_file_group(const char *path, + const char *group) +{ + return; +} + static inline int make_unix_socket(int style, bool nonblock, const char *bind_path, const char *connect_path) diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index b95610d..c931247 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -3507,6 +3507,7 @@ bridge_configure_remotes(struct bridge *br, enum ofproto_fail_mode fail_mode; + const char **punix_file_groups; struct ofproto_controller *ocs; size_t n_ocs; size_t i; @@ -3528,9 +3529,12 @@ bridge_configure_remotes(struct bridge *br, n_controllers = bridge_get_controllers(br, &controllers); + punix_file_groups = + xmalloc((n_controllers + 1) * sizeof *punix_file_groups); ocs = xmalloc((n_controllers + 1) * sizeof *ocs); n_ocs = 0; + punix_file_groups[n_ocs] = NULL; bridge_ofproto_controller_for_mgmt(br, &ocs[n_ocs++]); for (i = 0; i < n_controllers; i++) { struct ovsrec_controller *c = controllers[i]; @@ -3584,6 +3588,8 @@ bridge_configure_remotes(struct bridge *br, bridge_configure_local_iface_netdev(br, c); bridge_ofproto_controller_from_ovsrec(c, &ocs[n_ocs]); + punix_file_groups[n_ocs] = smap_get(&c->other_config, + "punix_file_group"); if (disable_in_band) { ocs[n_ocs].band = OFPROTO_OUT_OF_BAND; } @@ -3592,6 +3598,17 @@ bridge_configure_remotes(struct bridge *br, ofproto_set_controllers(br->ofproto, ocs, n_ocs, bridge_get_allowed_versions(br)); + + for (i = 0; i < n_ocs; i++) { + if (!strncmp(ocs[i].target, "punix:", 6)) { + const char *path = ocs[i].target + 6; + const char *group = punix_file_groups[i]; + + unix_socket_set_file_group(path, group); + } + } + + free(punix_file_groups); free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */ free(ocs); diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 457f34a..6f6e0ed 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -3989,6 +3989,22 @@ a default value of 48 is chosen. Valid DSCP values must be in the range 0 to 63. </column> + + <column name="other_config" key="punix_file_group" + type='{"type": "string"}'> + <p> + When connection method in <ref column="target"/> is + <code>punix</code>, this config specifies the user group to which + the group ownership for 'punix' (unix domain socket) file created + by ovs will be applied. Also, the file's access permission will be + changed to '0770'. + </p> + <p> + By default, the 'punix' file is associated with the 'root' + group and have access permission '0700'. If this config is + not specified or specified as 'root', the default is restored. + </p> + </column> </group> -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev