aboutsummaryrefslogtreecommitdiffstats
path: root/main/asterisk.c
diff options
context:
space:
mode:
authoreliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-01 18:52:14 +0000
committereliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-01 18:52:14 +0000
commitc3bceb968b01e897185cf8910893939e72c445d0 (patch)
tree35cdf9c8ac4353b858aa5ad558e8b9b6830cad7c /main/asterisk.c
parent14324a5259f64e532e44f0acf1684555b88369bb (diff)
Introduce CLI permissions.
Based on cli_permissions.conf configuration file, we are able to permit or deny cli commands based on some patterns and the local user and group running rasterisk. (Sorry if I missed some of the testers). Reviewboard: http://reviewboard.digium.com/r/11/ (closes issue #11123) Reported by: eliel Tested by: eliel, IgorG, Laureano, otherwiseguy, mvanbaak git-svn-id: http://svn.digium.com/svn/asterisk/trunk@160062 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/asterisk.c')
-rw-r--r--main/asterisk.c86
1 files changed, 74 insertions, 12 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index 00b8df1e5..bef3cba49 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -176,6 +176,8 @@ struct console {
int p[2]; /*!< Pipe */
pthread_t t; /*!< Thread of handler */
int mute; /*!< Is the console muted for logs */
+ int uid; /*!< Remote user ID. */
+ int gid; /*!< Remote group ID. */
int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
};
@@ -988,6 +990,48 @@ static void network_verboser(const char *s)
static pthread_t lthread;
+/*!
+ * \brief read() function supporting the reception of user credentials.
+ *
+ * \param fd Socket file descriptor.
+ * \param buffer Receive buffer.
+ * \param size 'buffer' size.
+ * \param con Console structure to set received credentials
+ * \retval -1 on error
+ * \retval the number of bytes received on success.
+ */
+static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
+{
+#if defined(SO_PEERCRED)
+ struct ucred cred;
+ socklen_t len = sizeof(cred);
+#endif
+ int result, uid, gid;
+
+ result = read(fd, buffer, size);
+ if (result < 0) {
+ return result;
+ }
+
+#if defined(SO_PEERCRED)
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
+ return result;
+ }
+ uid = cred.uid;
+ gid = cred.gid;
+#elif defined(HAVE_GETPEEREID)
+ if (getpeereid(fd, &uid, &gid)) {
+ return result;
+ }
+#else
+ return result;
+#endif
+ con->uid = uid;
+ con->gid = gid;
+
+ return result;
+}
+
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
@@ -1015,19 +1059,19 @@ static void *netconsole(void *vconsole)
continue;
}
if (fds[0].revents) {
- res = read(con->fd, tmp, sizeof(tmp));
+ res = read_credentials(con->fd, tmp, sizeof(tmp), con);
if (res < 1) {
break;
}
tmp[res] = 0;
if (strncmp(tmp, "cli quit after ", 15) == 0) {
- ast_cli_command_multiple(con->fd, res - 15, tmp + 15);
+ ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
break;
}
- ast_cli_command_multiple(con->fd, res, tmp);
+ ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
}
if (fds[1].revents) {
- res = read(con->p[0], tmp, sizeof(tmp));
+ res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
if (res < 1) {
ast_log(LOG_ERROR, "read returned %d\n", res);
break;
@@ -1072,8 +1116,19 @@ static void *listener(void *unused)
if (errno != EINTR)
ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
} else {
- for (x = 0; x < AST_MAX_CONNECTS; x++) {
- if (consoles[x].fd < 0) {
+#if !defined(SO_PASSCRED)
+ {
+#else
+ int sckopt = 1;
+ /* turn on socket credentials passing. */
+ if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
+ ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
+ } else {
+#endif
+ for (x = 0; x < AST_MAX_CONNECTS; x++) {
+ if (consoles[x].fd >= 0) {
+ continue;
+ }
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
consoles[x].fd = -1;
@@ -1085,6 +1140,10 @@ static void *listener(void *unused)
fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
consoles[x].fd = s;
consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
+ /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
+ to know if the user didn't send the credentials. */
+ consoles[x].uid = -2;
+ consoles[x].gid = -2;
if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
close(consoles[x].p[0]);
@@ -1095,13 +1154,13 @@ static void *listener(void *unused)
}
break;
}
+ if (x >= AST_MAX_CONNECTS) {
+ fdprint(s, "No more connections allowed\n");
+ ast_log(LOG_WARNING, "No more connections allowed\n");
+ close(s);
+ } else if (consoles[x].fd > -1)
+ ast_verb(3, "Remote UNIX connection\n");
}
- if (x >= AST_MAX_CONNECTS) {
- fdprint(s, "No more connections allowed\n");
- ast_log(LOG_WARNING, "No more connections allowed\n");
- close(s);
- } else if (consoles[x].fd > -1)
- ast_verb(3, "Remote UNIX connection\n");
}
}
return NULL;
@@ -3350,6 +3409,9 @@ int main(int argc, char *argv[])
exit(1);
}
+ /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
+ ast_cli_perms_init(0);
+
/* AMI is initialized after loading modules because of a potential
* conflict between issuing a module reload from manager and
* registering manager actions. This will cause reversed locking