2010-12-20 12:29:10 -08:00
|
|
|
/*
|
2011-02-22 03:51:16 -08:00
|
|
|
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
|
|
|
* Copyright 2009-2010 Canonical Ltd.
|
|
|
|
*
|
|
|
|
* The libapparmor library is licensed under the terms of the GNU
|
|
|
|
* Lesser General Public License, version 2.1. Please see the file
|
|
|
|
* COPYING.LGPL.
|
|
|
|
*
|
2011-02-23 14:02:45 -08:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
2011-02-22 03:51:16 -08:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2007-07-28 15:41:04 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/syscall.h>
|
2011-08-09 06:47:40 -07:00
|
|
|
#include <sys/socket.h>
|
2007-07-28 15:41:04 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2010-02-11 15:38:24 -08:00
|
|
|
#include <stdarg.h>
|
2011-08-09 06:48:17 -07:00
|
|
|
#include <mntent.h>
|
2007-07-28 15:41:04 +00:00
|
|
|
|
2011-08-09 06:48:56 -07:00
|
|
|
#include "apparmor.h"
|
|
|
|
|
2011-05-27 14:20:03 -07:00
|
|
|
/* some non-Linux systems do not define a static value */
|
|
|
|
#ifndef PATH_MAX
|
|
|
|
# define PATH_MAX 4096
|
|
|
|
#endif
|
|
|
|
|
2007-08-16 04:19:54 +00:00
|
|
|
#define symbol_version(real, name, version) \
|
|
|
|
__asm__ (".symver " #real "," #name "@" #version)
|
|
|
|
#define default_symbol_version(real, name, version) \
|
|
|
|
__asm__ (".symver " #real "," #name "@@" #version)
|
|
|
|
|
2011-08-09 06:48:17 -07:00
|
|
|
/**
|
|
|
|
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
|
|
|
|
* @mnt: returns buffer with the mountpoint string
|
|
|
|
*
|
|
|
|
* Returns: 0 on success else -1 on error
|
|
|
|
*
|
|
|
|
* NOTE: this function only supports versions of apparmor using securityfs
|
|
|
|
*/
|
|
|
|
int aa_find_mountpoint(char **mnt)
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
struct mntent *mntpt;
|
|
|
|
FILE *mntfile;
|
|
|
|
int rc = -1;
|
|
|
|
|
|
|
|
if (!mnt) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mntfile = setmntent("/proc/mounts", "r");
|
|
|
|
if (!mntfile)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((mntpt = getmntent(mntfile))) {
|
|
|
|
char *proposed = NULL;
|
|
|
|
if (strcmp(mntpt->mnt_type, "securityfs") != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (asprintf(&proposed, "%s/apparmor", mntpt->mnt_dir) < 0)
|
|
|
|
/* ENOMEM */
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (stat(proposed, &statbuf) == 0) {
|
|
|
|
*mnt = proposed;
|
|
|
|
rc = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(proposed);
|
|
|
|
}
|
|
|
|
endmntent(mntfile);
|
|
|
|
if (rc == -1)
|
|
|
|
errno = ENOENT;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-08-09 06:48:56 -07:00
|
|
|
/**
|
|
|
|
* aa_is_enabled - determine if apparmor is enabled
|
|
|
|
*
|
|
|
|
* Returns: 1 if enabled else reason it is not, or 0 on error
|
|
|
|
*
|
|
|
|
* ENOSYS - no indication apparmor is present in the system
|
|
|
|
* ENOENT - enabled but interface could not be found
|
|
|
|
* ECANCELED - disabled at boot
|
|
|
|
* ENOMEM - out of memory
|
|
|
|
*/
|
|
|
|
int aa_is_enabled(void)
|
|
|
|
{
|
|
|
|
int serrno, fd, rc, size;
|
|
|
|
char buffer[2];
|
|
|
|
char *mnt;
|
|
|
|
|
|
|
|
/* if the interface mountpoint is available apparmor is enabled */
|
|
|
|
rc = aa_find_mountpoint(&mnt);
|
|
|
|
if (rc == 0) {
|
|
|
|
free(mnt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* determine why the interface mountpoint isn't available */
|
|
|
|
fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
errno = ENOSYS;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = read(fd, &buffer, 2);
|
|
|
|
serrno = errno;
|
|
|
|
close(fd);
|
|
|
|
errno = serrno;
|
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
if (buffer[0] == 'Y')
|
|
|
|
errno = ENOENT;
|
|
|
|
else
|
|
|
|
errno = ECANCELED;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2011-08-09 06:48:17 -07:00
|
|
|
|
2011-07-21 11:06:57 -07:00
|
|
|
static inline pid_t aa_gettid(void)
|
|
|
|
{
|
|
|
|
#ifdef SYS_gettid
|
|
|
|
return syscall(SYS_gettid);
|
|
|
|
#else
|
|
|
|
return getpid();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-07-21 11:09:22 -07:00
|
|
|
static char *procattr_path(pid_t pid, const char *attr)
|
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
if (asprintf(&path, "/proc/%d/attr/%s", pid, attr) > 0)
|
|
|
|
return path;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-08-09 06:45:51 -07:00
|
|
|
/**
|
|
|
|
* aa_getprocattr_raw - get the contents of @attr for @tid into @buf
|
|
|
|
* @tid: tid of task to query
|
|
|
|
* @attr: which /proc/<tid>/attr/<attr> to query
|
|
|
|
* @buf: buffer to store the result in
|
|
|
|
* @len: size of the buffer
|
|
|
|
* @mode: if set will point to mode string within buffer if it is present
|
|
|
|
*
|
|
|
|
* Returns: size of data read or -1 on error, and sets errno
|
|
|
|
*/
|
|
|
|
int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
|
|
|
char **mode)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
|
|
|
int fd, ret;
|
|
|
|
char *tmp = NULL;
|
|
|
|
int size = 0;
|
|
|
|
|
|
|
|
if (!buf || len <= 0) {
|
|
|
|
errno = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = procattr_path(tid, attr);
|
|
|
|
if (!tmp)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
fd = open(tmp, O_RDONLY);
|
|
|
|
free(tmp);
|
|
|
|
if (fd == -1) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = buf;
|
|
|
|
do {
|
|
|
|
ret = read(fd, tmp, len);
|
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
tmp += ret;
|
|
|
|
size += ret;
|
|
|
|
len -= ret;
|
|
|
|
if (len < 0) {
|
|
|
|
errno = ERANGE;
|
|
|
|
goto out2;
|
|
|
|
}
|
|
|
|
} while (ret > 0);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
int saved;
|
|
|
|
if (ret != -1) {
|
|
|
|
errno = EPROTO;
|
|
|
|
}
|
|
|
|
saved = errno;
|
|
|
|
(void)close(fd);
|
|
|
|
errno = saved;
|
|
|
|
goto out;
|
|
|
|
} else if (size > 0 && buf[size - 1] != 0) {
|
|
|
|
/* check for null termination */
|
|
|
|
if (buf[size - 1] == '\n') {
|
|
|
|
buf[size - 1] = 0;
|
|
|
|
} else if (len == 0) {
|
|
|
|
errno = ERANGE;
|
|
|
|
goto out2;
|
|
|
|
} else {
|
|
|
|
buf[size] = 0;
|
|
|
|
size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* now separate the mode. If we don't find it just
|
|
|
|
* return NULL
|
|
|
|
*/
|
|
|
|
if (mode)
|
|
|
|
*mode = NULL;
|
|
|
|
if (strcmp(buf, "unconfined") != 0 &&
|
|
|
|
size > 4 && buf[size - 2] == ')') {
|
|
|
|
int pos = size - 3;
|
|
|
|
while (pos > 0 &&
|
|
|
|
!(buf[pos] == ' ' && buf[pos + 1] == '('))
|
|
|
|
pos--;
|
|
|
|
if (pos > 0) {
|
|
|
|
buf[pos] = 0; /* overwrite ' ' */
|
|
|
|
buf[size - 2] = 0; /* overwrite trailing ) */
|
|
|
|
if (mode)
|
|
|
|
*mode = &buf[pos + 2]; /* skip '(' */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rc = size;
|
|
|
|
|
|
|
|
out2:
|
|
|
|
(void)close(fd);
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INITIAL_GUESS_SIZE 128
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aa_getprocattr - get the contents of @attr for @tid into @buf
|
|
|
|
* @tid: tid of task to query
|
|
|
|
* @attr: which /proc/<tid>/attr/<attr> to query
|
|
|
|
* @buf: allocated buffer the result is stored in
|
|
|
|
* @mode: if set will point to mode string within buffer if it is present
|
|
|
|
*
|
|
|
|
* Returns: size of data read or -1 on error, and sets errno
|
|
|
|
*/
|
|
|
|
int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode)
|
|
|
|
{
|
|
|
|
int rc, size = INITIAL_GUESS_SIZE/2;
|
|
|
|
char *buffer = NULL;
|
|
|
|
|
|
|
|
if (!buf) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
size <<= 1;
|
|
|
|
buffer = realloc(buffer, size);
|
|
|
|
if (!buffer)
|
|
|
|
return -1;
|
|
|
|
memset(buffer, 0, size);
|
|
|
|
|
|
|
|
rc = aa_getprocattr_raw(tid, attr, buffer, size, mode);
|
|
|
|
} while (rc == -1 && errno == ERANGE);
|
|
|
|
|
|
|
|
if (rc == -1) {
|
|
|
|
free(buffer);
|
|
|
|
size = -1;
|
|
|
|
} else
|
|
|
|
*buf = buffer;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2011-07-21 11:10:35 -07:00
|
|
|
static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
|
2007-07-28 15:41:04 +00:00
|
|
|
{
|
|
|
|
int rc = -1;
|
2011-07-21 11:09:22 -07:00
|
|
|
int fd, ret;
|
2007-07-28 15:41:04 +00:00
|
|
|
char *ctl = NULL;
|
|
|
|
|
2007-09-15 05:41:44 +00:00
|
|
|
if (!buf) {
|
2007-07-28 15:41:04 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2011-07-21 11:09:22 -07:00
|
|
|
ctl = procattr_path(tid, attr);
|
|
|
|
if (!ctl)
|
2007-07-28 15:41:04 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
fd = open(ctl, O_WRONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = write(fd, buf, len);
|
|
|
|
if (ret != len) {
|
|
|
|
int saved;
|
|
|
|
if (ret != -1) {
|
|
|
|
errno = EPROTO;
|
|
|
|
}
|
|
|
|
saved = errno;
|
|
|
|
(void)close(fd);
|
|
|
|
errno = saved;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
(void)close(fd);
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (ctl) {
|
|
|
|
free(ctl);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
2007-08-16 04:19:54 +00:00
|
|
|
|
2007-08-16 04:26:19 +00:00
|
|
|
int aa_change_hat(const char *subprofile, unsigned long token)
|
|
|
|
{
|
2007-09-15 05:41:44 +00:00
|
|
|
int rc = -1;
|
|
|
|
int len = 0;
|
|
|
|
char *buf = NULL;
|
|
|
|
const char *fmt = "changehat %016x^%s";
|
|
|
|
|
|
|
|
/* both may not be null */
|
|
|
|
if (!(token || subprofile)) {
|
|
|
|
errno = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subprofile && strnlen(subprofile, PATH_MAX + 1) > PATH_MAX) {
|
|
|
|
errno = EPROTO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = asprintf(&buf, fmt, token, subprofile ? subprofile : "");
|
|
|
|
if (len < 0) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2011-07-21 11:10:35 -07:00
|
|
|
rc = setprocattr(aa_gettid(), "current", buf, len);
|
2007-09-15 05:41:44 +00:00
|
|
|
out:
|
|
|
|
if (buf) {
|
|
|
|
/* clear local copy of magic token before freeing */
|
|
|
|
memset(buf, '\0', len);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
return rc;
|
2007-08-16 04:26:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* original change_hat interface */
|
|
|
|
int __change_hat(char *subprofile, unsigned int token)
|
|
|
|
{
|
|
|
|
return aa_change_hat(subprofile, (unsigned long) token);
|
|
|
|
}
|
|
|
|
|
2007-09-15 05:41:44 +00:00
|
|
|
int aa_change_profile(const char *profile)
|
2007-08-16 04:35:56 +00:00
|
|
|
{
|
2007-09-15 05:41:44 +00:00
|
|
|
char *buf = NULL;
|
|
|
|
int len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!profile) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = asprintf(&buf, "changeprofile %s", profile);
|
|
|
|
if (len < 0)
|
|
|
|
return -1;
|
|
|
|
|
2011-07-21 11:10:35 -07:00
|
|
|
rc = setprocattr(aa_gettid(), "current", buf, len);
|
2010-02-11 15:37:25 -08:00
|
|
|
|
|
|
|
free(buf);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int aa_change_onexec(const char *profile)
|
|
|
|
{
|
|
|
|
char *buf = NULL;
|
|
|
|
int len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!profile) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = asprintf(&buf, "exec %s", profile);
|
|
|
|
if (len < 0)
|
|
|
|
return -1;
|
|
|
|
|
2011-07-21 11:10:35 -07:00
|
|
|
rc = setprocattr(aa_gettid(), "exec", buf, len);
|
2007-09-15 05:41:44 +00:00
|
|
|
|
|
|
|
free(buf);
|
|
|
|
return rc;
|
2007-08-16 04:35:56 +00:00
|
|
|
}
|
|
|
|
|
2007-08-16 04:19:54 +00:00
|
|
|
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
|
|
|
|
extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
|
|
|
symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
|
|
|
|
default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
|
2010-02-11 15:38:24 -08:00
|
|
|
|
|
|
|
|
|
|
|
int aa_change_hatv(const char *subprofiles[], unsigned long token)
|
|
|
|
{
|
|
|
|
int size, totallen = 0, hatcount = 0;
|
|
|
|
int rc = -1;
|
|
|
|
const char **hats;
|
|
|
|
char *pos, *buf = NULL;
|
|
|
|
const char *cmd = "changehat";
|
|
|
|
|
|
|
|
/* both may not be null */
|
|
|
|
if (!token && !(subprofiles && *subprofiles)) {
|
|
|
|
errno = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validate hat lengths and while we are at it count how many and
|
|
|
|
* mem required */
|
|
|
|
if (subprofiles) {
|
|
|
|
for (hats = subprofiles; *hats; hats++) {
|
|
|
|
int len = strnlen(*hats, PATH_MAX + 1);
|
|
|
|
if (len > PATH_MAX) {
|
|
|
|
errno = EPROTO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
totallen += len + 1;
|
|
|
|
hatcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate size of cmd + space + token + ^ + vector of hats */
|
|
|
|
size = strlen(cmd) + 18 + totallen + 1;
|
|
|
|
buf = malloc(size);
|
|
|
|
if (!buf) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setup command string which is of the form
|
|
|
|
* changehat <token>^hat1\0hat2\0hat3\0..\0
|
|
|
|
*/
|
2010-07-26 10:58:07 -07:00
|
|
|
sprintf(buf, "%s %016lx^", cmd, token);
|
2010-02-11 15:38:24 -08:00
|
|
|
pos = buf + strlen(buf);
|
|
|
|
if (subprofiles) {
|
|
|
|
for (hats = subprofiles; *hats; hats++) {
|
|
|
|
strcpy(pos, *hats);
|
|
|
|
pos += strlen(*hats) + 1;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
/* step pos past trailing \0 */
|
|
|
|
pos++;
|
|
|
|
|
2011-07-21 11:10:35 -07:00
|
|
|
rc = setprocattr(aa_gettid(), "current", buf, pos - buf);
|
2010-02-11 15:38:24 -08:00
|
|
|
|
|
|
|
out:
|
|
|
|
if (buf) {
|
|
|
|
/* clear local copy of magic token before freeing */
|
|
|
|
memset(buf, '\0', size);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* change_hat_vargs - change_hatv but passing the hats as fn arguments
|
|
|
|
* @token: the magic token
|
|
|
|
* @nhat: the number of hats being passed in the arguments
|
|
|
|
* ...: a argument list of const char * being passed
|
|
|
|
*
|
|
|
|
* change_hat_vargs can be called directly but it is meant to be called
|
|
|
|
* through its macro wrapper of the same name. Which automatically
|
|
|
|
* fills in the nhats arguments based on the number of parameters
|
|
|
|
* passed.
|
|
|
|
* to call change_hat_vargs direction do
|
|
|
|
* (change_hat_vargs)(token, nhats, hat1, hat2...)
|
|
|
|
*/
|
|
|
|
int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
const char *argv[nhats+1];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
va_start(ap, nhats);
|
|
|
|
for (i = 0; i < nhats ; i++) {
|
|
|
|
argv[i] = va_arg(ap, char *);
|
|
|
|
}
|
|
|
|
argv[nhats] = NULL;
|
|
|
|
va_end(ap);
|
|
|
|
return aa_change_hatv(argv, token);
|
|
|
|
}
|
2011-08-09 06:47:40 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* aa_gettaskcon - get the confinement for task @target in an allocated buffer
|
|
|
|
* @target: task to query
|
|
|
|
* @con: pointer to returned buffer with the confinement string
|
|
|
|
* @mode: if provided will point to the mode string in @con if present
|
|
|
|
*
|
|
|
|
* Returns: length of confinement data or -1 on error and sets errno
|
|
|
|
*
|
|
|
|
* Guarentees that @con and @mode are null terminated. The length returned
|
|
|
|
* is for all data including both @con and @mode, and maybe > than strlen(@con)
|
|
|
|
* even if @mode is NULL
|
|
|
|
*
|
|
|
|
* Caller is responsible for freeing the buffer returned in @con. @mode is
|
|
|
|
* always contained within @con's buffer and so NEVER do free(@mode)
|
|
|
|
*/
|
|
|
|
int aa_gettaskcon(pid_t target, char **con, char **mode)
|
|
|
|
{
|
|
|
|
return aa_getprocattr(target, "current", con, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aa_getcon - get the confinement for current task in an allocated buffer
|
|
|
|
* @con: pointer to return buffer with the confinement if successful
|
|
|
|
* @mode: if provided will point to the mode string in @con if present
|
|
|
|
*
|
|
|
|
* Returns: length of confinement data or -1 on error and sets errno
|
|
|
|
*
|
|
|
|
* Guarentees that @con and @mode are null terminated. The length returned
|
|
|
|
* is for all data including both @con and @mode, and may > than strlen(@con)
|
|
|
|
* even if @mode is NULL
|
|
|
|
*
|
|
|
|
* Caller is responsible for freeing the buffer returned in @con. @mode is
|
|
|
|
* always contained within @con's buffer and so NEVER do free(@mode)
|
|
|
|
*/
|
|
|
|
int aa_getcon(char **con, char **mode)
|
|
|
|
{
|
|
|
|
return aa_gettaskcon(aa_gettid(), con, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef SO_PEERSEC
|
|
|
|
#define SO_PEERSEC 31
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aa_getpeercon_raw - get the confinement of the socket's peer (other end)
|
|
|
|
* @fd: socket to get peer confinement for
|
|
|
|
* @con: pointer to buffer to store confinement string
|
|
|
|
* @size: initially contains size of the buffer, returns size of data read
|
|
|
|
*
|
|
|
|
* Returns: length of confinement data including null termination or -1 on error
|
|
|
|
* if errno == ERANGE then @size will hold the size needed
|
|
|
|
*/
|
|
|
|
int aa_getpeercon_raw(int fd, char *buffer, int *size)
|
|
|
|
{
|
|
|
|
socklen_t optlen = *size;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (optlen <= 0 || buffer == NULL) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &optlen);
|
|
|
|
if (rc == -1 || optlen <= 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* check for null termination */
|
|
|
|
if (buffer[optlen - 1] != 0) {
|
|
|
|
if (optlen < *size) {
|
|
|
|
buffer[optlen] = 0;
|
|
|
|
optlen++;
|
|
|
|
} else {
|
|
|
|
/* buffer needs to be bigger by 1 */
|
|
|
|
rc = -1;
|
|
|
|
errno = ERANGE;
|
|
|
|
optlen++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
*size = optlen;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aa_getpeercon - get the confinement of the socket's peer (other end)
|
|
|
|
* @fd: socket to get peer confinement for
|
|
|
|
* @con: pointer to allocated buffer with the confinement string
|
|
|
|
*
|
|
|
|
* Returns: length of confinement data including null termination or -1 on error
|
|
|
|
*
|
|
|
|
* Caller is responsible for freeing the buffer returned.
|
|
|
|
*/
|
|
|
|
int aa_getpeercon(int fd, char **con)
|
|
|
|
{
|
|
|
|
int rc, size = INITIAL_GUESS_SIZE;
|
|
|
|
char *buffer = NULL;
|
|
|
|
|
|
|
|
if (!con) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
buffer = realloc(buffer, size);
|
|
|
|
if (!buffer)
|
|
|
|
return -1;
|
|
|
|
memset(buffer, 0, size);
|
|
|
|
|
|
|
|
rc = aa_getpeercon_raw(fd, buffer, &size);
|
|
|
|
} while (rc == -1 && errno == ERANGE);
|
|
|
|
|
|
|
|
if (rc == -1) {
|
|
|
|
free(buffer);
|
|
|
|
size = -1;
|
|
|
|
} else
|
|
|
|
*con = buffer;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|