Merge lp:~zisis00/drizzle/ldap_policy into lp:drizzle
- ldap_policy
- Merge into 7.2
Status: | Work in progress |
---|---|
Proposed branch: | lp:~zisis00/drizzle/ldap_policy |
Merge into: | lp:drizzle |
Diff against target: |
1707 lines (+1673/-2) 5 files modified
plugin/ldap_policy/docs/index.rst (+187/-0) plugin/ldap_policy/ldap_policy.cc (+1286/-0) plugin/ldap_policy/ldap_policy.hpp (+194/-0) plugin/ldap_policy/plugin.ini (+3/-0) tests/lib/server_mgmt/drizzled.py (+3/-2) |
To merge this branch: | bzr merge lp:~zisis00/drizzle/ldap_policy |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Drizzle Trunk | Pending | ||
Review via email: mp+119016@code.launchpad.net |
Commit message
Description of the change
This branch introduce a new plugin named ldap policy. The plugin is an authentication system using LDAP. Each schema/table of Drizzle and user has a record in LDAP. The ldap_policy plugin search in LDAP and dictates if access to target schema/table from user should be granted or not. Also, it is capable to search for supplementaries groups and it has an implementation of a "per-user" cache system for better performance.
Note: Extending the testing suite to have some automated tests & writing detailed documentation are currently in progress.
- 2556. By Zisis Sialveras
-
Fixed some errors in ldap_policy
- 2557. By Zisis Sialveras
-
Documentation for ldap-policy
Brian Aker (brianaker) wrote : | # |
CXX plugin/
CXX plugin/
plugin/
plugin/
plugin/
CXX plugin/
cc1plus: all warnings being treated as errors
CXX plugin/
make[2]: *** [plugin/
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory `/home/
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/
make: *** [all] Error 2
Build step 'Use builders from another project' marked build as failure
[WARNINGS] Skipping publisher since build result is FAILURE
Notifying upstream projects of job completion
Finished: FAILURE
Unmerged revisions
- 2557. By Zisis Sialveras
-
Documentation for ldap-policy
- 2556. By Zisis Sialveras
-
Fixed some errors in ldap_policy
- 2555. By Zisis Sialveras
-
Some changes in ldap_policy
- 2554. By Zisis Sialveras
-
The LDAP policy plugin.
Preview Diff
1 | === added directory 'plugin/ldap_policy' | |||
2 | === added directory 'plugin/ldap_policy/docs' | |||
3 | === added file 'plugin/ldap_policy/docs/index.rst' | |||
4 | --- plugin/ldap_policy/docs/index.rst 1970-01-01 00:00:00 +0000 | |||
5 | +++ plugin/ldap_policy/docs/index.rst 2012-08-21 14:09:20 +0000 | |||
6 | @@ -0,0 +1,187 @@ | |||
7 | 1 | .. _ldap_policy_plugin: | ||
8 | 2 | |||
9 | 3 | LDAP Authorization | ||
10 | 4 | ================== | ||
11 | 5 | |||
12 | 6 | :program: `ldap_policy` is an :doc:`/administration/authorization` plugin that uses LDAP (Lightweight Directory Access Protocol) records to match policies. | ||
13 | 7 | Each schema and table has a record in LDAP with attributes that indicate which users and groups are authorized to the target schema and/or table. | ||
14 | 8 | More specifically, users exists in an LDAP directory (etc. ou=users,dc=example,dc=com). So do groups, tables and schemata. | ||
15 | 9 | Schemata and tables are defined with objectClass: drizzleItem, and they can have attributes like allowedUsers and allowedGroups. | ||
16 | 10 | These two attributes are the uidNumber of user or the gidNumber of the groups that should be authorized to the schema or table. | ||
17 | 11 | |||
18 | 12 | The plugin is also capable to search for permissions in the supplementaries groups. | ||
19 | 13 | Under the group directory (etc. ou=groups,dc=example,dc=com), may exist the groups of the users. Each group may have memberUID attribute | ||
20 | 14 | if it is defined with objectClass: posixGroup. Having these, allows the plugin to understand the supplementaries groups of the user. | ||
21 | 15 | So if a user has a group in supplementaries groups, and this group is authorized, then the user is authorized too, although he belong in a non-authorized | ||
22 | 16 | primary group. | ||
23 | 17 | |||
24 | 18 | .. seealso:: :doc:`/administration/authorization` | ||
25 | 19 | .. seealso:: :doc:`/plugins/auth_ldap/index` | ||
26 | 20 | |||
27 | 21 | .. _ldap_policy_loading: | ||
28 | 22 | |||
29 | 23 | Loading | ||
30 | 24 | ------- | ||
31 | 25 | |||
32 | 26 | To load this plugin, start :program:`drizzled` with:: | ||
33 | 27 | |||
34 | 28 | --plugin-add=ldap_policy | ||
35 | 29 | |||
36 | 30 | Loading the plugin may not enable or configure it. See the plugin's | ||
37 | 31 | :ref:`ldap_policy_configuration` and :ref:`ldap_policy_variables`. | ||
38 | 32 | |||
39 | 33 | .. seealso:: :ref:`drizzled_plugin_options` for more information about adding and removing plugins. | ||
40 | 34 | |||
41 | 35 | .. _ldap_policy_configuration: | ||
42 | 36 | |||
43 | 37 | Configuration | ||
44 | 38 | ------------- | ||
45 | 39 | |||
46 | 40 | These command line options configure the plugin when :program:`drizzled` | ||
47 | 41 | is started. See :ref:`command_line_options` for more information about specifying | ||
48 | 42 | command line options. | ||
49 | 43 | |||
50 | 44 | .. program:: drizzled | ||
51 | 45 | |||
52 | 46 | .. option:: --ldap-policy.uri ARG | ||
53 | 47 | |||
54 | 48 | :Default: ``ldap://localhost/`` | ||
55 | 49 | :Variable: :ref:`ldap_policy_uri <ldap_policy_uri>` | ||
56 | 50 | |||
57 | 51 | URI of LDAP server to connect. | ||
58 | 52 | |||
59 | 53 | .. option:: --ldap-policy.users-dir ARG | ||
60 | 54 | |||
61 | 55 | :Default: ``ou=users,dc=example,dc=com`` | ||
62 | 56 | :Variable: :ref:`ldap_policy_users_dir <ldap_policy_users_dir>` | ||
63 | 57 | |||
64 | 58 | The LDAP DN (distinguished name) with the users records. | ||
65 | 59 | |||
66 | 60 | Users should be in this LDAP directory, and must be defined objectClass: posixAccount. uidNumber and gidNumber attributes are required. | ||
67 | 61 | |||
68 | 62 | .. option:: --ldap-policy.groups-dir ARG | ||
69 | 63 | |||
70 | 64 | :Default: ``ou=groups,dc=example,dc=com`` | ||
71 | 65 | :Variable: :ref:`ldap_policy_groups_dir <ldap_policy_groups_dir>` | ||
72 | 66 | |||
73 | 67 | The LDAP DN (distinguished name) with the groups records. | ||
74 | 68 | |||
75 | 69 | Groups should be in this LDAP directory, and must be defined with objectClass: posixGroups. Although this class has as optional attribute memberUID, | ||
76 | 70 | it is essential to be filled so plugin can understand the supplementaries groups of the users. | ||
77 | 71 | |||
78 | 72 | |||
79 | 73 | .. option:: --ldap-policy.schemas-dir ARG | ||
80 | 74 | |||
81 | 75 | :Default: ``ou=schemas,dc=example,dc=com`` | ||
82 | 76 | :Variable: :ref:`ldap_policy_schemas_dir <ldap_policy_schemas_dir>` | ||
83 | 77 | |||
84 | 78 | The LDAP DN (distinguished name) with the schemas records. | ||
85 | 79 | |||
86 | 80 | Schemata should be in this LDAP directory, and must be defined with objectClass: drizzleItem. allowedUsers and allowedGroups attributes indicate | ||
87 | 81 | which uidNumber and gidNumber should be authorized in the current schema. | ||
88 | 82 | |||
89 | 83 | .. option:: --ldap-policy.tables-dir ARG | ||
90 | 84 | |||
91 | 85 | :Default: ``ou=tables,dc=example,dc=com`` | ||
92 | 86 | :Variable: :ref:`ldap_policy_tables_dir <ldap_policy_tables_dir>` | ||
93 | 87 | |||
94 | 88 | The LDAP DN (distinguished name) with the tables records. | ||
95 | 89 | |||
96 | 90 | Tables should be in this LDAP directory, and must be defined with objectClass: drizzleItem. allowedUsers and allowedGroups attributes indicate | ||
97 | 91 | which uidNumber and gidNumber should be authorized in the current table. | ||
98 | 92 | |||
99 | 93 | .. option:: --ldap-policy.cache-timeout ARG | ||
100 | 94 | |||
101 | 95 | :Default: ``500`` | ||
102 | 96 | :Variable: :ref:`ldap_policy_cache_timeout <ldap_policy_cache_timeout>` | ||
103 | 97 | |||
104 | 98 | How much time is valid each cache entry. (NOT implemented yet) | ||
105 | 99 | |||
106 | 100 | After a successful authorization to a schema or a table, the user and the schema/table is added in cache memory in order to achive better performance | ||
107 | 101 | the next time he/she tries to access the same schema/table again. Each cache entry is valid for only specific number of seconds. | ||
108 | 102 | |||
109 | 103 | .. _ldap_policy_variables: | ||
110 | 104 | |||
111 | 105 | Variables | ||
112 | 106 | --------- | ||
113 | 107 | |||
114 | 108 | These variables show the running configuration of the plugin. | ||
115 | 109 | See `variables` for more information about querying and setting variables. | ||
116 | 110 | |||
117 | 111 | |||
118 | 112 | .. _ldap_policy_uri: | ||
119 | 113 | * ``ldap_policy_uri`` | ||
120 | 114 | |||
121 | 115 | :Scope: Global | ||
122 | 116 | :Dynamic: No | ||
123 | 117 | :Option: :option:`--ldap_policy.uri` | ||
124 | 118 | |||
125 | 119 | URI of the LDAP server to contact. | ||
126 | 120 | |||
127 | 121 | .. _ldap_policy_users_dir: | ||
128 | 122 | * ``ldap_policy_users_dir`` | ||
129 | 123 | |||
130 | 124 | :Scope: Global | ||
131 | 125 | :Dynamic: No | ||
132 | 126 | :Option: :option:`--ldap_policy.users-dir` | ||
133 | 127 | |||
134 | 128 | The LDAP DN (distinguished name) with the users records. | ||
135 | 129 | |||
136 | 130 | .. _ldap_policy_groups_dir: | ||
137 | 131 | * ``ldap_policy_groups_dir`` | ||
138 | 132 | |||
139 | 133 | :Scope: Global | ||
140 | 134 | :Dynamic: No | ||
141 | 135 | :Option: :option:`--ldap_policy.groups-dir` | ||
142 | 136 | |||
143 | 137 | The LDAP DN (distinguished name) with the groups records. | ||
144 | 138 | |||
145 | 139 | .. _ldap_policy_schemas_dir: | ||
146 | 140 | * ``ldap_policy_schemas_dir`` | ||
147 | 141 | |||
148 | 142 | :Scope: Global | ||
149 | 143 | :Dynamic: No | ||
150 | 144 | :Option: :option:`--ldap_policy.schemas-dir` | ||
151 | 145 | |||
152 | 146 | The LDAP DN (distinguished name) with the schemas records. | ||
153 | 147 | |||
154 | 148 | .. _ldap_policy_tables_dir: | ||
155 | 149 | * ``ldap_policy_tables_dir`` | ||
156 | 150 | |||
157 | 151 | :Scope: Global | ||
158 | 152 | :Dynamic: No | ||
159 | 153 | :Option: :option:`--ldap_policy.tables-dir` | ||
160 | 154 | |||
161 | 155 | The LDAP DN (distinguished name) with the tables records. | ||
162 | 156 | |||
163 | 157 | |||
164 | 158 | .. ldap_policy_authors: | ||
165 | 159 | |||
166 | 160 | Authors | ||
167 | 161 | ------- | ||
168 | 162 | |||
169 | 163 | Zisis Sialveras | ||
170 | 164 | |||
171 | 165 | .. ldap_policy_version: | ||
172 | 166 | |||
173 | 167 | Version | ||
174 | 168 | ------- | ||
175 | 169 | |||
176 | 170 | This documentation applies to version **ldap_policy 0.1**. | ||
177 | 171 | |||
178 | 172 | To see which version of the plugin a Drizzle server is running, execute: | ||
179 | 173 | |||
180 | 174 | .. code-block:: mysql | ||
181 | 175 | |||
182 | 176 | SELECT MODULE_VERSION FROM DATA_DICTIONARY.MODULES WHERE MODULE_NAME='ldap_policy' | ||
183 | 177 | |||
184 | 178 | |||
185 | 179 | .. ldap_policy_changelog | ||
186 | 180 | |||
187 | 181 | Changelog | ||
188 | 182 | --------- | ||
189 | 183 | |||
190 | 184 | v0.1 | ||
191 | 185 | *First release. | ||
192 | 186 | |||
193 | 187 | |||
194 | 0 | 188 | ||
195 | === added file 'plugin/ldap_policy/ldap_policy.cc' | |||
196 | --- plugin/ldap_policy/ldap_policy.cc 1970-01-01 00:00:00 +0000 | |||
197 | +++ plugin/ldap_policy/ldap_policy.cc 2012-08-21 14:09:20 +0000 | |||
198 | @@ -0,0 +1,1286 @@ | |||
199 | 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- | ||
200 | 2 | * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
201 | 3 | * | ||
202 | 4 | * Copyright (C) 2012 Zisis Sialveras | ||
203 | 5 | * | ||
204 | 6 | * This program is free software; you can redistribute it and/or modify | ||
205 | 7 | * it under the terms of the GNU General Public License as published by | ||
206 | 8 | * the Free Software Foundation; version 2 of the License. | ||
207 | 9 | * | ||
208 | 10 | * This program is distributed in the hope that it will be useful, | ||
209 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
210 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
211 | 13 | * GNU General Public License for more details. | ||
212 | 14 | * | ||
213 | 15 | * You should have received a copy of the GNU General Public License | ||
214 | 16 | * along with this program; if not, write to the Free Software | ||
215 | 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
216 | 18 | */ | ||
217 | 19 | |||
218 | 20 | #include "ldap_policy.hpp" | ||
219 | 21 | #include <drizzled/module/option_map.h> | ||
220 | 22 | |||
221 | 23 | |||
222 | 24 | namespace po= boost::program_options; | ||
223 | 25 | |||
224 | 26 | using namespace std; | ||
225 | 27 | using namespace drizzled; | ||
226 | 28 | |||
227 | 29 | namespace ldap_policy | ||
228 | 30 | { | ||
229 | 31 | |||
230 | 32 | static int init(module::Context &context) | ||
231 | 33 | { | ||
232 | 34 | LDAP_policy *ldap_policy= new LDAP_policy(); | ||
233 | 35 | |||
234 | 36 | if(ldap_policy->connect() == false) | ||
235 | 37 | { | ||
236 | 38 | errmsg_printf(error::ERROR, _("Could not load ldap_policy\n")); | ||
237 | 39 | delete ldap_policy; | ||
238 | 40 | return 1; | ||
239 | 41 | } | ||
240 | 42 | |||
241 | 43 | context.registerVariable(new sys_var_const_string_val("uri", uri)); | ||
242 | 44 | context.registerVariable(new sys_var_const_string_val("users-dir", users_dir)); | ||
243 | 45 | context.registerVariable(new sys_var_const_string_val("schema-dir", schemas_dir)); | ||
244 | 46 | context.registerVariable(new sys_var_const_string_val("groups-dir", groups_dir)); | ||
245 | 47 | context.registerVariable(new sys_var_const_string_val("tables-dir", tables_dir)); | ||
246 | 48 | ///Remember to register the Variable Cache-timeout | ||
247 | 49 | |||
248 | 50 | context.add(ldap_policy); | ||
249 | 51 | return 0; | ||
250 | 52 | } | ||
251 | 53 | |||
252 | 54 | static void init_options(drizzled::module::option_context &context) | ||
253 | 55 | { | ||
254 | 56 | context("uri", po::value<string>(&uri)->default_value(DEFAULT_URI), | ||
255 | 57 | N_("URI of the LDAP server to contact")); | ||
256 | 58 | context("users-dir", po::value<string>(&users_dir)->default_value(DEFAULT_USERS_DIR), | ||
257 | 59 | N_("Users' LDAP directory")); | ||
258 | 60 | context("schemas-dir", po::value<string>(&schemas_dir)->default_value(DEFAULT_SCHEMAS_DIR), | ||
259 | 61 | N_("Schemas' LDAP directory")); | ||
260 | 62 | context("groups-dir", po::value<string>(&groups_dir)->default_value(DEFAULT_GROUPS_DIR), | ||
261 | 63 | N_("Groups' LDAP directory")); | ||
262 | 64 | context("tables-dir", po::value<string>(&tables_dir)->default_value(DEFAULT_TABLES_DIR), | ||
263 | 65 | N_("Tables' LDAP directory")); | ||
264 | 66 | context("cache-timeout", po::value<time_t>(&cache_timeout)->default_value(DEFAULT_CACHE_TIMEOUT), | ||
265 | 67 | N_("Cache timeout")); | ||
266 | 68 | } | ||
267 | 69 | |||
268 | 70 | void LDAP_policy::printerror() | ||
269 | 71 | { | ||
270 | 72 | errmsg_printf(error::ERROR, _(error.c_str())); | ||
271 | 73 | } | ||
272 | 74 | |||
273 | 75 | /** | ||
274 | 76 | * restrictProcess dictates if user A is allowed to see/kill user B connection. | ||
275 | 77 | * | ||
276 | 78 | * In the beginning, restrictProcess checks if user A and B has the same gidNumber | ||
277 | 79 | * attribute in their LDAP records. If they have not, restrictProcess checks | ||
278 | 80 | * if user's B group is one of the user's A supplementaries groups. This is done | ||
279 | 81 | * by searching in user's B group LDAP record and checking if its attributes is uid | ||
280 | 82 | * of user A. | ||
281 | 83 | */ | ||
282 | 84 | |||
283 | 85 | bool LDAP_policy::restrictProcess(const drizzled::identifier::User &user_ctx, | ||
284 | 86 | const drizzled::identifier::User &session_ctx) | ||
285 | 87 | { | ||
286 | 88 | |||
287 | 89 | LDAPMessage *response; | ||
288 | 90 | const char *attrs[]= {"uidNumber", | ||
289 | 91 | "gidNumber", | ||
290 | 92 | NULL | ||
291 | 93 | }; | ||
292 | 94 | string filter= "(cn=" + user_ctx.username() + ")"; | ||
293 | 95 | |||
294 | 96 | |||
295 | 97 | int return_code= ldap_search_ext_s(ldap, | ||
296 | 98 | users_dir.c_str(), | ||
297 | 99 | LDAP_SCOPE_ONELEVEL, | ||
298 | 100 | filter.c_str(), | ||
299 | 101 | const_cast<char**>(attrs), | ||
300 | 102 | 0, | ||
301 | 103 | NULL, | ||
302 | 104 | NULL, | ||
303 | 105 | NULL, | ||
304 | 106 | 1, | ||
305 | 107 | &response); | ||
306 | 108 | |||
307 | 109 | if( return_code != LDAP_SUCCESS ) | ||
308 | 110 | { | ||
309 | 111 | error= "ldap_search_ext_s failed:"; | ||
310 | 112 | error+= ldap_err2string(return_code); | ||
311 | 113 | printerror(); | ||
312 | 114 | |||
313 | 115 | ldap_msgfree(response); | ||
314 | 116 | return true; | ||
315 | 117 | } | ||
316 | 118 | |||
317 | 119 | LDAPMessage *entry; | ||
318 | 120 | int ldap_entries= ldap_count_entries(ldap, response); | ||
319 | 121 | |||
320 | 122 | if( ldap_entries == 0 || ldap_entries == (-1)) | ||
321 | 123 | { | ||
322 | 124 | ldap_msgfree(response); | ||
323 | 125 | return true; | ||
324 | 126 | } | ||
325 | 127 | |||
326 | 128 | entry= ldap_first_entry(ldap, response); | ||
327 | 129 | BerElement *berv; | ||
328 | 130 | char **gid, **uid, *attr; | ||
329 | 131 | for(attr= ldap_first_attribute(ldap, entry, &berv); //attr is gidNumber attribute | ||
330 | 132 | attr != NULL; | ||
331 | 133 | attr= ldap_next_attribute(ldap, entry, berv)) | ||
332 | 134 | { | ||
333 | 135 | |||
334 | 136 | if(not strcmp(attr, "uidNumber")) | ||
335 | 137 | { | ||
336 | 138 | uid= ldap_get_values(ldap, entry, attr); | ||
337 | 139 | } | ||
338 | 140 | else if( not strcmp(attr, "gidNumber")) | ||
339 | 141 | { | ||
340 | 142 | gid= ldap_get_values(ldap, entry, attr); | ||
341 | 143 | } | ||
342 | 144 | } //we have uid and gid of user A | ||
343 | 145 | |||
344 | 146 | if(gid == NULL) | ||
345 | 147 | { | ||
346 | 148 | return true; | ||
347 | 149 | } | ||
348 | 150 | |||
349 | 151 | struct berval brv; | ||
350 | 152 | brv.bv_len= strlen(gid[0]); | ||
351 | 153 | brv.bv_val= gid[0]; | ||
352 | 154 | |||
353 | 155 | string dn= "cn=" + session_ctx.username() + "," + users_dir.c_str(); | ||
354 | 156 | |||
355 | 157 | return_code= ldap_compare_ext_s(ldap, | ||
356 | 158 | dn.c_str(), | ||
357 | 159 | "gidNumber", | ||
358 | 160 | &brv, | ||
359 | 161 | NULL, | ||
360 | 162 | NULL); | ||
361 | 163 | |||
362 | 164 | if(return_code == LDAP_COMPARE_TRUE) | ||
363 | 165 | { | ||
364 | 166 | if(berv != NULL) | ||
365 | 167 | { | ||
366 | 168 | ber_free(berv, 0); | ||
367 | 169 | } | ||
368 | 170 | ldap_memfree(attr); | ||
369 | 171 | ldap_msgfree(response); | ||
370 | 172 | ldap_value_free(gid); | ||
371 | 173 | ldap_value_free(uid); | ||
372 | 174 | |||
373 | 175 | return false; | ||
374 | 176 | } | ||
375 | 177 | else if (return_code != LDAP_COMPARE_FALSE) | ||
376 | 178 | { | ||
377 | 179 | |||
378 | 180 | error= "ldap_compare_ext_s failed"; | ||
379 | 181 | error+= ldap_err2string(return_code); | ||
380 | 182 | printerror(); | ||
381 | 183 | |||
382 | 184 | if(berv != NULL) | ||
383 | 185 | { | ||
384 | 186 | ber_free(berv, 0); | ||
385 | 187 | } | ||
386 | 188 | ldap_memfree(attr); | ||
387 | 189 | ldap_msgfree(response); | ||
388 | 190 | ldap_value_free(gid); | ||
389 | 191 | ldap_value_free(uid); | ||
390 | 192 | return true; | ||
391 | 193 | } | ||
392 | 194 | |||
393 | 195 | //If they are not in the same group, search for the supplementaries | ||
394 | 196 | ldap_msgfree(response); | ||
395 | 197 | ldap_memfree(attr); | ||
396 | 198 | |||
397 | 199 | if(berv != NULL) | ||
398 | 200 | { | ||
399 | 201 | ber_free(berv, 0); | ||
400 | 202 | } | ||
401 | 203 | |||
402 | 204 | filter= "(cn=" + session_ctx.username() + ")"; | ||
403 | 205 | |||
404 | 206 | const char *attrs2[]= {"gidNumber", NULL}; | ||
405 | 207 | |||
406 | 208 | return_code= ldap_search_ext_s( ldap, | ||
407 | 209 | users_dir.c_str(), | ||
408 | 210 | LDAP_SCOPE_ONELEVEL, | ||
409 | 211 | filter.c_str(), | ||
410 | 212 | const_cast<char**>(attrs2), | ||
411 | 213 | 0, | ||
412 | 214 | NULL, | ||
413 | 215 | NULL, | ||
414 | 216 | NULL, | ||
415 | 217 | 1, | ||
416 | 218 | &response); | ||
417 | 219 | |||
418 | 220 | |||
419 | 221 | if(return_code != LDAP_SUCCESS) | ||
420 | 222 | { | ||
421 | 223 | error= "ldap_search_ext_s failed:"; | ||
422 | 224 | error+= ldap_err2string(return_code); | ||
423 | 225 | printerror(); | ||
424 | 226 | ldap_msgfree(response); | ||
425 | 227 | ldap_value_free(gid); | ||
426 | 228 | ldap_value_free(uid); | ||
427 | 229 | return true; | ||
428 | 230 | } | ||
429 | 231 | |||
430 | 232 | LDAPMessage *entry2= ldap_first_entry(ldap, response); | ||
431 | 233 | ldap_entries= ldap_count_entries(ldap, entry2); | ||
432 | 234 | |||
433 | 235 | if(ldap_entries == 0 || ldap_entries == -1) | ||
434 | 236 | { | ||
435 | 237 | ldap_msgfree(response); | ||
436 | 238 | ldap_value_free(gid); | ||
437 | 239 | ldap_value_free(uid); | ||
438 | 240 | return true; | ||
439 | 241 | } | ||
440 | 242 | |||
441 | 243 | attr= ldap_first_attribute(ldap, entry2, &berv); //attr is gidNumber | ||
442 | 244 | char **gidNumber= ldap_get_values(ldap, entry2, attr); //we got the gidNumber of user B | ||
443 | 245 | |||
444 | 246 | if(gidNumber==NULL) | ||
445 | 247 | { | ||
446 | 248 | if(berv != NULL) | ||
447 | 249 | { | ||
448 | 250 | ber_free(berv, 0); | ||
449 | 251 | } | ||
450 | 252 | |||
451 | 253 | ldap_memfree(attr); | ||
452 | 254 | ldap_msgfree(response); | ||
453 | 255 | ldap_value_free(gid); | ||
454 | 256 | ldap_value_free(uid); | ||
455 | 257 | return true; | ||
456 | 258 | } | ||
457 | 259 | |||
458 | 260 | filter= "gidNumber="; | ||
459 | 261 | filter+= gidNumber[0]; | ||
460 | 262 | |||
461 | 263 | // searching for the user B group attrs | ||
462 | 264 | return_code= ldap_search_ext_s(ldap, | ||
463 | 265 | groups_dir.c_str(), | ||
464 | 266 | LDAP_SCOPE_ONELEVEL, | ||
465 | 267 | filter.c_str(), | ||
466 | 268 | NULL, /* all attributes are requested */ | ||
467 | 269 | 0, | ||
468 | 270 | NULL, | ||
469 | 271 | NULL, | ||
470 | 272 | NULL, | ||
471 | 273 | 1, | ||
472 | 274 | &response); | ||
473 | 275 | |||
474 | 276 | if(return_code != LDAP_SUCCESS) | ||
475 | 277 | { | ||
476 | 278 | error= "ldap_search_ext_s failed:"; | ||
477 | 279 | error+= ldap_err2string(return_code); | ||
478 | 280 | printerror(); | ||
479 | 281 | |||
480 | 282 | ldap_msgfree(response); | ||
481 | 283 | ldap_value_free(gid); | ||
482 | 284 | ldap_value_free(uid); | ||
483 | 285 | |||
484 | 286 | return true; | ||
485 | 287 | } | ||
486 | 288 | |||
487 | 289 | LDAPMessage *grp_entry= ldap_first_entry(ldap, response); | ||
488 | 290 | ldap_entries= ldap_count_entries(ldap, grp_entry); | ||
489 | 291 | |||
490 | 292 | if(ldap_entries == 0 || ldap_entries == -1) | ||
491 | 293 | { | ||
492 | 294 | |||
493 | 295 | if(berv != NULL) | ||
494 | 296 | { | ||
495 | 297 | ber_free(berv, 0); | ||
496 | 298 | } | ||
497 | 299 | |||
498 | 300 | ldap_memfree(attr); | ||
499 | 301 | ldap_msgfree(response); | ||
500 | 302 | ldap_value_free(gidNumber); | ||
501 | 303 | ldap_value_free(gid); | ||
502 | 304 | ldap_value_free(uid); | ||
503 | 305 | return true; | ||
504 | 306 | } | ||
505 | 307 | |||
506 | 308 | char *group_dn= ldap_get_dn(ldap, grp_entry); | ||
507 | 309 | |||
508 | 310 | if(group_dn == NULL) | ||
509 | 311 | { | ||
510 | 312 | |||
511 | 313 | if(berv != NULL) | ||
512 | 314 | { | ||
513 | 315 | ber_free(berv, 0); | ||
514 | 316 | } | ||
515 | 317 | |||
516 | 318 | ldap_memfree(attr); | ||
517 | 319 | ldap_value_free(gidNumber); | ||
518 | 320 | ldap_value_free(gid); | ||
519 | 321 | ldap_value_free(uid); | ||
520 | 322 | |||
521 | 323 | return true; | ||
522 | 324 | } | ||
523 | 325 | |||
524 | 326 | if(uid == NULL) | ||
525 | 327 | { | ||
526 | 328 | return true; | ||
527 | 329 | } | ||
528 | 330 | struct berval ber_uid; | ||
529 | 331 | ber_uid.bv_len= strlen(uid[0]); | ||
530 | 332 | ber_uid.bv_val= uid[0]; | ||
531 | 333 | |||
532 | 334 | return_code= ldap_compare_ext_s(ldap, | ||
533 | 335 | group_dn, | ||
534 | 336 | "memberUID", | ||
535 | 337 | &ber_uid, | ||
536 | 338 | NULL, | ||
537 | 339 | NULL); | ||
538 | 340 | bool retval= true; | ||
539 | 341 | |||
540 | 342 | if(return_code == LDAP_COMPARE_TRUE) | ||
541 | 343 | { | ||
542 | 344 | retval= false; | ||
543 | 345 | } | ||
544 | 346 | else if(return_code != LDAP_COMPARE_FALSE) | ||
545 | 347 | { | ||
546 | 348 | error= "ldap_compare_ext_s failed:"; | ||
547 | 349 | error+= ldap_err2string(return_code); | ||
548 | 350 | printerror(); | ||
549 | 351 | } | ||
550 | 352 | |||
551 | 353 | ldap_memfree(group_dn); | ||
552 | 354 | if(berv != NULL) | ||
553 | 355 | { | ||
554 | 356 | ber_free(berv, 0); | ||
555 | 357 | } | ||
556 | 358 | ldap_memfree(attr); | ||
557 | 359 | ldap_value_free(gidNumber); | ||
558 | 360 | ldap_value_free(gid); | ||
559 | 361 | ldap_value_free(uid); | ||
560 | 362 | |||
561 | 363 | return retval; | ||
562 | 364 | } | ||
563 | 365 | |||
564 | 366 | |||
565 | 367 | /** | ||
566 | 368 | * check_if_allowed returns TRUE if user is NOT authorized in target table. Otherwise, it returns FALSE. | ||
567 | 369 | * check_if_allowed function, checks if uidNumber attribute of user's LDAP record matches with | ||
568 | 370 | * allowedUsers attribute of tables's LDAP record or gidNumber matches with allowedGroups. | ||
569 | 371 | * If neither of them matches, check_if_allowed search for the supplementaries groups of user | ||
570 | 372 | * and returns true if none of them is allowed. Otherwise it returns false. | ||
571 | 373 | */ | ||
572 | 374 | |||
573 | 375 | bool LDAP_policy::check_if_allowed(LDAPMessage *u_rep, const drizzled::identifier::User &user, const drizzled::identifier::Table &table) | ||
574 | 376 | { | ||
575 | 377 | LDAPMessage *entry= ldap_first_entry(ldap, u_rep); | ||
576 | 378 | int rc; | ||
577 | 379 | string table_dn= "cn=" + table.getTableName() + "," + tables_dir; | ||
578 | 380 | char *uattr, **gid= NULL, **uid= NULL; | ||
579 | 381 | BerElement *uber_val; | ||
580 | 382 | int ldap_entries= ldap_count_entries(ldap, entry); | ||
581 | 383 | |||
582 | 384 | if(ldap_entries == 0 || ldap_entries == -1) | ||
583 | 385 | { | ||
584 | 386 | return true; | ||
585 | 387 | } | ||
586 | 388 | |||
587 | 389 | for(uattr= ldap_first_attribute(ldap, entry, &uber_val); | ||
588 | 390 | uattr != NULL; | ||
589 | 391 | uattr=ldap_next_attribute(ldap, entry, uber_val)) | ||
590 | 392 | { | ||
591 | 393 | if( not strcmp(uattr, "gidNumber")) | ||
592 | 394 | { | ||
593 | 395 | gid= ldap_get_values(ldap, entry, uattr); | ||
594 | 396 | |||
595 | 397 | struct berval bval; | ||
596 | 398 | bval.bv_val= gid[0]; | ||
597 | 399 | bval.bv_len= strlen(gid[0]); | ||
598 | 400 | |||
599 | 401 | rc= ldap_compare_ext_s( ldap, | ||
600 | 402 | table_dn.c_str(), | ||
601 | 403 | "allowedGroups", | ||
602 | 404 | &bval, | ||
603 | 405 | NULL, | ||
604 | 406 | NULL); | ||
605 | 407 | |||
606 | 408 | if(rc == LDAP_COMPARE_TRUE) | ||
607 | 409 | { | ||
608 | 410 | if(uber_val != NULL) | ||
609 | 411 | { | ||
610 | 412 | ber_free(uber_val, 0); | ||
611 | 413 | } | ||
612 | 414 | |||
613 | 415 | ldap_memfree(uattr); | ||
614 | 416 | |||
615 | 417 | if(uid!=NULL) | ||
616 | 418 | ldap_value_free(uid); | ||
617 | 419 | |||
618 | 420 | ldap_value_free(gid); | ||
619 | 421 | |||
620 | 422 | user_cache.insert(user, table, true); | ||
621 | 423 | |||
622 | 424 | return false; | ||
623 | 425 | } | ||
624 | 426 | else if(rc != LDAP_COMPARE_FALSE) | ||
625 | 427 | { | ||
626 | 428 | error= "ldap_compare_ext_s failed: "; | ||
627 | 429 | error+= ldap_err2string(rc); | ||
628 | 430 | printerror(); | ||
629 | 431 | |||
630 | 432 | if(uber_val != NULL) | ||
631 | 433 | { | ||
632 | 434 | ber_free(uber_val, 0); | ||
633 | 435 | } | ||
634 | 436 | |||
635 | 437 | ldap_memfree(uattr); | ||
636 | 438 | |||
637 | 439 | if(uid!=NULL) | ||
638 | 440 | ldap_value_free(uid); | ||
639 | 441 | |||
640 | 442 | ldap_value_free(gid); | ||
641 | 443 | |||
642 | 444 | return true; | ||
643 | 445 | } | ||
644 | 446 | |||
645 | 447 | } | ||
646 | 448 | else if( not strcmp(uattr, "uidNumber")) | ||
647 | 449 | { | ||
648 | 450 | uid= ldap_get_values(ldap, entry, uattr); | ||
649 | 451 | |||
650 | 452 | struct berval bval; | ||
651 | 453 | bval.bv_val= uid[0]; | ||
652 | 454 | bval.bv_len= strlen(uid[0]); | ||
653 | 455 | |||
654 | 456 | rc= ldap_compare_ext_s( ldap, | ||
655 | 457 | table_dn.c_str(), | ||
656 | 458 | "allowedUsers", | ||
657 | 459 | &bval, | ||
658 | 460 | NULL, | ||
659 | 461 | NULL); | ||
660 | 462 | |||
661 | 463 | if( rc == LDAP_COMPARE_TRUE ) | ||
662 | 464 | { | ||
663 | 465 | |||
664 | 466 | if(uber_val != NULL) | ||
665 | 467 | { | ||
666 | 468 | ber_free(uber_val, 0); | ||
667 | 469 | } | ||
668 | 470 | ldap_memfree(uattr); | ||
669 | 471 | |||
670 | 472 | if(gid!=NULL) | ||
671 | 473 | ldap_value_free(gid); | ||
672 | 474 | |||
673 | 475 | ldap_value_free(uid); | ||
674 | 476 | |||
675 | 477 | user_cache.insert(user, table, true); | ||
676 | 478 | |||
677 | 479 | return false; | ||
678 | 480 | } | ||
679 | 481 | else if(rc != LDAP_COMPARE_FALSE) | ||
680 | 482 | { | ||
681 | 483 | error= "ldap_compare_ext_s failed: "; | ||
682 | 484 | error+= ldap_err2string(rc); | ||
683 | 485 | printerror(); | ||
684 | 486 | |||
685 | 487 | if(uber_val != NULL) | ||
686 | 488 | { | ||
687 | 489 | ber_free(uber_val, 0); | ||
688 | 490 | } | ||
689 | 491 | |||
690 | 492 | ldap_memfree(uattr); | ||
691 | 493 | |||
692 | 494 | if(gid!=NULL) | ||
693 | 495 | ldap_value_free(gid); | ||
694 | 496 | |||
695 | 497 | ldap_value_free(uid); | ||
696 | 498 | |||
697 | 499 | return true; | ||
698 | 500 | } | ||
699 | 501 | } | ||
700 | 502 | } | ||
701 | 503 | |||
702 | 504 | if(uber_val != NULL) | ||
703 | 505 | { | ||
704 | 506 | ber_free(uber_val, 0); | ||
705 | 507 | } | ||
706 | 508 | |||
707 | 509 | ldap_memfree(uattr); | ||
708 | 510 | |||
709 | 511 | const char *group_attrs[]= { "gidNumber", | ||
710 | 512 | NULL | ||
711 | 513 | }; | ||
712 | 514 | |||
713 | 515 | LDAPMessage *group_response; | ||
714 | 516 | |||
715 | 517 | string filter= "(memberUID="; | ||
716 | 518 | filter+= uid[0]; | ||
717 | 519 | filter+= ")"; | ||
718 | 520 | |||
719 | 521 | rc= ldap_search_ext_s(ldap, | ||
720 | 522 | groups_dir.c_str(), | ||
721 | 523 | LDAP_SCOPE_ONELEVEL, | ||
722 | 524 | filter.c_str(), | ||
723 | 525 | const_cast<char**>(group_attrs), | ||
724 | 526 | 0, | ||
725 | 527 | NULL, | ||
726 | 528 | NULL, | ||
727 | 529 | NULL, | ||
728 | 530 | LDAP_NO_LIMIT, | ||
729 | 531 | &group_response); | ||
730 | 532 | |||
731 | 533 | if( rc != LDAP_SUCCESS) | ||
732 | 534 | { | ||
733 | 535 | error= "ldap_search_ext_s: "; | ||
734 | 536 | error+= ldap_err2string(rc); | ||
735 | 537 | printerror(); | ||
736 | 538 | ldap_value_free(uid); | ||
737 | 539 | ldap_value_free(gid); | ||
738 | 540 | |||
739 | 541 | return true; | ||
740 | 542 | } | ||
741 | 543 | |||
742 | 544 | LDAPMessage *gentry= ldap_first_entry(ldap, group_response); | ||
743 | 545 | ldap_entries= ldap_count_entries(ldap, gentry); | ||
744 | 546 | |||
745 | 547 | if(ldap_entries == 0 || ldap_entries == -1) | ||
746 | 548 | { | ||
747 | 549 | ldap_value_free(gid); | ||
748 | 550 | ldap_value_free(uid); | ||
749 | 551 | ldap_msgfree(gentry); | ||
750 | 552 | ldap_msgfree(group_response); | ||
751 | 553 | |||
752 | 554 | return true; | ||
753 | 555 | } | ||
754 | 556 | |||
755 | 557 | BerElement *gber; | ||
756 | 558 | char *gattr= ldap_first_attribute(ldap, gentry, &gber); // it has only one attribute, gidNumber | ||
757 | 559 | |||
758 | 560 | if(gattr == NULL) | ||
759 | 561 | { | ||
760 | 562 | ldap_value_free(gid); | ||
761 | 563 | ldap_value_free(uid); | ||
762 | 564 | if(gber != NULL) | ||
763 | 565 | { | ||
764 | 566 | ber_free(gber, 0); | ||
765 | 567 | } | ||
766 | 568 | ldap_msgfree(group_response); | ||
767 | 569 | ldap_msgfree(gentry); | ||
768 | 570 | return true; | ||
769 | 571 | } | ||
770 | 572 | |||
771 | 573 | char **groups= ldap_get_values(ldap, gentry, gattr); // we have the gidNumber attribute of users' supplementaries groups | ||
772 | 574 | |||
773 | 575 | if(groups == NULL) | ||
774 | 576 | { | ||
775 | 577 | ldap_value_free(gid); | ||
776 | 578 | ldap_value_free(uid); | ||
777 | 579 | if( gber != NULL ) | ||
778 | 580 | { | ||
779 | 581 | ber_free(gber, 0); | ||
780 | 582 | } | ||
781 | 583 | ldap_msgfree(group_response); | ||
782 | 584 | ldap_msgfree(gentry); | ||
783 | 585 | return true; | ||
784 | 586 | } | ||
785 | 587 | |||
786 | 588 | int num_of_val= ldap_count_values(groups) - 1; | ||
787 | 589 | |||
788 | 590 | while( num_of_val >= 0) | ||
789 | 591 | { | ||
790 | 592 | struct berval bval; | ||
791 | 593 | bval.bv_len= strlen(groups[num_of_val]); | ||
792 | 594 | bval.bv_val= groups[num_of_val]; | ||
793 | 595 | |||
794 | 596 | rc= ldap_compare_ext_s( ldap, | ||
795 | 597 | table_dn.c_str(), | ||
796 | 598 | "allowedGroups", | ||
797 | 599 | &bval, | ||
798 | 600 | NULL, | ||
799 | 601 | NULL); | ||
800 | 602 | |||
801 | 603 | if( rc == LDAP_COMPARE_TRUE ) | ||
802 | 604 | { | ||
803 | 605 | |||
804 | 606 | if(gber != NULL) | ||
805 | 607 | { | ||
806 | 608 | ber_free(gber, 0); | ||
807 | 609 | } | ||
808 | 610 | ldap_memfree(gattr); | ||
809 | 611 | ldap_value_free(groups); | ||
810 | 612 | ldap_value_free(gid); | ||
811 | 613 | ldap_value_free(uid); | ||
812 | 614 | ldap_msgfree(gentry); | ||
813 | 615 | |||
814 | 616 | user_cache.insert(user, table, true); | ||
815 | 617 | |||
816 | 618 | return false; | ||
817 | 619 | } | ||
818 | 620 | else if( rc != LDAP_COMPARE_FALSE ) | ||
819 | 621 | { | ||
820 | 622 | error= "ldap_compare_ext_s failed: "; | ||
821 | 623 | error+= ldap_err2string(rc); | ||
822 | 624 | printerror(); | ||
823 | 625 | |||
824 | 626 | if(gber != NULL) | ||
825 | 627 | { | ||
826 | 628 | ber_free(gber, 0); | ||
827 | 629 | } | ||
828 | 630 | |||
829 | 631 | ldap_memfree(gattr); | ||
830 | 632 | ldap_value_free(groups); | ||
831 | 633 | ldap_value_free(gid); | ||
832 | 634 | ldap_value_free(uid); | ||
833 | 635 | ldap_msgfree(gentry); | ||
834 | 636 | |||
835 | 637 | return true; | ||
836 | 638 | } | ||
837 | 639 | |||
838 | 640 | num_of_val--; | ||
839 | 641 | } | ||
840 | 642 | |||
841 | 643 | if(gber != NULL) | ||
842 | 644 | { | ||
843 | 645 | ber_free(gber, 0); | ||
844 | 646 | } | ||
845 | 647 | |||
846 | 648 | ldap_memfree(gattr); | ||
847 | 649 | ldap_value_free(groups); | ||
848 | 650 | ldap_value_free(gid); | ||
849 | 651 | ldap_value_free(uid); | ||
850 | 652 | ldap_msgfree(gentry); | ||
851 | 653 | ldap_msgfree(group_response); | ||
852 | 654 | |||
853 | 655 | user_cache.insert(user, table, false); | ||
854 | 656 | |||
855 | 657 | return true; | ||
856 | 658 | } | ||
857 | 659 | |||
858 | 660 | |||
859 | 661 | /** | ||
860 | 662 | * check_if_allowed returns TRUE if user is NOT authorized in target schema. Otherwise, it returns FALSE. | ||
861 | 663 | * check_if_allowed function, checks if uidNumber attribute of user's LDAP record matches with | ||
862 | 664 | * allowedUsers attribute of schema's LDAP record or gidNumber matches with allowedGroups. | ||
863 | 665 | * If neither of them matches, check_if_allowed search for the supplementaries groups of user | ||
864 | 666 | * and returns true if none of them is allowed. Otherwise it returns false. | ||
865 | 667 | */ | ||
866 | 668 | |||
867 | 669 | bool LDAP_policy::check_if_allowed(LDAPMessage *u_rep, const drizzled::identifier::User &user, const drizzled::identifier::Schema& schema) | ||
868 | 670 | { | ||
869 | 671 | LDAPMessage *entry= ldap_first_entry(ldap, u_rep); | ||
870 | 672 | int ldap_entries= ldap_count_entries(ldap, entry); | ||
871 | 673 | if(ldap_entries == 0 || ldap_entries == -1) | ||
872 | 674 | { | ||
873 | 675 | return true; | ||
874 | 676 | } | ||
875 | 677 | |||
876 | 678 | int rc; | ||
877 | 679 | string user_id; | ||
878 | 680 | char *uattr, **gid= NULL, **uid= NULL; | ||
879 | 681 | uid= NULL; | ||
880 | 682 | BerElement *uber_val; | ||
881 | 683 | string schema_dn= "cn=" + schema.getSchemaName() + "," + schemas_dir; | ||
882 | 684 | |||
883 | 685 | for(uattr= ldap_first_attribute(ldap, entry, &uber_val); | ||
884 | 686 | uattr!=NULL; | ||
885 | 687 | uattr=ldap_next_attribute(ldap, entry, uber_val)) | ||
886 | 688 | { | ||
887 | 689 | |||
888 | 690 | if(not strcmp(uattr, "gidNumber")) | ||
889 | 691 | { | ||
890 | 692 | gid= ldap_get_values(ldap, entry, uattr); | ||
891 | 693 | |||
892 | 694 | struct berval bval; | ||
893 | 695 | bval.bv_val= gid[0]; | ||
894 | 696 | bval.bv_len= strlen(gid[0]); | ||
895 | 697 | |||
896 | 698 | rc= ldap_compare_ext_s( ldap, | ||
897 | 699 | schema_dn.c_str(), | ||
898 | 700 | "allowedGroups", | ||
899 | 701 | &bval, | ||
900 | 702 | NULL, | ||
901 | 703 | NULL); | ||
902 | 704 | |||
903 | 705 | if( rc == LDAP_COMPARE_TRUE) | ||
904 | 706 | { | ||
905 | 707 | if(uber_val != NULL) | ||
906 | 708 | { | ||
907 | 709 | ber_free(uber_val, 0); | ||
908 | 710 | } | ||
909 | 711 | ldap_memfree(uattr); | ||
910 | 712 | ldap_value_free(gid); | ||
911 | 713 | |||
912 | 714 | if(uid != NULL) | ||
913 | 715 | ldap_value_free(uid); | ||
914 | 716 | |||
915 | 717 | user_cache.insert(user, schema, true); | ||
916 | 718 | |||
917 | 719 | return false; | ||
918 | 720 | } | ||
919 | 721 | else if(rc != LDAP_COMPARE_FALSE) | ||
920 | 722 | { | ||
921 | 723 | //Maybe when return code is "No such object" I could add in cache. | ||
922 | 724 | |||
923 | 725 | error= "ldap_compare_ext_s failed: "; | ||
924 | 726 | error+= ldap_err2string(rc); | ||
925 | 727 | printerror(); | ||
926 | 728 | |||
927 | 729 | if(uber_val != NULL) | ||
928 | 730 | { | ||
929 | 731 | ber_free(uber_val, 0); | ||
930 | 732 | } | ||
931 | 733 | |||
932 | 734 | ldap_memfree(uattr); | ||
933 | 735 | ldap_value_free(gid); | ||
934 | 736 | |||
935 | 737 | if( uid != NULL) | ||
936 | 738 | ldap_value_free(uid); | ||
937 | 739 | |||
938 | 740 | return true; | ||
939 | 741 | } | ||
940 | 742 | } | ||
941 | 743 | else if (not strcmp(uattr, "uidNumber")) | ||
942 | 744 | { | ||
943 | 745 | uid= ldap_get_values(ldap, entry, uattr); | ||
944 | 746 | |||
945 | 747 | struct berval bval; | ||
946 | 748 | bval.bv_val= uid[0]; | ||
947 | 749 | bval.bv_len= strlen(uid[0]); | ||
948 | 750 | |||
949 | 751 | rc= ldap_compare_ext_s( ldap, | ||
950 | 752 | schema_dn.c_str(), | ||
951 | 753 | "allowedUsers", | ||
952 | 754 | &bval, | ||
953 | 755 | NULL, | ||
954 | 756 | NULL); | ||
955 | 757 | |||
956 | 758 | if( rc == LDAP_COMPARE_TRUE) | ||
957 | 759 | { | ||
958 | 760 | |||
959 | 761 | if(uber_val != NULL) | ||
960 | 762 | { | ||
961 | 763 | ber_free(uber_val, 0); | ||
962 | 764 | } | ||
963 | 765 | |||
964 | 766 | if(gid != NULL) | ||
965 | 767 | ldap_value_free(gid); | ||
966 | 768 | |||
967 | 769 | ldap_memfree(uattr); | ||
968 | 770 | ldap_value_free(uid); | ||
969 | 771 | |||
970 | 772 | user_cache.insert(user, schema, true); | ||
971 | 773 | |||
972 | 774 | return false; | ||
973 | 775 | } | ||
974 | 776 | else if (rc != LDAP_COMPARE_FALSE) | ||
975 | 777 | { | ||
976 | 778 | |||
977 | 779 | error= "ldap_compare_ext_s failed: "; | ||
978 | 780 | error+= ldap_err2string(rc); | ||
979 | 781 | printerror(); | ||
980 | 782 | if(uber_val != NULL) | ||
981 | 783 | { | ||
982 | 784 | ber_free(uber_val, 0); | ||
983 | 785 | } | ||
984 | 786 | ldap_memfree(uattr); | ||
985 | 787 | |||
986 | 788 | if(uid != NULL) | ||
987 | 789 | ldap_value_free(uid); | ||
988 | 790 | |||
989 | 791 | ldap_value_free(gid); | ||
990 | 792 | |||
991 | 793 | return true; | ||
992 | 794 | } | ||
993 | 795 | } | ||
994 | 796 | } | ||
995 | 797 | |||
996 | 798 | ldap_memfree(uattr); | ||
997 | 799 | |||
998 | 800 | if(uber_val != NULL) | ||
999 | 801 | { | ||
1000 | 802 | ber_free(uber_val, 0); | ||
1001 | 803 | } | ||
1002 | 804 | |||
1003 | 805 | if(uid==NULL) | ||
1004 | 806 | { | ||
1005 | 807 | return true; | ||
1006 | 808 | } | ||
1007 | 809 | const char *gattrs[]= {"gidNumber", | ||
1008 | 810 | NULL | ||
1009 | 811 | }; | ||
1010 | 812 | |||
1011 | 813 | LDAPMessage *group_response; | ||
1012 | 814 | |||
1013 | 815 | string filter= "(memberUID="; | ||
1014 | 816 | filter+= uid[0]; | ||
1015 | 817 | filter+= ")"; | ||
1016 | 818 | |||
1017 | 819 | rc= ldap_search_ext_s(ldap, | ||
1018 | 820 | groups_dir.c_str(), | ||
1019 | 821 | LDAP_SCOPE_ONELEVEL, | ||
1020 | 822 | filter.c_str(), | ||
1021 | 823 | const_cast<char**>(gattrs), | ||
1022 | 824 | 0, | ||
1023 | 825 | NULL, | ||
1024 | 826 | NULL, | ||
1025 | 827 | NULL, | ||
1026 | 828 | LDAP_NO_LIMIT, | ||
1027 | 829 | &group_response); | ||
1028 | 830 | |||
1029 | 831 | if(rc != LDAP_SUCCESS) | ||
1030 | 832 | { | ||
1031 | 833 | error= "ldap_search_ext_s: "; | ||
1032 | 834 | error+= ldap_err2string(rc); | ||
1033 | 835 | printerror(); | ||
1034 | 836 | return true; | ||
1035 | 837 | } | ||
1036 | 838 | |||
1037 | 839 | LDAPMessage *gentry= ldap_first_entry(ldap, group_response); | ||
1038 | 840 | BerElement *gber; | ||
1039 | 841 | |||
1040 | 842 | char *gattr= ldap_first_attribute(ldap, gentry, &gber); | ||
1041 | 843 | char **groups= ldap_get_values(ldap, gentry, gattr); // exoyme ta groups sta opoia anoikei o user | ||
1042 | 844 | |||
1043 | 845 | for(int num_of_values= ldap_count_values(groups) - 1; num_of_values >= 0; num_of_values--) | ||
1044 | 846 | { | ||
1045 | 847 | struct berval bval; | ||
1046 | 848 | bval.bv_len= strlen(groups[num_of_values]); | ||
1047 | 849 | bval.bv_val= groups[num_of_values]; | ||
1048 | 850 | |||
1049 | 851 | if( ldap_compare_ext_s( ldap, | ||
1050 | 852 | schema_dn.c_str(), | ||
1051 | 853 | "allowedGroups", | ||
1052 | 854 | &bval, | ||
1053 | 855 | NULL, | ||
1054 | 856 | NULL) == LDAP_COMPARE_TRUE) | ||
1055 | 857 | { | ||
1056 | 858 | |||
1057 | 859 | if(gber != NULL) | ||
1058 | 860 | { | ||
1059 | 861 | ber_free(gber, 0); | ||
1060 | 862 | } | ||
1061 | 863 | ldap_memfree(gattr); | ||
1062 | 864 | ldap_value_free(groups); | ||
1063 | 865 | |||
1064 | 866 | user_cache.insert(user, schema, true); | ||
1065 | 867 | |||
1066 | 868 | return false; | ||
1067 | 869 | } | ||
1068 | 870 | } | ||
1069 | 871 | |||
1070 | 872 | if(gber != NULL) | ||
1071 | 873 | { | ||
1072 | 874 | ber_free(gber, 0); | ||
1073 | 875 | } | ||
1074 | 876 | ldap_memfree(gattr); | ||
1075 | 877 | ldap_value_free(groups); | ||
1076 | 878 | ldap_msgfree(group_response); | ||
1077 | 879 | |||
1078 | 880 | user_cache.insert(user, schema, false); | ||
1079 | 881 | |||
1080 | 882 | return true; | ||
1081 | 883 | } | ||
1082 | 884 | |||
1083 | 885 | bool LDAP_policy::restrictTable(const drizzled::identifier::User &user_ctx, | ||
1084 | 886 | const drizzled::identifier::Table& table) | ||
1085 | 887 | { | ||
1086 | 888 | |||
1087 | 889 | if( table.getSchemaName() == "information_schema" || table.getSchemaName() == "INFORMATION_SCHEMA") | ||
1088 | 890 | { | ||
1089 | 891 | return false; | ||
1090 | 892 | } | ||
1091 | 893 | |||
1092 | 894 | LDAPMessage *user_response; | ||
1093 | 895 | |||
1094 | 896 | const char *uattrs[]= { "uidNumber", | ||
1095 | 897 | "gidNumber", | ||
1096 | 898 | NULL | ||
1097 | 899 | }; | ||
1098 | 900 | |||
1099 | 901 | string filter= "(&(cn=" + user_ctx.username() + ")(BelongInSchema=" + table.getSchemaName() + "))"; | ||
1100 | 902 | /* Schema attribute allows to determine from which schema, is the table we are looking for. | ||
1101 | 903 | Still I need to implement the BelongInSchema schema */ | ||
1102 | 904 | |||
1103 | 905 | CacheResponse cache_res= user_cache.is_authorized(user_ctx, table); | ||
1104 | 906 | |||
1105 | 907 | if(cache_res == ALLOWED) | ||
1106 | 908 | { | ||
1107 | 909 | return false; | ||
1108 | 910 | } | ||
1109 | 911 | else if(cache_res == DENIED) | ||
1110 | 912 | { | ||
1111 | 913 | return true; | ||
1112 | 914 | } | ||
1113 | 915 | |||
1114 | 916 | int return_code= ldap_search_ext_s( ldap, | ||
1115 | 917 | users_dir.c_str(), | ||
1116 | 918 | LDAP_SCOPE_ONELEVEL, | ||
1117 | 919 | filter.c_str(), | ||
1118 | 920 | const_cast<char**>(uattrs), | ||
1119 | 921 | 0, | ||
1120 | 922 | NULL, | ||
1121 | 923 | NULL, | ||
1122 | 924 | NULL, | ||
1123 | 925 | 1, | ||
1124 | 926 | &user_response); | ||
1125 | 927 | |||
1126 | 928 | if(return_code != LDAP_SUCCESS) | ||
1127 | 929 | { | ||
1128 | 930 | error= "ldap_search_ext_s failed:"; | ||
1129 | 931 | error+= ldap_err2string(return_code); | ||
1130 | 932 | printerror(); | ||
1131 | 933 | |||
1132 | 934 | return true; | ||
1133 | 935 | } | ||
1134 | 936 | |||
1135 | 937 | bool restr= check_if_allowed(user_response, user_ctx, table); | ||
1136 | 938 | |||
1137 | 939 | ldap_msgfree(user_response); | ||
1138 | 940 | |||
1139 | 941 | return restr; | ||
1140 | 942 | } | ||
1141 | 943 | |||
1142 | 944 | bool LDAP_policy::restrictSchema(const drizzled::identifier::User &user_ctx, | ||
1143 | 945 | const drizzled::identifier::Schema& schema) | ||
1144 | 946 | { | ||
1145 | 947 | |||
1146 | 948 | if(schema.getSchemaName() == "information_schema" || schema.getSchemaName() == "INFORMATION_SCHEMA") | ||
1147 | 949 | { | ||
1148 | 950 | return false; | ||
1149 | 951 | } | ||
1150 | 952 | |||
1151 | 953 | CacheResponse cache_res= user_cache.is_authorized(user_ctx, schema); | ||
1152 | 954 | |||
1153 | 955 | if(cache_res == ALLOWED) | ||
1154 | 956 | { | ||
1155 | 957 | return false; | ||
1156 | 958 | } | ||
1157 | 959 | else if (cache_res == DENIED) | ||
1158 | 960 | { | ||
1159 | 961 | return true; | ||
1160 | 962 | } | ||
1161 | 963 | |||
1162 | 964 | LDAPMessage *user_response; | ||
1163 | 965 | const char *uattrs[]= { "uidNumber", | ||
1164 | 966 | "gidNumber", | ||
1165 | 967 | NULL | ||
1166 | 968 | }; | ||
1167 | 969 | string filter = "(cn=" + user_ctx.username() + ")"; | ||
1168 | 970 | |||
1169 | 971 | int return_code= ldap_search_ext_s(ldap, | ||
1170 | 972 | users_dir.c_str(), | ||
1171 | 973 | LDAP_SCOPE_ONELEVEL, | ||
1172 | 974 | filter.c_str(), | ||
1173 | 975 | const_cast<char**>(uattrs), | ||
1174 | 976 | 0, | ||
1175 | 977 | NULL, | ||
1176 | 978 | NULL, | ||
1177 | 979 | NULL, | ||
1178 | 980 | 1, | ||
1179 | 981 | &user_response); //search for gidNumber and uidNumber in users' directory | ||
1180 | 982 | |||
1181 | 983 | if(return_code != LDAP_SUCCESS) { | ||
1182 | 984 | error= "ldap_search_ext_s failed:"; | ||
1183 | 985 | error+= ldap_err2string(return_code); | ||
1184 | 986 | printerror(); | ||
1185 | 987 | return true; | ||
1186 | 988 | } | ||
1187 | 989 | |||
1188 | 990 | bool restr= check_if_allowed(user_response, user_ctx, schema); | ||
1189 | 991 | ldap_msgfree(user_response); | ||
1190 | 992 | |||
1191 | 993 | return restr; | ||
1192 | 994 | } | ||
1193 | 995 | |||
1194 | 996 | bool LDAP_policy::connect(void) | ||
1195 | 997 | { | ||
1196 | 998 | int return_code= ldap_initialize(&ldap, (char *)uri.c_str()); | ||
1197 | 999 | |||
1198 | 1000 | if (return_code != LDAP_SUCCESS) | ||
1199 | 1001 | { | ||
1200 | 1002 | error= "ldap_initialize failed: "; | ||
1201 | 1003 | error+= ldap_err2string(return_code); | ||
1202 | 1004 | printerror(); | ||
1203 | 1005 | return false; | ||
1204 | 1006 | } | ||
1205 | 1007 | |||
1206 | 1008 | int version= 3; | ||
1207 | 1009 | return_code= ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); | ||
1208 | 1010 | |||
1209 | 1011 | if (return_code != LDAP_SUCCESS) | ||
1210 | 1012 | { | ||
1211 | 1013 | ldap_unbind_ext_s(ldap, NULL, NULL); | ||
1212 | 1014 | ldap= NULL; | ||
1213 | 1015 | error= "ldap_set_option failed: "; | ||
1214 | 1016 | error+= ldap_err2string(return_code); | ||
1215 | 1017 | printerror(); | ||
1216 | 1018 | return false; | ||
1217 | 1019 | } | ||
1218 | 1020 | |||
1219 | 1021 | return_code= ldap_simple_bind_s(ldap, NULL, NULL); | ||
1220 | 1022 | |||
1221 | 1023 | if (return_code != LDAP_SUCCESS) | ||
1222 | 1024 | { | ||
1223 | 1025 | ldap_unbind(ldap); | ||
1224 | 1026 | ldap= NULL; | ||
1225 | 1027 | error= "ldap_simple_bind_s failed: "; | ||
1226 | 1028 | error+= ldap_err2string(return_code); | ||
1227 | 1029 | printerror(); | ||
1228 | 1030 | |||
1229 | 1031 | return false; | ||
1230 | 1032 | } | ||
1231 | 1033 | |||
1232 | 1034 | return true; | ||
1233 | 1035 | |||
1234 | 1036 | } | ||
1235 | 1037 | |||
1236 | 1038 | inline bool CacheItem::is_valid() const | ||
1237 | 1039 | { | ||
1238 | 1040 | time_t temp_timer; | ||
1239 | 1041 | temp_timer = time(NULL); | ||
1240 | 1042 | |||
1241 | 1043 | if(temp_timer - timer > cache_timeout) | ||
1242 | 1044 | { | ||
1243 | 1045 | return false; | ||
1244 | 1046 | } | ||
1245 | 1047 | else | ||
1246 | 1048 | { | ||
1247 | 1049 | return true; | ||
1248 | 1050 | } | ||
1249 | 1051 | } | ||
1250 | 1052 | |||
1251 | 1053 | void UserCache::insert(const drizzled::identifier::User &user, const drizzled::identifier::Table &table, bool auth) | ||
1252 | 1054 | { | ||
1253 | 1055 | string user_name= user.username(); | ||
1254 | 1056 | |||
1255 | 1057 | if(table_cache.count(user_name) != 1) // user not found, need to insert a new one | ||
1256 | 1058 | { | ||
1257 | 1059 | CacheItem new_cache_item(user_name, table.getTableName(), table.getSchemaName(), auth); | ||
1258 | 1060 | table_cache.insert(CacheMap::value_type(user_name, ItemDeque())); | ||
1259 | 1061 | table_cache[user_name].push_back(new_cache_item); | ||
1260 | 1062 | } | ||
1261 | 1063 | else //user found | ||
1262 | 1064 | { | ||
1263 | 1065 | CacheItem new_cache_item(user_name, table.getTableName(), table.getSchemaName(), auth); | ||
1264 | 1066 | table_cache[user_name].push_back(new_cache_item); | ||
1265 | 1067 | } | ||
1266 | 1068 | } | ||
1267 | 1069 | |||
1268 | 1070 | void UserCache::insert(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema, bool auth) | ||
1269 | 1071 | { | ||
1270 | 1072 | string user_name= user.username(); | ||
1271 | 1073 | |||
1272 | 1074 | if(schema_cache.count(user.username()) != 1) | ||
1273 | 1075 | { | ||
1274 | 1076 | CacheItem new_cache_item(user_name, "", schema.getSchemaName(), auth); | ||
1275 | 1077 | schema_cache.insert(CacheMap::value_type(user_name, ItemDeque())); | ||
1276 | 1078 | schema_cache[user_name].push_back(new_cache_item); | ||
1277 | 1079 | } | ||
1278 | 1080 | else | ||
1279 | 1081 | { | ||
1280 | 1082 | CacheItem new_cache_item(user_name, "", schema.getSchemaName(), auth); | ||
1281 | 1083 | schema_cache[user_name].push_back(new_cache_item); | ||
1282 | 1084 | } | ||
1283 | 1085 | } | ||
1284 | 1086 | |||
1285 | 1087 | int UserCache::remove(const drizzled::identifier::User &user, const drizzled::identifier::Table &table) | ||
1286 | 1088 | { | ||
1287 | 1089 | CacheMap_Iterator map_iterator; | ||
1288 | 1090 | map_iterator= table_cache.find(user.username()); | ||
1289 | 1091 | |||
1290 | 1092 | if(map_iterator == table_cache.end() ) | ||
1291 | 1093 | { | ||
1292 | 1094 | return -1; | ||
1293 | 1095 | } | ||
1294 | 1096 | |||
1295 | 1097 | ItemDeque::iterator deque_iter; | ||
1296 | 1098 | |||
1297 | 1099 | string user_name= user.username(); | ||
1298 | 1100 | string table_name= table.getTableName(); | ||
1299 | 1101 | string schema_name= table.getSchemaName(); | ||
1300 | 1102 | |||
1301 | 1103 | for( deque_iter= table_cache[user_name].begin(); | ||
1302 | 1104 | deque_iter != table_cache[user_name].end(); | ||
1303 | 1105 | deque_iter++) | ||
1304 | 1106 | { | ||
1305 | 1107 | if( (deque_iter->getTable() == table_name) | ||
1306 | 1108 | && (deque_iter->getSchema() == schema_name) ) | ||
1307 | 1109 | { | ||
1308 | 1110 | break; | ||
1309 | 1111 | } | ||
1310 | 1112 | } | ||
1311 | 1113 | |||
1312 | 1114 | if(deque_iter != table_cache[user_name].end()) | ||
1313 | 1115 | { | ||
1314 | 1116 | table_cache[user_name].erase(deque_iter); | ||
1315 | 1117 | |||
1316 | 1118 | return 0; | ||
1317 | 1119 | } | ||
1318 | 1120 | return -1; | ||
1319 | 1121 | } | ||
1320 | 1122 | |||
1321 | 1123 | int UserCache::remove(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema) | ||
1322 | 1124 | { | ||
1323 | 1125 | CacheMap_Iterator map_iterator; | ||
1324 | 1126 | map_iterator= schema_cache.find(user.username()); | ||
1325 | 1127 | |||
1326 | 1128 | if( map_iterator == schema_cache.end()) | ||
1327 | 1129 | { | ||
1328 | 1130 | return -1; | ||
1329 | 1131 | } | ||
1330 | 1132 | |||
1331 | 1133 | ItemDeque::iterator deque_iter; | ||
1332 | 1134 | |||
1333 | 1135 | string user_name= user.username(); | ||
1334 | 1136 | string schema_name= schema.getSchemaName(); | ||
1335 | 1137 | |||
1336 | 1138 | for( deque_iter= schema_cache[user_name].begin(); | ||
1337 | 1139 | deque_iter != schema_cache[user_name].end(); | ||
1338 | 1140 | deque_iter++) | ||
1339 | 1141 | { | ||
1340 | 1142 | if( deque_iter->getSchema() == schema_name) | ||
1341 | 1143 | { | ||
1342 | 1144 | break; | ||
1343 | 1145 | } | ||
1344 | 1146 | } | ||
1345 | 1147 | |||
1346 | 1148 | if( deque_iter != schema_cache[user_name].end()) | ||
1347 | 1149 | { | ||
1348 | 1150 | schema_cache[user_name].erase(deque_iter); | ||
1349 | 1151 | |||
1350 | 1152 | return 0; | ||
1351 | 1153 | } | ||
1352 | 1154 | return -1; | ||
1353 | 1155 | } | ||
1354 | 1156 | |||
1355 | 1157 | CacheResponse UserCache::is_authorized(const drizzled::identifier::User &user, const drizzled::identifier::Schema &schema) | ||
1356 | 1158 | { | ||
1357 | 1159 | if(schema_cache.size() == 0) | ||
1358 | 1160 | return NOT_FOUND; | ||
1359 | 1161 | |||
1360 | 1162 | CacheMap_Iterator map_iterator; | ||
1361 | 1163 | map_iterator= schema_cache.find(user.username()); | ||
1362 | 1164 | |||
1363 | 1165 | if(map_iterator != schema_cache.end()) | ||
1364 | 1166 | { | ||
1365 | 1167 | ItemDeque::iterator deque_iter; | ||
1366 | 1168 | |||
1367 | 1169 | string user_name= user.username(); | ||
1368 | 1170 | string schema_name= schema.getSchemaName(); | ||
1369 | 1171 | |||
1370 | 1172 | for(deque_iter= schema_cache[user_name].begin(); | ||
1371 | 1173 | deque_iter != schema_cache[user_name].end(); | ||
1372 | 1174 | deque_iter++) | ||
1373 | 1175 | { | ||
1374 | 1176 | if(deque_iter->getSchema() == schema_name) | ||
1375 | 1177 | { | ||
1376 | 1178 | break; | ||
1377 | 1179 | } | ||
1378 | 1180 | } | ||
1379 | 1181 | |||
1380 | 1182 | |||
1381 | 1183 | if(deque_iter != schema_cache[user_name].end()) | ||
1382 | 1184 | { | ||
1383 | 1185 | if(deque_iter->is_valid()) | ||
1384 | 1186 | { | ||
1385 | 1187 | if(deque_iter->is_authorized()) | ||
1386 | 1188 | { | ||
1387 | 1189 | return ALLOWED; | ||
1388 | 1190 | } | ||
1389 | 1191 | else | ||
1390 | 1192 | { | ||
1391 | 1193 | return DENIED; | ||
1392 | 1194 | } | ||
1393 | 1195 | } | ||
1394 | 1196 | else | ||
1395 | 1197 | { | ||
1396 | 1198 | remove(user, schema); | ||
1397 | 1199 | return NOT_FOUND; | ||
1398 | 1200 | } | ||
1399 | 1201 | } | ||
1400 | 1202 | else //not found | ||
1401 | 1203 | { | ||
1402 | 1204 | return NOT_FOUND; | ||
1403 | 1205 | } | ||
1404 | 1206 | } | ||
1405 | 1207 | else | ||
1406 | 1208 | { | ||
1407 | 1209 | return NOT_FOUND; | ||
1408 | 1210 | } | ||
1409 | 1211 | } | ||
1410 | 1212 | |||
1411 | 1213 | CacheResponse UserCache::is_authorized(const drizzled::identifier::User &user, const drizzled::identifier::Table &table) | ||
1412 | 1214 | { | ||
1413 | 1215 | if(table_cache.size() == 0) | ||
1414 | 1216 | return NOT_FOUND; | ||
1415 | 1217 | |||
1416 | 1218 | CacheMap_Iterator map_iterator; | ||
1417 | 1219 | map_iterator= table_cache.find(user.username()); | ||
1418 | 1220 | |||
1419 | 1221 | if(map_iterator != table_cache.end()) | ||
1420 | 1222 | { | ||
1421 | 1223 | ItemDeque::iterator deque_iter; | ||
1422 | 1224 | |||
1423 | 1225 | string user_name= user.username(); | ||
1424 | 1226 | string table_name= table.getTableName(); | ||
1425 | 1227 | string schema_name= table.getSchemaName(); | ||
1426 | 1228 | |||
1427 | 1229 | for(deque_iter= table_cache[user_name].begin(); | ||
1428 | 1230 | deque_iter != table_cache[user_name].end(); | ||
1429 | 1231 | deque_iter++) | ||
1430 | 1232 | { | ||
1431 | 1233 | if(deque_iter->getTable() == table_name | ||
1432 | 1234 | && deque_iter->getSchema() == schema_name) | ||
1433 | 1235 | { | ||
1434 | 1236 | break; | ||
1435 | 1237 | } | ||
1436 | 1238 | } | ||
1437 | 1239 | |||
1438 | 1240 | |||
1439 | 1241 | if(deque_iter != table_cache[user_name].end()) | ||
1440 | 1242 | { | ||
1441 | 1243 | if(deque_iter->is_valid()) | ||
1442 | 1244 | { | ||
1443 | 1245 | if(deque_iter->is_authorized()) | ||
1444 | 1246 | { | ||
1445 | 1247 | return ALLOWED; | ||
1446 | 1248 | } | ||
1447 | 1249 | else | ||
1448 | 1250 | { | ||
1449 | 1251 | return DENIED; | ||
1450 | 1252 | } | ||
1451 | 1253 | } | ||
1452 | 1254 | else //cache item has expired, so we should remove it | ||
1453 | 1255 | { | ||
1454 | 1256 | remove(user, table); | ||
1455 | 1257 | return NOT_FOUND; | ||
1456 | 1258 | } | ||
1457 | 1259 | } | ||
1458 | 1260 | else // table/schema for the user does not exist in cache | ||
1459 | 1261 | { | ||
1460 | 1262 | return NOT_FOUND; | ||
1461 | 1263 | } | ||
1462 | 1264 | } | ||
1463 | 1265 | else //user does not exist in cache | ||
1464 | 1266 | { | ||
1465 | 1267 | return NOT_FOUND; | ||
1466 | 1268 | } | ||
1467 | 1269 | } | ||
1468 | 1270 | |||
1469 | 1271 | } /* namespace ldap_policy */ | ||
1470 | 1272 | |||
1471 | 1273 | DRIZZLE_DECLARE_PLUGIN | ||
1472 | 1274 | { | ||
1473 | 1275 | DRIZZLE_VERSION_ID, | ||
1474 | 1276 | "ldap_policy", | ||
1475 | 1277 | "0.1", | ||
1476 | 1278 | "Sialveras Zisis", | ||
1477 | 1279 | N_("LDAP based authorization system"), | ||
1478 | 1280 | PLUGIN_LICENSE_GPL, | ||
1479 | 1281 | ldap_policy::init, | ||
1480 | 1282 | NULL, | ||
1481 | 1283 | ldap_policy::init_options | ||
1482 | 1284 | } | ||
1483 | 1285 | DRIZZLE_DECLARE_PLUGIN_END; | ||
1484 | 1286 | |||
1485 | 0 | 1287 | ||
1486 | === added file 'plugin/ldap_policy/ldap_policy.hpp' | |||
1487 | --- plugin/ldap_policy/ldap_policy.hpp 1970-01-01 00:00:00 +0000 | |||
1488 | +++ plugin/ldap_policy/ldap_policy.hpp 2012-08-21 14:09:20 +0000 | |||
1489 | @@ -0,0 +1,194 @@ | |||
1490 | 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- | ||
1491 | 2 | * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
1492 | 3 | * | ||
1493 | 4 | * Copyright (C) 2012 Zisis Sialveras | ||
1494 | 5 | * | ||
1495 | 6 | * This program is free software; you can redistribute it and/or modify | ||
1496 | 7 | * it under the terms of the GNU General Public License as published by | ||
1497 | 8 | * the Free Software Foundation; version 2 of the License. | ||
1498 | 9 | * | ||
1499 | 10 | * This program is distributed in the hope that it will be useful, | ||
1500 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1501 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1502 | 13 | * GNU General Public License for more details. | ||
1503 | 14 | * | ||
1504 | 15 | * You should have received a copy of the GNU General Public License | ||
1505 | 16 | * along with this program; if not, write to the Free Software | ||
1506 | 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
1507 | 18 | */ | ||
1508 | 19 | |||
1509 | 20 | |||
1510 | 21 | #pragma once | ||
1511 | 22 | |||
1512 | 23 | #include <config.h> | ||
1513 | 24 | |||
1514 | 25 | |||
1515 | 26 | #include <boost/unordered_map.hpp> | ||
1516 | 27 | |||
1517 | 28 | #include <drizzled/plugin/authorization.h> | ||
1518 | 29 | #include <drizzled/plugin.h> | ||
1519 | 30 | |||
1520 | 31 | #include <deque> | ||
1521 | 32 | #include <string> | ||
1522 | 33 | #include <ctime> | ||
1523 | 34 | |||
1524 | 35 | #define LDAP_DEPRECATED 1 | ||
1525 | 36 | #include <ldap.h> | ||
1526 | 37 | |||
1527 | 38 | namespace ldap_policy | ||
1528 | 39 | { | ||
1529 | 40 | |||
1530 | 41 | std::string DEFAULT_URI= "ldap://localhost/"; | ||
1531 | 42 | std::string DEFAULT_USERS_DIR= "ou=users,dc=example,dc=com"; | ||
1532 | 43 | std::string DEFAULT_SCHEMAS_DIR= "ou=schemas,dc=example,dc=com"; | ||
1533 | 44 | std::string DEFAULT_TABLES_DIR= "ou=tables,dc=example,dc=com"; | ||
1534 | 45 | std::string DEFAULT_GROUPS_DIR= "ou=groups,dc=example,dc=com"; | ||
1535 | 46 | time_t DEFAULT_CACHE_TIMEOUT= 500; | ||
1536 | 47 | |||
1537 | 48 | time_t cache_timeout; | ||
1538 | 49 | std::string uri; | ||
1539 | 50 | std::string groups_dir; | ||
1540 | 51 | std::string base_dn; | ||
1541 | 52 | std::string bind_passwd; | ||
1542 | 53 | std::string users_dir; | ||
1543 | 54 | std::string schemas_dir; | ||
1544 | 55 | std::string tables_dir; | ||
1545 | 56 | |||
1546 | 57 | |||
1547 | 58 | class CacheItem | ||
1548 | 59 | { | ||
1549 | 60 | std::string user, table, schema; | ||
1550 | 61 | bool authorized; | ||
1551 | 62 | time_t timer; | ||
1552 | 63 | |||
1553 | 64 | public: | ||
1554 | 65 | |||
1555 | 66 | CacheItem(std::string u, std::string t, std::string s, bool a): user(u), table(t), schema(s), authorized(a) | ||
1556 | 67 | { | ||
1557 | 68 | timer = time(NULL); | ||
1558 | 69 | }; | ||
1559 | 70 | |||
1560 | 71 | /* | ||
1561 | 72 | CacheItem() | ||
1562 | 73 | { | ||
1563 | 74 | gettimeofday(&tv, NULL); | ||
1564 | 75 | }; | ||
1565 | 76 | */ | ||
1566 | 77 | |||
1567 | 78 | ~CacheItem(){}; | ||
1568 | 79 | |||
1569 | 80 | inline bool is_valid() const; | ||
1570 | 81 | |||
1571 | 82 | inline bool is_authorized() | ||
1572 | 83 | { | ||
1573 | 84 | return authorized; | ||
1574 | 85 | }; | ||
1575 | 86 | |||
1576 | 87 | void setTable(std::string t) | ||
1577 | 88 | { | ||
1578 | 89 | table = t; | ||
1579 | 90 | }; | ||
1580 | 91 | |||
1581 | 92 | void setSchema(std::string s) | ||
1582 | 93 | { | ||
1583 | 94 | schema = s; | ||
1584 | 95 | }; | ||
1585 | 96 | |||
1586 | 97 | inline std::string getTable() | ||
1587 | 98 | { | ||
1588 | 99 | return table; | ||
1589 | 100 | }; | ||
1590 | 101 | |||
1591 | 102 | inline std::string getSchema() | ||
1592 | 103 | { | ||
1593 | 104 | return schema; | ||
1594 | 105 | }; | ||
1595 | 106 | |||
1596 | 107 | }; | ||
1597 | 108 | |||
1598 | 109 | typedef std::deque<CacheItem> ItemDeque; | ||
1599 | 110 | typedef boost::unordered_map<std::string, ItemDeque> CacheMap; | ||
1600 | 111 | typedef boost::unordered_map<std::string, ItemDeque>::const_iterator CacheMap_Iterator; | ||
1601 | 112 | |||
1602 | 113 | typedef enum | ||
1603 | 114 | { | ||
1604 | 115 | ALLOWED, | ||
1605 | 116 | DENIED, | ||
1606 | 117 | NOT_FOUND | ||
1607 | 118 | } CacheResponse; | ||
1608 | 119 | |||
1609 | 120 | class UserCache | ||
1610 | 121 | { | ||
1611 | 122 | CacheMap table_cache, schema_cache; | ||
1612 | 123 | |||
1613 | 124 | public: | ||
1614 | 125 | |||
1615 | 126 | UserCache() {}; | ||
1616 | 127 | |||
1617 | 128 | ~UserCache() {}; | ||
1618 | 129 | |||
1619 | 130 | /** | ||
1620 | 131 | * Insert a schema/table in cache for a specific user. | ||
1621 | 132 | * | ||
1622 | 133 | * If the last parametr is true then the user is allowed to access the schema/table. | ||
1623 | 134 | * Otherwise, if it is false, access is denied. | ||
1624 | 135 | */ | ||
1625 | 136 | void insert(const drizzled::identifier::User &, const drizzled::identifier::Table &, bool ); | ||
1626 | 137 | void insert(const drizzled::identifier::User &, const drizzled::identifier::Schema &, bool ); | ||
1627 | 138 | |||
1628 | 139 | /** | ||
1629 | 140 | * Removes a schema/table from cache for a specific user. | ||
1630 | 141 | */ | ||
1631 | 142 | int remove(const drizzled::identifier::User &, const drizzled::identifier::Table &); | ||
1632 | 143 | int remove(const drizzled::identifier::User &, const drizzled::identifier::Schema &); | ||
1633 | 144 | |||
1634 | 145 | /** | ||
1635 | 146 | * Returns if a user is authorized to access target schema/table. | ||
1636 | 147 | */ | ||
1637 | 148 | CacheResponse is_authorized(const drizzled::identifier::User &, const drizzled::identifier::Table &); | ||
1638 | 149 | CacheResponse is_authorized(const drizzled::identifier::User &, const drizzled::identifier::Schema &); | ||
1639 | 150 | |||
1640 | 151 | } user_cache; | ||
1641 | 152 | |||
1642 | 153 | class LDAP_policy : | ||
1643 | 154 | public drizzled::plugin::Authorization | ||
1644 | 155 | { | ||
1645 | 156 | |||
1646 | 157 | std::string error; | ||
1647 | 158 | LDAP *ldap; | ||
1648 | 159 | |||
1649 | 160 | void printerror(); | ||
1650 | 161 | |||
1651 | 162 | bool check_if_allowed(LDAPMessage *, const drizzled::identifier::User &, const drizzled::identifier::Schema& ); | ||
1652 | 163 | bool check_if_allowed(LDAPMessage *, const drizzled::identifier::User &, const drizzled::identifier::Table & ); | ||
1653 | 164 | |||
1654 | 165 | public: | ||
1655 | 166 | LDAP_policy(): | ||
1656 | 167 | drizzled::plugin::Authorization("ldap_policy") | ||
1657 | 168 | { | ||
1658 | 169 | |||
1659 | 170 | } | ||
1660 | 171 | |||
1661 | 172 | ~LDAP_policy() | ||
1662 | 173 | { | ||
1663 | 174 | if(ldap != NULL) | ||
1664 | 175 | ldap_unbind(ldap); | ||
1665 | 176 | } | ||
1666 | 177 | |||
1667 | 178 | bool connect(void); | ||
1668 | 179 | |||
1669 | 180 | virtual bool restrictSchema(const drizzled::identifier::User &user_ctx, | ||
1670 | 181 | const drizzled::identifier::Schema& schema); | ||
1671 | 182 | |||
1672 | 183 | virtual bool restrictProcess(const drizzled::identifier::User &user_ctx, | ||
1673 | 184 | const drizzled::identifier::User &session_ctx); | ||
1674 | 185 | |||
1675 | 186 | virtual bool restrictTable(const drizzled::identifier::User& user_ctx, | ||
1676 | 187 | const drizzled::identifier::Table& table); | ||
1677 | 188 | |||
1678 | 189 | |||
1679 | 190 | }; | ||
1680 | 191 | |||
1681 | 192 | } /* namespace ldap_policy */ | ||
1682 | 193 | |||
1683 | 194 | |||
1684 | 0 | 195 | ||
1685 | === added file 'plugin/ldap_policy/plugin.ini' | |||
1686 | --- plugin/ldap_policy/plugin.ini 1970-01-01 00:00:00 +0000 | |||
1687 | +++ plugin/ldap_policy/plugin.ini 2012-08-21 14:09:20 +0000 | |||
1688 | @@ -0,0 +1,3 @@ | |||
1689 | 1 | [plugin] | ||
1690 | 2 | build_conditional="x${ac_cv_libldap}" = "xyes" | ||
1691 | 3 | ldflags=${LTLIBLDAP} | ||
1692 | 0 | 4 | ||
1693 | === modified file 'tests/lib/server_mgmt/drizzled.py' | |||
1694 | --- tests/lib/server_mgmt/drizzled.py 2012-06-19 18:46:42 +0000 | |||
1695 | +++ tests/lib/server_mgmt/drizzled.py 2012-08-21 14:09:20 +0000 | |||
1696 | @@ -200,8 +200,9 @@ | |||
1697 | 200 | # This is what test-run.pl does and it helps us pass logging_stats tests | 200 | # This is what test-run.pl does and it helps us pass logging_stats tests |
1698 | 201 | # while not self.ping_server(server, quiet=True) and timer != timeout: | 201 | # while not self.ping_server(server, quiet=True) and timer != timeout: |
1699 | 202 | 202 | ||
1702 | 203 | return self.system_manager.find_path( [self.pid_file] | 203 | #return self.system_manager.find_path( [self.pid_file] |
1703 | 204 | , required=0) | 204 | # , required=0) |
1704 | 205 | return self.ping(quiet=True) | ||
1705 | 205 | 206 | ||
1706 | 206 | def create_slave_config_file(self): | 207 | def create_slave_config_file(self): |
1707 | 207 | """ Create a config file suitable for use | 208 | """ Create a config file suitable for use |
Thanks, this will be reviewed next.