]>
git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/rbac.c
2 * Copyright (c) 2017 Red Hat, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include "condition.h"
26 #include "openvswitch/vlog.h"
27 #include "ovsdb-data.h"
28 #include "ovsdb-error.h"
29 #include "ovsdb-parser.h"
30 #include "ovsdb-util.h"
37 #include "transaction.h"
39 VLOG_DEFINE_THIS_MODULE(ovsdb_rbac
);
41 static const struct ovsdb_row
*
42 ovsdb_find_row_by_string_key(const struct ovsdb_table
*table
,
43 const char *column_name
,
46 const struct ovsdb_column
*column
;
47 column
= ovsdb_table_schema_get_column(table
->schema
, column_name
);
50 /* XXX This is O(n) in the size of the table. If the table has an
51 * index on the column, then we could implement it in O(1). */
52 const struct ovsdb_row
*row
;
53 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
54 const struct ovsdb_datum
*datum
= &row
->fields
[column
->index
];
55 for (size_t i
= 0; i
< datum
->n
; i
++) {
56 if (datum
->keys
[i
].string
[0] &&
57 !strcmp(key
, datum
->keys
[i
].string
)) {
67 static const struct ovsdb_row
*
68 ovsdb_rbac_lookup_perms(const struct ovsdb
*db
, const char *role
,
71 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
72 const struct ovsdb_row
*role_row
, *perm_row
;
73 const struct ovsdb_column
*column
;
75 /* Lookup role in roles table */
76 role_row
= ovsdb_find_row_by_string_key(db
->rbac_role
, "name", role
);
78 VLOG_INFO_RL(&rl
, "rbac: role \"%s\" not found in rbac roles table",
83 /* Find row in permissions column for table from "permissions" column */
84 column
= ovsdb_table_schema_get_column(role_row
->table
->schema
,
87 VLOG_INFO_RL(&rl
, "rbac: \"permissions\" column not present in rbac "
91 perm_row
= ovsdb_util_read_map_string_uuid_column(role_row
, "permissions",
98 ovsdb_rbac_authorized(const struct ovsdb_row
*perms
,
100 const struct ovsdb_row
*row
)
102 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
103 const struct ovsdb_datum
*datum
;
106 datum
= ovsdb_util_get_datum(CONST_CAST(struct ovsdb_row
*, perms
),
108 OVSDB_TYPE_STRING
, OVSDB_TYPE_VOID
, UINT_MAX
);
111 VLOG_INFO_RL(&rl
, "rbac: error reading authorization column");
115 for (i
= 0; i
< datum
->n
; i
++) {
116 const char *name
= datum
->keys
[i
].string
;
117 const char *value
= NULL
;
120 if (name
[0] == '\0') {
121 /* empty string means all are authorized */
125 is_map
= strchr(name
, ':') != NULL
;
128 char *tmp
= xstrdup(name
);
129 char *col_name
, *key
, *save_ptr
= NULL
;
130 col_name
= strtok_r(tmp
, ":", &save_ptr
);
131 key
= strtok_r(NULL
, ":", &save_ptr
);
133 if (col_name
&& key
) {
134 value
= ovsdb_util_read_map_string_column(row
, col_name
, key
);
138 ovsdb_util_read_string_column(row
, name
, &value
);
140 if (value
&& !strcmp(value
, id
)) {
149 ovsdb_rbac_insert(const struct ovsdb
*db
, const struct ovsdb_table
*table
,
150 const struct ovsdb_row
*row
,
151 const char *role
, const char *id
)
153 const struct ovsdb_table_schema
*ts
= table
->schema
;
154 const struct ovsdb_row
*perms
;
157 if (!db
->rbac_role
|| !role
|| *role
== '\0') {
165 perms
= ovsdb_rbac_lookup_perms(db
, role
, ts
->name
);
171 if (!ovsdb_rbac_authorized(perms
, id
, row
)) {
175 if (!ovsdb_util_read_bool_column(perms
, "insert_delete", &insdel
)) {
187 struct rbac_delete_cbdata
{
188 const struct ovsdb_table
*table
;
189 const struct ovsdb_row
*perms
;
196 rbac_delete_cb(const struct ovsdb_row
*row
, void *rd_
)
198 struct rbac_delete_cbdata
*rd
= rd_
;
201 if (!ovsdb_rbac_authorized(rd
->perms
, rd
->id
, row
)) {
205 if (!ovsdb_util_read_bool_column(rd
->perms
, "insert_delete", &insdel
)) {
215 rd
->permitted
= false;
220 ovsdb_rbac_delete(const struct ovsdb
*db
, struct ovsdb_table
*table
,
221 struct ovsdb_condition
*condition
,
222 const char *role
, const char *id
)
224 const struct ovsdb_table_schema
*ts
= table
->schema
;
225 const struct ovsdb_row
*perms
;
226 struct rbac_delete_cbdata rd
;
228 if (!db
->rbac_role
|| !role
|| *role
== '\0') {
235 perms
= ovsdb_rbac_lookup_perms(db
, role
, ts
->name
);
247 ovsdb_query(table
, condition
, rbac_delete_cb
, &rd
);
257 struct rbac_update_cbdata
{
258 const struct ovsdb_table
*table
;
259 const struct ovsdb_column_set
*columns
; /* columns to be modified */
260 const struct ovsdb_datum
*modifiable
; /* modifiable column names */
261 const struct ovsdb_row
*perms
;
268 rbac_column_modification_permitted(const struct ovsdb_column
*column
,
269 const struct ovsdb_datum
*modifiable
)
273 for (i
= 0; i
< modifiable
->n
; i
++) {
274 char *name
= modifiable
->keys
[i
].string
;
276 if (!strcmp(name
, column
->name
)) {
284 rbac_update_cb(const struct ovsdb_row
*row
, void *ru_
)
286 struct rbac_update_cbdata
*ru
= ru_
;
289 if (!ovsdb_rbac_authorized(ru
->perms
, ru
->id
, row
)) {
293 for (i
= 0; i
< ru
->columns
->n_columns
; i
++) {
294 const struct ovsdb_column
*column
= ru
->columns
->columns
[i
];
296 if (!rbac_column_modification_permitted(column
, ru
->modifiable
)) {
303 ru
->permitted
= false;
308 ovsdb_rbac_update(const struct ovsdb
*db
,
309 struct ovsdb_table
*table
,
310 struct ovsdb_column_set
*columns
,
311 struct ovsdb_condition
*condition
,
312 const char *role
, const char *id
)
314 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
315 const struct ovsdb_table_schema
*ts
= table
->schema
;
316 const struct ovsdb_datum
*datum
;
317 const struct ovsdb_row
*perms
;
318 struct rbac_update_cbdata ru
;
320 if (!db
->rbac_role
|| !role
|| *role
== '\0') {
327 perms
= ovsdb_rbac_lookup_perms(db
, role
, ts
->name
);
333 datum
= ovsdb_util_get_datum(CONST_CAST(struct ovsdb_row
*, perms
),
335 OVSDB_TYPE_STRING
, OVSDB_TYPE_VOID
, UINT_MAX
);
338 VLOG_INFO_RL(&rl
, "ovsdb_rbac_update: could not read \"update\" "
344 ru
.columns
= columns
;
348 ru
.modifiable
= datum
;
351 ovsdb_query(table
, condition
, rbac_update_cb
, &ru
);
361 struct rbac_mutate_cbdata
{
362 const struct ovsdb_table
*table
;
363 const struct ovsdb_mutation_set
*mutations
; /* columns to be mutated */
364 const struct ovsdb_datum
*modifiable
; /* modifiable column names */
365 const struct ovsdb_row
*perms
;
372 rbac_mutate_cb(const struct ovsdb_row
*row
, void *rm_
)
374 struct rbac_mutate_cbdata
*rm
= rm_
;
377 if (!ovsdb_rbac_authorized(rm
->perms
, rm
->id
, row
)) {
381 for (i
= 0; i
< rm
->mutations
->n_mutations
; i
++) {
382 const struct ovsdb_column
*column
= rm
->mutations
->mutations
[i
].column
;
384 if (!rbac_column_modification_permitted(column
, rm
->modifiable
)) {
392 rm
->permitted
= false;
397 ovsdb_rbac_mutate(const struct ovsdb
*db
,
398 struct ovsdb_table
*table
,
399 struct ovsdb_mutation_set
*mutations
,
400 struct ovsdb_condition
*condition
,
401 const char *role
, const char *id
)
403 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
404 const struct ovsdb_table_schema
*ts
= table
->schema
;
405 const struct ovsdb_datum
*datum
;
406 const struct ovsdb_row
*perms
;
407 struct rbac_mutate_cbdata rm
;
409 if (!db
->rbac_role
|| !role
|| *role
== '\0') {
416 perms
= ovsdb_rbac_lookup_perms(db
, role
, ts
->name
);
422 datum
= ovsdb_util_get_datum(CONST_CAST(struct ovsdb_row
*, perms
),
424 OVSDB_TYPE_STRING
, OVSDB_TYPE_VOID
, UINT_MAX
);
427 VLOG_INFO_RL(&rl
, "ovsdb_rbac_mutate: could not read \"update\" "
433 rm
.mutations
= mutations
;
437 rm
.modifiable
= datum
;
440 ovsdb_query(table
, condition
, rbac_mutate_cb
, &rm
);