-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod_authz_fsacl.c
executable file
·253 lines (221 loc) · 7.52 KB
/
mod_authz_fsacl.c
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Filesystem ACL authorization module for Apache
*
* Paul B. Henson <henson@acm.org>
*
* Copyright (c) 2008-2019 Paul B. Henson -- see COPYRIGHT file for details
*
*/
#include <grp.h>
#include <pwd.h>
#include <sys/acl.h>
#include "apr_errno.h"
#include "apr_file_info.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_request.h"
#include "mod_auth.h"
module AP_MODULE_DECLARE_DATA authz_fsacl_module;
/* Copied from mod_dir.c, must be updated if source changes. */
typedef struct dir_config_struct {
apr_array_header_t *index_names;
} dir_config_rec;
static authz_status fsacl_check_authz(request_rec *r, const char *require_args,
const void *parsed_require_args) {
char *index_file = NULL;
struct group *gr;
struct passwd *pw;
acl_t *aclp;
void *ace_list;
int acl_index;
int result = 0;
if (r->finfo.filetype == APR_NOFILE) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"authz_fsacl: no file found for request (uri=%s)", r->uri);
return AUTHZ_DENIED;
}
if (r->path_info && *r->path_info) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"authz_fsacl: found unexpected path_info (uri=%s)", r->uri);
return AUTHZ_DENIED;
}
/* If it's a directory, look for index files */
if (r->finfo.filetype == APR_DIR) {
module *mod_dir_module = ap_find_linked_module("mod_dir.c");
if (mod_dir_module) {
dir_config_rec *dir_config = (dir_config_rec *)ap_get_module_config(r->per_dir_config,
mod_dir_module);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: looking for index files");
char **names_ptr;
int num_names;
char *default_index[1];
if (dir_config->index_names) {
names_ptr = (char **)dir_config->index_names->elts;
num_names = dir_config->index_names->nelts;
}
else {
default_index[0] = AP_DEFAULT_INDEX;
names_ptr = default_index;
num_names = 1;
}
for (; num_names; ++names_ptr, --num_names) {
apr_finfo_t finfo;
apr_status_t result;
char *index_path = apr_pstrcat(r->pool, r->filename, "/", *names_ptr, NULL);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: looking for index %s", index_path);
if ((result = apr_stat(&finfo, index_path, APR_FINFO_PROT, r->pool)) != APR_SUCCESS) {
if (APR_STATUS_IS_EACCES(result)) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"authz_fsacl: stat %s failed with EACCES", index_path);
return AUTHZ_DENIED;
}
else if (!APR_STATUS_IS_ENOENT(result)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, apr_get_os_error(), r,
"authz_fsacl: unexpected stat failure on %s", index_path);
return AUTHZ_GENERAL_ERROR;
}
}
else if (finfo.protection & APR_FPROT_WREAD) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"authz_fsacl: index %s is world readable", index_path);
return AUTHZ_GRANTED;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"authz_fsacl: index %s is not world readable", index_path);
if (!r->user) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"authz_fsacl: returning AUTHZ_DENIED_NO_USER");
return AUTHZ_DENIED_NO_USER;
}
else {
index_file = index_path;
break;
}
}
}
if (!index_file) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: no index file found");
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: mod_dir not loaded");
}
}
if (!index_file) {
if (r->finfo.protection & APR_FPROT_WREAD) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: %s is world readable", r->filename);
return AUTHZ_GRANTED;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: %s is not world readable", r->filename);
if (!r->user) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"authz_fsacl: returning AUTHZ_DENIED_NO_USER");
return AUTHZ_DENIED_NO_USER;
}
}
}
if ((pw = getpwnam(r->user)) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "authz_fsacl: getpwnam failed for user %s (uri=%s)", r->user, r->uri);
return AUTHZ_GENERAL_ERROR;
}
if (acl_get(index_file ? index_file : r->filename, 0, &aclp) != 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, apr_get_os_error(), r,
"authz_fsacl: acl_get failed for file %s (uri=%s)",
index_file ? index_file : r->filename, r->uri);
return AUTHZ_GENERAL_ERROR;
}
if (aclp->acl_type != ACE_T) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"authz_fsacl: invalid acl type for file %s (uri=%s)",
index_file ? index_file : r->filename, r->uri);
result = -1;
goto acl_loop_end;
}
ace_list = aclp->acl_aclp;
for (acl_index = 0; acl_index < aclp->acl_cnt; acl_index++) {
ace_t *ace = (ace_t *)(ace_list+acl_index*sizeof(ace_t));
if (ace->a_flags & ACE_INHERIT_ONLY_ACE)
continue;
/* XXX - deny entries are not currently handled properly */
if (ace->a_access_mask & ACE_READ_DATA && ace->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
if (ace->a_flags & ACE_EVERYONE) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d everyone", acl_index);
result = 1;
goto acl_loop_end;
}
else if (ace->a_flags & (ACE_GROUP|ACE_IDENTIFIER_GROUP)) {
gid_t gid = (ace->a_flags & ACE_GROUP) ? r->finfo.group : ace->a_who;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d group %d", acl_index, gid);
char **member;
if (pw->pw_gid == gid) {
result = 1;
goto acl_loop_end;
}
if ((gr = getgrgid(gid)) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"authz_fsacl: getgrgid failed for group %d (uri=%s)", gid, r->uri);
result = -1;
goto acl_loop_end;
}
for (member = gr->gr_mem ; *member != NULL; member++) {
if (strcmp(pw->pw_name, *member) == 0) {
result = 1;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d group matched", acl_index);
goto acl_loop_end;
}
}
}
else {
uid_t uid = (ace->a_flags & ACE_OWNER) ? r->finfo.user : ace->a_who;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d user %d", acl_index, uid);
if (pw->pw_uid == uid) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d user matched", acl_index);
result = 1;
goto acl_loop_end;
}
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: ace %d not read/allow", acl_index);
}
} acl_loop_end:
acl_free(aclp);
if (result == 1) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: returning AUTHZ_GRANTED", acl_index);
return AUTHZ_GRANTED;
}
else if (result == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "authz_fsacl: permission denied user=%s uri=%s", r->user, r->uri);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: returning AUTHZ_DENIED", acl_index);
return AUTHZ_DENIED;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "authz_fsacl: returning AUTHZ_GENERAL_ERROR", acl_index);
return AUTHZ_GENERAL_ERROR;
}
}
static const authz_provider authz_fsacl_provider =
{
&fsacl_check_authz,
NULL,
};
static void register_hooks(apr_pool_t *p) {
ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "fs-acl",
AUTHZ_PROVIDER_VERSION, &authz_fsacl_provider,
AP_AUTH_INTERNAL_PER_CONF);
}
AP_DECLARE_MODULE(authz_fsacl) =
{
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
NULL, /* command apr_table_t */
register_hooks /* register hooks */
};