1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "module-dir.h"
#include "randgen.h"
#include "mail-user.h"
#include "mail-storage-private.h"
#include "mail-storage-hooks.h"
#include <sys/apparmor.h>
#define APPARMOR_PLUGIN_SETTING_HAT_PREFIX "apparmor_hat"
const char *apparmor_plugin_version = DOVECOT_ABI_VERSION;
/* hooks into user creation and deinit, will try to use
hats provided by apparmor_hat, apparmor_hat1... etc */
#define APPARMOR_USER_CONTEXT(obj) \
(struct apparmor_mail_user*)MODULE_CONTEXT(obj, apparmor_mail_user_module)
static MODULE_CONTEXT_DEFINE_INIT(apparmor_mail_user_module,
&mail_user_module_register);
struct apparmor_mail_user {
union mail_user_module_context module_ctx;
unsigned long token;
};
void apparmor_plugin_init(struct module*);
void apparmor_plugin_deinit(void);
static void apparmor_log_current_context(struct mail_user *user)
{
char *con, *mode;
if (aa_getcon(&con, &mode) < 0) {
e_debug(user->event, "aa_getcon() failed: %m");
} else {
e_debug(user->event, "apparmor: Current context=%s, mode=%s",
con, mode);
free(con);
}
}
static void apparmor_mail_user_deinit(struct mail_user *user)
{
struct apparmor_mail_user *auser = APPARMOR_USER_CONTEXT(user);
i_assert(auser != NULL);
auser->module_ctx.super.deinit(user);
if (aa_change_hat(NULL, auser->token)<0)
i_fatal("aa_change_hat(NULL) failed: %m");
apparmor_log_current_context(user);
}
static void apparmor_mail_user_created(struct mail_user *user)
{
struct mail_user_vfuncs *v = user->vlast;
struct apparmor_mail_user *auser;
ARRAY_TYPE(const_string) hats;
/* see if we can find any hats */
const char *hat =
mail_user_plugin_getenv(user, APPARMOR_PLUGIN_SETTING_HAT_PREFIX);
if (hat == NULL)
return;
t_array_init(&hats, 8);
array_push_back(&hats, &hat);
for(unsigned int i = 2;; i++) {
hat = mail_user_plugin_getenv(user, t_strdup_printf("%s%u",
APPARMOR_PLUGIN_SETTING_HAT_PREFIX, i));
if (hat == NULL) break;
array_push_back(&hats, &hat);
}
array_append_zero(&hats);
/* we got hat(s) to try */
auser = p_new(user->pool, struct apparmor_mail_user, 1);
auser->module_ctx.super = *v;
user->vlast = &auser->module_ctx.super;
v->deinit = apparmor_mail_user_deinit;
MODULE_CONTEXT_SET(user, apparmor_mail_user_module, auser);
/* generate a magic token */
random_fill(&auser->token, sizeof(auser->token));
/* try change hat */
if (aa_change_hatv(array_front_modifiable(&hats), auser->token) < 0) {
i_fatal("aa_change_hatv(%s) failed: %m",
t_array_const_string_join(&hats, ","));
}
apparmor_log_current_context(user);
}
static const struct mail_storage_hooks apparmor_hooks = {
.mail_user_created = apparmor_mail_user_created
};
void apparmor_plugin_init(struct module *module)
{
mail_storage_hooks_add(module, &apparmor_hooks);
}
void apparmor_plugin_deinit(void)
{
mail_storage_hooks_remove(&apparmor_hooks);
}
|