1 This patch provides Python RBAC support.
3 diff --git Python-2.6.4/Modules/authattr.c Python-2.6.4/Modules/authattr.c
6 +++ Python-2.6.4/Modules/authattr.c
11 + * The contents of this file are subject to the terms of the
12 + * Common Development and Distribution License (the "License").
13 + * You may not use this file except in compliance with the License.
15 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
16 + * or http://www.opensolaris.org/os/licensing.
17 + * See the License for the specific language governing permissions
18 + * and limitations under the License.
20 + * When distributing Covered Code, include this CDDL HEADER in each
21 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
22 + * If applicable, add the following below this CDDL HEADER, with the
23 + * fields enclosed by brackets "[]" replaced with your own identifying
24 + * information: Portions Copyright [yyyy] [name of copyright owner]
30 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
34 + * RBAC Bindings for Python - auth_attr functions
37 +#include <auth_attr.h>
42 +pyrbac_setauthattr(PyObject* self, PyObject* args) {
48 +pyrbac_endauthattr(PyObject* self, PyObject* args) {
54 +pyrbac_getauthnamattr(PyObject* self, char* authname, int mode) {
58 + authattr_t * ret_authattr = (mode == PYRBAC_NAM_MODE) ? getauthnam(authname) : getauthattr();
59 + if (ret_authattr == NULL)
62 + PyObject* kv_data = PyDict_New();
63 + if (kv_data == NULL) {
64 + free_authattr(ret_authattr);
68 + if(ret_authattr->attr != NULL) {
70 + for(len = 0; len < ret_authattr->attr->length; len++) {
71 + kv_t current = ret_authattr->attr->data[len];
73 + PyObject* set = PyList_New(NULL);
75 + char* item = strtok_r(current.value, ",", &saveptr);
76 + PyList_Append(set, PyString_FromString(item));
78 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
79 + if(PyList_Append(set, PyString_FromString(item)) != 0) {
81 + Py_XDECREF(kv_data);
82 + free_authattr(ret_authattr);
86 + if(PyDict_SetItemString(kv_data, current.key, set)) {
87 + free_authattr(ret_authattr);
92 + PyObject * retval = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:O}",
93 + "name",ret_authattr->name,
94 + "res1",ret_authattr->res1,
95 + "res2",ret_authattr->res2,
96 + "short",ret_authattr->short_desc,
97 + "long",ret_authattr->long_desc,
98 + "attributes",kv_data);
100 + free_authattr(ret_authattr);
106 +pyrbac_getauthattr(PyObject* self, PyObject* args) {
107 + return(pyrbac_getauthnamattr(self, NULL, PYRBAC_ATTR_MODE));
111 +pyrbac_getauthnam(PyObject* self, PyObject* args) {
113 + if(!PyArg_ParseTuple(args, "s:getauthnam", &name))
115 + return(pyrbac_getauthnamattr(self, name, PYRBAC_NAM_MODE));
119 +pyrbac_chkauthattr(PyObject* self, PyObject* args) {
120 + char* authstring = NULL;
121 + char* username = NULL;
122 + if(!PyArg_ParseTuple(args, "ss:chkauthattr", &authstring, &username))
124 + return PyBool_FromLong((long)chkauthattr(authstring, username));
128 +pyrbac_authattr_next(PyObject* self, PyObject* args) {
129 + PyObject* retval = pyrbac_getauthattr(self, args);
130 + if( retval == Py_None ) {
137 +pyrbac_authattr__iter__(PyObject* self, PyObject* args) {
146 +Authattr_dealloc(Authattr* self) {
148 + self->ob_type->tp_free((PyObject*) self);
152 +Authattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
154 + self = (Authattr*)type->tp_alloc(type, 0);
156 + return ((PyObject *) self);
160 +Authattr_init(Authattr* self, PyObject *args, PyObject *kwargs) {
165 +static char pyrbac_authattr__doc__[];
167 +PyDoc_STRVAR(pyrbac_authattr__doc__, """provides interfaces to the auth_attr \
168 +database. may be iterated over to return all auth_attr entries\n\n\
169 +Methods provided:\n\
176 +static char pyrbac_setauthattr__doc__[];
177 +static char pyrbac_endauthattr__doc__[];
178 +static char pyrbac_getauthattr__doc__[];
179 +static char pyrbac_chkauthattr__doc__[];
181 +PyDoc_STRVAR(pyrbac_setauthattr__doc__,
182 +"\"rewinds\" the auth_attr functions to the first entry in the db. Called \
183 +automatically by the constructor\n\tArguments: None\n\tReturns: None");
185 +PyDoc_STRVAR(pyrbac_endauthattr__doc__,
186 +"closes the auth_attr database, cleans up storage. called automatically by \
187 +the destructor\n\tArguments: None\n\tReturns: None");
189 +PyDoc_STRVAR(pyrbac_chkauthattr__doc__, "verifies if a user has a given \
190 +authorization.\n\tArguments: 2 Python strings, 'authname' and 'username'\n\
191 +\tReturns: True if the user is authorized, False otherwise");
193 +PyDoc_STRVAR(pyrbac_getauthattr__doc__,
194 +"return one entry from the auth_attr database\n\
195 +\tArguments: None\n\
196 +\tReturns: a dict representing the authattr_t struct:\n\
197 +\t\t\"name\": Authorization Name\n\
198 +\t\t\"res1\": reserved\n\
199 +\t\t\"res2\": reserved\n\
200 +\t\t\"short\": Short Description\n\
201 +\t\t\"long\": Long Description\n\
202 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
203 +or a string depending on value");
205 +PyDoc_STRVAR(pyrbac_getauthnam__doc__,
206 +"searches the auth_attr database for a given authorization name\n\
207 +\tArguments: a Python string containing the auth name\n\
208 +\tReturns: a dict representing the authattr_t struct:\n\
209 +\t\t\"name\": Authorization Name\n\
210 +\t\t\"res1\": reserved\n\
211 +\t\t\"res2\": reserved\n\
212 +\t\t\"short\": Short Description\n\
213 +\t\t\"long\": Long Description\n\
214 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
215 +or a string depending on value");
217 +static PyMethodDef Authattr_methods[] = {
218 + {"setauthattr", pyrbac_setauthattr, METH_NOARGS, pyrbac_setauthattr__doc__},
219 + {"endauthattr", pyrbac_endauthattr, METH_NOARGS, pyrbac_endauthattr__doc__},
220 + {"chkauthattr", pyrbac_chkauthattr, METH_VARARGS, pyrbac_chkauthattr__doc__},
221 + {"getauthattr", pyrbac_getauthattr, METH_NOARGS, pyrbac_getauthattr__doc__},
222 + {"getauthnam", pyrbac_getauthnam, METH_VARARGS, pyrbac_getauthnam__doc__},
226 +PyTypeObject AuthattrType = {
227 + PyObject_HEAD_INIT(NULL)
229 + "rbac.authattr", /*tp_name*/
230 + sizeof(Authattr), /*tp_basicsize*/
232 + (destructor)Authattr_dealloc, /*tp_dealloc*/
238 + 0, /*tp_as_number*/
239 + 0, /*tp_as_sequence*/
240 + 0, /*tp_as_mapping*/
246 + 0, /*tp_as_buffer*/
247 + Py_TPFLAGS_DEFAULT |
248 + Py_TPFLAGS_BASETYPE |
249 + Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
250 + pyrbac_authattr__doc__, /* tp_doc */
251 + 0, /* tp_traverse */
253 + 0, /* tp_richcompare */
254 + 0, /* tp_weaklistoffset */
255 + pyrbac_authattr__iter__, /* tp_iter */
256 + pyrbac_authattr_next, /* tp_iternext */
257 + Authattr_methods, /* tp_methods */
258 + 0, /* tp_members */
262 + 0, /* tp_descr_get */
263 + 0, /* tp_descr_set */
264 + 0, /* tp_dictoffset */
265 + (initproc)Authattr_init, /* tp_init */
267 + Authattr_new, /* tp_new */
269 diff --git Python-2.6.4/Modules/execattr.c Python-2.6.4/Modules/execattr.c
272 +++ Python-2.6.4/Modules/execattr.c
275 + * CDDL HEADER START
277 + * The contents of this file are subject to the terms of the
278 + * Common Development and Distribution License (the "License").
279 + * You may not use this file except in compliance with the License.
281 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
282 + * or http://www.opensolaris.org/os/licensing.
283 + * See the License for the specific language governing permissions
284 + * and limitations under the License.
286 + * When distributing Covered Code, include this CDDL HEADER in each
287 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
288 + * If applicable, add the following below this CDDL HEADER, with the
289 + * fields enclosed by brackets "[]" replaced with your own identifying
290 + * information: Portions Copyright [yyyy] [name of copyright owner]
296 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
300 + * RBAC Bindings for Python - exec_attr functions
303 +#include <exec_attr.h>
308 +pyrbac_setexecattr(PyObject* self, PyObject* args) {
314 +pyrbac_endexecattr(PyObject* self, PyObject* args) {
320 +pyrbac_getexecuserprofattr(PyObject* self, char* userprofname, char* type, char* id, int mode) {
322 + PyObject* ep_data = (mode == PYRBAC_ATTR_MODE) ? NULL : PyList_New(0);
324 + if (ep_data == NULL && mode != PYRBAC_ATTR_MODE )
327 + execattr_t *execprof;
328 + if (mode == PYRBAC_USER_MODE)
329 + execprof = getexecuser(userprofname, type, id, GET_ALL);
330 + else if (mode == PYRBAC_PROF_MODE)
331 + execprof = getexecprof(userprofname, type, id, GET_ALL);
332 + else if (mode == PYRBAC_ATTR_MODE)
333 + execprof = getexecattr();
337 + if (execprof == NULL)
340 + execattr_t *execprof_head = execprof;
342 + while(execprof != NULL) {
344 + PyObject* kv_data = PyDict_New();
346 + if(execprof->attr != NULL) {
348 + for(len = 0; len < execprof->attr->length; len++) {
349 + kv_t current = execprof->attr->data[len];
351 + PyObject* set = PyList_New(NULL);
353 + char* item = strtok_r(current.value, ",", &saveptr);
354 + PyList_Append(set, PyString_FromString(item));
356 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
357 + if(PyList_Append(set, PyString_FromString(item)) != 0) {
359 + Py_XDECREF(kv_data);
360 + free_execattr(execprof_head);
364 + if(PyDict_SetItemString(kv_data, current.key, set)) {
365 + free_execattr(execprof_head);
370 + PyObject* entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:s,s:O}",
371 + "name", execprof->name,
372 + "type", execprof->type,
373 + "policy", execprof->policy,
374 + "res1", execprof->res1,
375 + "res2", execprof->res2,
376 + "id", execprof->id,
377 + "attributes", kv_data);
379 + if (entry == NULL) {
380 + Py_XDECREF(kv_data);
381 + free_execattr(execprof_head);
385 + if (mode == PYRBAC_ATTR_MODE) {
386 + free_execattr(execprof_head);
389 + PyList_Append(ep_data, entry);
390 + execprof = execprof->next;
393 + free_execattr(execprof_head);
399 +pyrbac_getexecuser(PyObject* self, PyObject* args) {
400 + char* username = NULL;
404 + if(!PyArg_ParseTuple(args, "sss:getexecuser", &username, &type, &id))
407 + return (pyrbac_getexecuserprofattr(self, username, type, id, PYRBAC_USER_MODE));
411 +pyrbac_getexecprof(PyObject* self, PyObject* args) {
413 + char* profname = NULL;
417 + if(!PyArg_ParseTuple(args, "sss:getexecprof", &profname, &type, &id))
420 + return (pyrbac_getexecuserprofattr(self, profname, type, id, PYRBAC_PROF_MODE));
424 +pyrbac_getexecattr(PyObject* self, PyObject* args) {
425 + return pyrbac_getexecuserprofattr(self, NULL, NULL, NULL, PYRBAC_ATTR_MODE);
429 +pyrbac_execattr_next(PyObject* self, PyObject* args) {
430 + PyObject* retval = pyrbac_getexecattr(self, args);
431 + if( retval == Py_None ) {
438 +pyrbac_execattr__iter__(PyObject* self, PyObject* args) {
447 +Execattr_dealloc(Execattr* self) {
449 + self->ob_type->tp_free((PyObject*) self);
453 +Execattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
455 + self = (Execattr*)type->tp_alloc(type, 0);
457 + return ((PyObject *) self);
461 +Execattr_init(Execattr* self, PyObject *args, PyObject *kwargs) {
466 +static char pyrbac_execattr__doc__[];
468 +PyDoc_STRVAR(pyrbac_execattr__doc__, "provides functions for \
469 +interacting with the execution profiles database. May be iterated over to \
470 +enumerate exec_attr(4) entries\n\n\
471 +Methods provided:\n\
479 +static char pyrbac_getexecuser__doc__[];
480 +static char pyrbac_getexecprof__doc__[];
481 +static char pyrbac_getexecattr__doc__[];
482 +static char pyrbac_setexecattr__doc__[];
483 +static char pyrbac_endexecattr__doc__[];
485 +PyDoc_STRVAR(pyrbac_setexecattr__doc__,
486 +"\"rewinds\" the exec_attr functions to the first entry in the db. Called \
487 +automatically by the constructor.\n\
491 +PyDoc_STRVAR(pyrbac_endexecattr__doc__,
492 +"closes the exec_attr database, cleans up storage. called automatically by \
497 +PyDoc_STRVAR(pyrbac_getexecuser__doc__, "corresponds with getexecuser(3SECDB)\
498 +\nTakes: \'username\', \'type\', \'id\'\n\
499 +Return: a single exec_attr entry\n\
500 +\tArguments: None\n\
501 +\tReturns: a dict representation of an execattr_t struct:\n\
502 +\t\t\"name\": Authorization Name\n\
503 +\t\t\"type\": Profile Type\n\
504 +\t\t\"policy\": Policy attributes are relevant in\n\
505 +\t\t\"res1\": reserved\n\
506 +\t\t\"res2\": reserved\n\
507 +\t\t\"id\": unique identifier\n\
508 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
509 +either a list or a string depending on value");
511 +PyDoc_STRVAR(pyrbac_getexecprof__doc__, "corresponds with getexecprof(3SECDB)\
512 +\nTakes: \'profile name\', \'type\', \'id\'\n\
513 +\tReturns: a dict representation of an execattr_t struct:\n\
514 +\t\t\"name\": Authorization Name\n\
515 +\t\t\"type\": Profile Type\n\
516 +\t\t\"policy\": Policy attributes are relevant in\n\
517 +\t\t\"res1\": reserved\n\
518 +\t\t\"res2\": reserved\n\
519 +\t\t\"id\": unique identifier\n\
520 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
521 +either a list or a string depending on value");
523 +PyDoc_STRVAR(pyrbac_getexecattr__doc__, "corresponds with getexecattr(3SECDB)\
524 +\nTakes 0 arguments\n\
525 +\tReturns: a dict representation of an execattr_t struct:\n\
526 +\t\t\"name\": Authorization Name\n\
527 +\t\t\"type\": Profile Type\n\
528 +\t\t\"policy\": Policy attributes are relevant in\n\
529 +\t\t\"res1\": reserved\n\
530 +\t\t\"res2\": reserved\n\
531 +\t\t\"id\": unique identifier\n\
532 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
533 +either a list or a string depending on value");
535 +static PyMethodDef Execattr_methods[] = {
536 + {"setexecattr", pyrbac_setexecattr, METH_NOARGS, pyrbac_setexecattr__doc__},
537 + {"endexecattr", pyrbac_endexecattr, METH_NOARGS, pyrbac_endexecattr__doc__},
538 + {"getexecprof", pyrbac_getexecprof, METH_VARARGS, pyrbac_getexecprof__doc__},
539 + {"getexecuser", pyrbac_getexecuser, METH_VARARGS, pyrbac_getexecuser__doc__},
540 + {"getexecattr", pyrbac_getexecattr, METH_NOARGS, pyrbac_getexecattr__doc__},
544 +PyTypeObject ExecattrType = {
545 + PyObject_HEAD_INIT(NULL)
547 + "rbac.execattr", /*tp_name*/
548 + sizeof(Execattr), /*tp_basicsize*/
550 + (destructor)Execattr_dealloc, /*tp_dealloc*/
556 + 0, /*tp_as_number*/
557 + 0, /*tp_as_sequence*/
558 + 0, /*tp_as_mapping*/
564 + 0, /*tp_as_buffer*/
565 + Py_TPFLAGS_DEFAULT |
566 + Py_TPFLAGS_BASETYPE |
567 + Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
568 + pyrbac_execattr__doc__, /* tp_doc */
569 + 0, /* tp_traverse */
571 + 0, /* tp_richcompare */
572 + 0, /* tp_weaklistoffset */
573 + pyrbac_execattr__iter__, /* tp_iter */
574 + pyrbac_execattr_next, /* tp_iternext */
575 + Execattr_methods, /* tp_methods */
576 + 0, /* tp_members */
580 + 0, /* tp_descr_get */
581 + 0, /* tp_descr_set */
582 + 0, /* tp_dictoffset */
583 + (initproc)Execattr_init, /* tp_init */
585 + Execattr_new, /* tp_new */
587 diff --git Python-2.6.4/Modules/privileges.c Python-2.6.4/Modules/privileges.c
590 +++ Python-2.6.4/Modules/privileges.c
593 + * CDDL HEADER START
595 + * The contents of this file are subject to the terms of the
596 + * Common Development and Distribution License (the "License").
597 + * You may not use this file except in compliance with the License.
599 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
600 + * or http://www.opensolaris.org/os/licensing.
601 + * See the License for the specific language governing permissions
602 + * and limitations under the License.
604 + * When distributing Covered Code, include this CDDL HEADER in each
605 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
606 + * If applicable, add the following below this CDDL HEADER, with the
607 + * fields enclosed by brackets "[]" replaced with your own identifying
608 + * information: Portions Copyright [yyyy] [name of copyright owner]
614 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
618 + * privileges(5) bindings for Python
625 +pyprivileges_setppriv( PyObject *self, PyObject *args) {
626 + priv_op_t op = -1 ;
627 + priv_ptype_t which = NULL;
629 + PyObject* set_list = NULL;
631 + priv_set_t * set = NULL;
633 + if(!PyArg_ParseTuple(args, "iiO:setppriv", &op, &which, &set_list))
636 + if((op != PRIV_ON && op != PRIV_OFF && op != PRIV_SET) ||
637 + (which != PRIV_PERMITTED && which != PRIV_EFFECTIVE &&
638 + which != PRIV_INHERITABLE && which != PRIV_LIMIT))
641 + PyObject* set_string = PyList_GetItem(set_list, 0);
643 + for (i = 1; i < PyList_Size(set_list); ++i) {
644 + PyString_Concat(&set_string, PyString_FromString(","));
645 + PyString_Concat(&set_string, PyList_GetItem(set_list, i));
648 + set = priv_str_to_set(PyString_AsString(set_string), ",", NULL );
653 + long ret = (long) setppriv(op, which, set);
655 + // Python inverts true & false
663 +pyprivileges_getppriv( PyObject *self, PyObject *args) {
665 + char* set_str = NULL;
666 + priv_ptype_t which = NULL;
667 + priv_set_t * set = priv_allocset();
671 + if(!PyArg_ParseTuple(args, "i:getppriv", &which))
674 + if (which != PRIV_PERMITTED && which != PRIV_EFFECTIVE &&
675 + which != PRIV_INHERITABLE && which != PRIV_LIMIT)
678 + if (getppriv(which, set) != 0)
681 + set_str = priv_set_to_str(set, ',', PRIV_STR_LIT);
684 + PyObject* set_list = PyList_New(NULL);
686 + char* item = strtok_r(set_str, ",", &saveptr);
687 + PyList_Append(set_list, PyString_FromString(item));
689 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
690 + if(PyList_Append(set_list, PyString_FromString(item)) != 0) {
691 + Py_XDECREF(set_list);
700 +pyprivileges_priv_inverse( PyObject *self, PyObject *args ) {
702 + PyObject* set_list_in = NULL;
703 + if(!PyArg_ParseTuple(args, "O:priv_inverse", &set_list_in))
706 + PyObject* set_string = PyList_GetItem(set_list_in, 0);
708 + for (i = 1; i < PyList_Size(set_list_in); ++i) {
709 + PyString_Concat(set_string, PyString_FromString(","));
710 + PyString_Concat(set_string, PyList_GetItem(set_list_in, i));
713 + priv_set_t * set = priv_str_to_set(PyString_AsString(set_string), ",", NULL);
717 + char * ret_str = priv_set_to_str(set, ',', PRIV_STR_LIT);
720 + PyObject* set_list_out = PyList_New(NULL);
722 + char* item = strtok_r(ret_str, ",", &saveptr);
723 + PyList_Append(set_list_out, PyString_FromString(item));
725 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
726 + if(PyList_Append(set_list_out, PyString_FromString(item)) != 0) {
727 + Py_XDECREF(set_list_out);
732 + Py_XDECREF(set_list_in);
734 + return(set_list_out);
737 +/* priv_ineffect is a convienient wrapper to priv_get
738 + * however priv_set is, in the context of python, not
739 + * much of a convienience, so it's omitted
742 +pyprivileges_priv_ineffect(PyObject* self, PyObject* args) {
743 + char* privstring=NULL;
744 + if (!PyArg_ParseTuple(args, "s:priv_ineffect", &privstring))
746 + return PyBool_FromLong(priv_ineffect(privstring));
750 +static char pyprivileges__doc__[];
751 +PyDoc_STRVAR(pyprivileges__doc__,
752 +"Provides functions for interacting with the Solaris privileges(5) framework\n\
753 +Functions provided:\n\
759 +static char pyprivileges_setppriv__doc__[];
760 +static char pyprivileges_getppriv__doc__[];
761 +static char pyprivileges_priv_ineffect__doc__[];
762 +static char pyprivileges_priv_inverse__doc__[];
764 +PyDoc_STRVAR(pyprivileges_setppriv__doc__,
765 +"Facilitates setting the permitted/inheritable/limit/effective privileges set\n\
767 +\t\tone of (PRIV_ON|PRIV_OFF|PRIV_SET)\n\
768 +\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\
769 +\t\tset of privileges: a list of strings\n\
770 +\tReturns: True on success, False on failure\
773 +PyDoc_STRVAR(pyprivileges_getppriv__doc__,
774 +"Return the process privilege set\n\
776 +\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\
777 +\tReturns: a Python list of strings");
779 +PyDoc_STRVAR(pyprivileges_priv_ineffect__doc__,
780 +"Checks for a privileges presence in the effective set\n\
781 +\tArguments: a String\n\
782 +\tReturns: True if the privilege is in effect, False otherwise");
784 +PyDoc_STRVAR(pyprivileges_priv_inverse__doc__,
785 +"The complement of the set of privileges\n\
786 +\tArguments: a list of strings\n\tReturns: a list of strings");
788 +static PyMethodDef module_methods[] = {
789 + {"setppriv", pyprivileges_setppriv, METH_VARARGS, pyprivileges_setppriv__doc__},
790 + {"getppriv", pyprivileges_getppriv, METH_VARARGS, pyprivileges_getppriv__doc__},
791 + {"priv_ineffect", pyprivileges_priv_ineffect, METH_VARARGS, pyprivileges_priv_ineffect__doc__},
792 + {"priv_inverse", pyprivileges_priv_inverse, METH_VARARGS, pyprivileges_priv_inverse__doc__},
797 +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
798 +#define PyMODINIT_FUNC void
801 +initprivileges(void) {
804 + m = Py_InitModule3("privileges", module_methods, pyprivileges__doc__);
808 + PyObject* d = PyModule_GetDict(m);
812 + PyDict_SetItemString(d, "PRIV_ON", PyInt_FromLong((long)PRIV_ON));
813 + PyDict_SetItemString(d, "PRIV_OFF", PyInt_FromLong((long)PRIV_OFF));
814 + PyDict_SetItemString(d, "PRIV_SET", PyInt_FromLong((long)PRIV_SET));
816 + PyDict_SetItemString(d, "PRIV_PERMITTED", PyInt_FromLong((long)PRIV_PERMITTED));
817 + PyDict_SetItemString(d, "PRIV_INHERITABLE", PyInt_FromLong((long)PRIV_INHERITABLE));
818 + PyDict_SetItemString(d, "PRIV_LIMIT", PyInt_FromLong((long)PRIV_LIMIT));
819 + PyDict_SetItemString(d, "PRIV_EFFECTIVE", PyInt_FromLong((long)PRIV_EFFECTIVE));
821 diff --git Python-2.6.4/Modules/pyrbac.c Python-2.6.4/Modules/pyrbac.c
824 +++ Python-2.6.4/Modules/pyrbac.c
827 + * CDDL HEADER START
829 + * The contents of this file are subject to the terms of the
830 + * Common Development and Distribution License (the "License").
831 + * You may not use this file except in compliance with the License.
833 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
834 + * or http://www.opensolaris.org/os/licensing.
835 + * See the License for the specific language governing permissions
836 + * and limitations under the License.
838 + * When distributing Covered Code, include this CDDL HEADER in each
839 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
840 + * If applicable, add the following below this CDDL HEADER, with the
841 + * fields enclosed by brackets "[]" replaced with your own identifying
842 + * information: Portions Copyright [yyyy] [name of copyright owner]
848 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
852 + * RBAC Bindings for Python
858 +static PyMethodDef module_methods[] = {NULL};
859 +static char pyrbac__doc__[];
861 +PyDoc_STRVAR(pyrbac__doc__, "provides access to some objects \
862 +for interaction with the Solaris Role-Based Access Control \
863 +framework.\n\nDynamic objects:\n\
864 +userattr -- for interacting with user_attr(4)\n\
865 +authattr -- for interacting with auth_attr(4)\n\
866 +execattr -- for interacting with exec_attr(4)\n");
868 +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
869 +#define PyMODINIT_FUNC void
874 + if (PyType_Ready(&AuthattrType) < 0 ||
875 + PyType_Ready(&ExecattrType) < 0 ||
876 + PyType_Ready(&UserattrType) < 0 )
879 + m = Py_InitModule3("rbac", module_methods, pyrbac__doc__);
883 + Py_INCREF(&AuthattrType);
884 + PyModule_AddObject(m, "authattr", (PyObject*)&AuthattrType);
886 + Py_INCREF(&ExecattrType);
887 + PyModule_AddObject(m, "execattr", (PyObject*)&ExecattrType);
889 + Py_INCREF(&UserattrType);
890 + PyModule_AddObject(m, "userattr", (PyObject*)&UserattrType);
894 diff --git Python-2.6.4/Modules/pyrbac.h Python-2.6.4/Modules/pyrbac.h
897 +++ Python-2.6.4/Modules/pyrbac.h
900 + * CDDL HEADER START
902 + * The contents of this file are subject to the terms of the
903 + * Common Development and Distribution License (the "License").
904 + * You may not use this file except in compliance with the License.
906 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
907 + * or http://www.opensolaris.org/os/licensing.
908 + * See the License for the specific language governing permissions
909 + * and limitations under the License.
911 + * When distributing Covered Code, include this CDDL HEADER in each
912 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
913 + * If applicable, add the following below this CDDL HEADER, with the
914 + * fields enclosed by brackets "[]" replaced with your own identifying
915 + * information: Portions Copyright [yyyy] [name of copyright owner]
921 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
925 + * RBAC bindings for python
933 +#define PYRBAC_USER_MODE 1
934 +#define PYRBAC_PROF_MODE 2
935 +#define PYRBAC_ATTR_MODE 3
936 +#define PYRBAC_NAM_MODE 4
937 +#define PYRBAC_UID_MODE 5
939 +extern PyTypeObject AuthattrType;
940 +extern PyTypeObject ExecattrType;
941 +extern PyTypeObject UserattrType;
944 diff --git Python-2.6.4/Modules/userattr.c Python-2.6.4/Modules/userattr.c
947 +++ Python-2.6.4/Modules/userattr.c
950 + * CDDL HEADER START
952 + * The contents of this file are subject to the terms of the
953 + * Common Development and Distribution License (the "License").
954 + * You may not use this file except in compliance with the License.
956 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
957 + * or http://www.opensolaris.org/os/licensing.
958 + * See the License for the specific language governing permissions
959 + * and limitations under the License.
961 + * When distributing Covered Code, include this CDDL HEADER in each
962 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
963 + * If applicable, add the following below this CDDL HEADER, with the
964 + * fields enclosed by brackets "[]" replaced with your own identifying
965 + * information: Portions Copyright [yyyy] [name of copyright owner]
971 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
975 + * RBAC Bindings for Python - user_attr functions
979 +#include <user_attr.h>
984 +pyrbac_setuserattr(PyObject* self, PyObject* args) {
990 +pyrbac_enduserattr(PyObject* self, PyObject* args) {
996 +pyrbac_getuseruidnamattr(PyObject* self, void* arg, int mode, char* filename) {
998 + userattr_t *ret_userattr;
1000 + if (mode == PYRBAC_ATTR_MODE) {
1001 + if (filename != NULL) {
1002 + FILE* file = fopen(filename, "r");
1005 + ret_userattr = fgetuserattr(file);
1010 + ret_userattr = getuserattr();
1012 + else if (mode == PYRBAC_NAM_MODE)
1013 + ret_userattr = getusernam((char*) arg);
1014 + else if (mode == PYRBAC_UID_MODE)
1015 + ret_userattr = getuseruid(*((uid_t*) arg));
1017 + if (ret_userattr == NULL)
1020 + PyObject* entry = PyTuple_New(5);
1021 + if (entry == NULL) {
1022 + free_userattr(ret_userattr);
1026 + PyObject* kv_data = PyDict_New();
1028 + if(ret_userattr->attr != NULL) {
1030 + for(len = 0; len < ret_userattr->attr->length; len++) {
1031 + kv_t current = ret_userattr->attr->data[len];
1033 + PyObject* set = PyList_New(NULL);
1035 + char* item = strtok_r(current.value, ",", &saveptr);
1036 + PyList_Append(set, PyString_FromString(item));
1038 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
1039 + if(PyList_Append(set, PyString_FromString(item)) != 0) {
1041 + Py_XDECREF(kv_data);
1042 + free_userattr(ret_userattr);
1046 + if(PyDict_SetItemString(kv_data, current.key, set)) {
1047 + free_userattr(ret_userattr);
1052 + entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:O}",
1053 + "name", ret_userattr->name,
1054 + "qualifier", ret_userattr->qualifier,
1055 + "res1", ret_userattr->res1,
1056 + "res2", ret_userattr->res2,
1057 + "attributes", kv_data);
1059 + free_userattr(ret_userattr);
1066 +pyrbac_getuserattr(PyObject* self, PyObject* args) {
1067 + return(pyrbac_getuseruidnamattr(self, (void*) NULL, PYRBAC_ATTR_MODE, NULL));
1071 +pyrbac_fgetuserattr(PyObject* self, PyObject* args) {
1072 + char* filename = NULL;
1073 + if(!PyArg_ParseTuple(args, "s:fgetuserattr", &filename))
1075 + return(pyrbac_getuseruidnamattr(self, NULL, PYRBAC_ATTR_MODE, filename));
1079 +pyrbac_getusernam(PyObject* self, PyObject* args) {
1080 + char* name = NULL;
1081 + if(!PyArg_ParseTuple(args, "s:getusernam", &name))
1083 + return(pyrbac_getuseruidnamattr(self, (void*) name, PYRBAC_NAM_MODE, NULL));
1087 +pyrbac_getuseruid(PyObject* self, PyObject* args) {
1089 + if(!PyArg_ParseTuple(args, "i:getuseruid", &uid))
1091 + return(pyrbac_getuseruidnamattr(self, (void*) &uid, PYRBAC_UID_MODE, NULL));
1095 +pyrbac_userattr_next(PyObject* self, PyObject* args) {
1096 + PyObject* retval = pyrbac_getuserattr(self, args);
1097 + if( retval == Py_None ) {
1104 +pyrbac_userattr__iter__(PyObject* self, PyObject* args) {
1113 +Userattr_dealloc(Userattr* self) {
1115 + self->ob_type->tp_free((PyObject*) self);
1119 +Userattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
1121 + self = (Userattr*)type->tp_alloc(type, 0);
1123 + return ((PyObject *) self);
1127 +Userattr_init(Userattr* self, PyObject *args, PyObject *kwargs) {
1132 +static char pyrbac_userattr__doc__[];
1133 +PyDoc_STRVAR(pyrbac_userattr__doc__, "provides functions for \
1134 +interacting with the extended user attributes database. May be iterated over \
1135 +to enumerate user_attr(4) entries\n\n\
1136 +Methods provided:\n\
1144 +static char pyrbac_setuserattr__doc__[];
1145 +static char pyrbac_enduserattr__doc__[];
1146 +static char pyrbac_getuserattr__doc__[];
1147 +static char pyrbac_getusernam__doc__[];
1148 +static char pyrbac_getuseruid__doc__[];
1150 +PyDoc_STRVAR(pyrbac_setuserattr__doc__, "\"rewinds\" the user_attr functions \
1151 +to the first entry in the db. Called automatically by the constructor.\n\
1152 +\tArguments: None\n\
1155 +PyDoc_STRVAR(pyrbac_enduserattr__doc__, "closes the user_attr database, \
1156 +cleans up storage. called automatically by the destructor\n\
1157 +\tArguments: None\n\
1160 +PyDoc_STRVAR(pyrbac_getuserattr__doc__, "Return a single user_attr entry\n \
1161 +\tArguments: None\n\
1162 +\tReturns: a dict representation of a userattr_t struct:\n\
1163 +\t\t\"name\": username\n\
1164 +\t\t\"qualifier\": reserved\n\
1165 +\t\t\"res1\": reserved\n\
1166 +\t\t\"res2\": reserved\n\
1167 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1168 +or a string depending on value"
1171 +PyDoc_STRVAR(pyrbac_fgetuserattr__doc__, "Return a single user_attr entry \
1172 +from a file, bypassing nsswitch.conf\n\
1173 +\tArguments: \'filename\'\n\
1174 +\tReturns: a dict representation of a userattr_t struct:\n\
1175 +\t\t\"name\": username\n\
1176 +\t\t\"qualifier\": reserved\n\
1177 +\t\t\"res1\": reserved\n\
1178 +\t\t\"res2\": reserved\n\
1179 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1180 +or a string depending on value");
1182 +PyDoc_STRVAR(pyrbac_getusernam__doc__, "Searches for a user_attr entry with a \
1184 +\tArgument: \'username\'\n\
1185 +\tReturns: a dict representation of a userattr_t struct:\n\
1186 +\t\t\"name\": username\n\
1187 +\t\t\"qualifier\": reserved\n\
1188 +\t\t\"res1\": reserved\n\
1189 +\t\t\"res2\": reserved\n\
1190 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1191 +or a string depending on value");
1193 +PyDoc_STRVAR(pyrbac_getuseruid__doc__, "Searches for a user_attr entry with a \
1196 +\tReturns: a dict representation of a userattr_t struct:\n\
1197 +\t\t\"name\": username\n\
1198 +\t\t\"qualifier\": reserved\n\
1199 +\t\t\"res1\": reserved\n\
1200 +\t\t\"res2\": reserved\n\
1201 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1202 +or a string depending on value");
1204 +static PyMethodDef Userattr_methods[] = {
1205 + {"setuserattr", pyrbac_setuserattr, METH_NOARGS, pyrbac_setuserattr__doc__},
1206 + {"enduserattr", pyrbac_enduserattr, METH_NOARGS, pyrbac_enduserattr__doc__},
1207 + {"getuserattr", pyrbac_getuserattr, METH_NOARGS, pyrbac_getuserattr__doc__},
1208 + {"fgetuserattr", pyrbac_fgetuserattr, METH_VARARGS, pyrbac_fgetuserattr__doc__},
1209 + {"getusernam", pyrbac_getusernam, METH_VARARGS, pyrbac_getusernam__doc__},
1210 + {"getuseruid", pyrbac_getuseruid, METH_VARARGS, pyrbac_getuseruid__doc__},
1214 +PyTypeObject UserattrType = {
1215 + PyObject_HEAD_INIT(NULL)
1217 + "rbac.userattr", /*tp_name*/
1218 + sizeof(Userattr), /*tp_basicsize*/
1219 + 0, /*tp_itemsize*/
1220 + (destructor)Userattr_dealloc, /*tp_dealloc*/
1226 + 0, /*tp_as_number*/
1227 + 0, /*tp_as_sequence*/
1228 + 0, /*tp_as_mapping*/
1232 + 0, /*tp_getattro*/
1233 + 0, /*tp_setattro*/
1234 + 0, /*tp_as_buffer*/
1235 + Py_TPFLAGS_DEFAULT |
1236 + Py_TPFLAGS_BASETYPE |
1237 + Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
1238 + pyrbac_userattr__doc__, /* tp_doc */
1239 + 0, /* tp_traverse */
1241 + 0, /* tp_richcompare */
1242 + 0, /* tp_weaklistoffset */
1243 + pyrbac_userattr__iter__, /* tp_iter */
1244 + pyrbac_userattr_next, /* tp_iternext */
1245 + Userattr_methods, /* tp_methods */
1246 + 0, /* tp_members */
1247 + 0, /* tp_getset */
1250 + 0, /* tp_descr_get */
1251 + 0, /* tp_descr_set */
1252 + 0, /* tp_dictoffset */
1253 + (initproc)Userattr_init, /* tp_init */
1255 + Userattr_new, /* tp_new */
1257 --- Python-2.7.6/setup.py.~4~ 2014-05-14 13:16:33.749494047 -0700
1258 +++ Python-2.7.6/setup.py 2014-05-14 13:16:33.803607449 -0700
1259 @@ -1549,6 +1549,22 @@
1260 exts.append( Extension('dlpi', ['dlpimodule.c'],
1261 libraries = ['dlpi']) )
1263 + # privileges module (Solaris)
1264 + priv_inc = find_file('priv.h', [], inc_dirs)
1265 + if priv_inc is not None:
1266 + exts.append( Extension('privileges', ['privileges.c']))
1268 + # rbac module (Solaris)
1269 + secdb_inc = find_file('secdb.h', [], inc_dirs)
1270 + aa_inc = find_file('auth_attr.h', [], inc_dirs)
1271 + ea_inc = find_file('exec_attr.h', [], inc_dirs)
1272 + ua_inc = find_file('user_attr.h', [], inc_dirs)
1273 + if secdb_inc is not None and aa_inc is not None and \
1274 + ea_inc is not None and ua_inc is not None:
1275 + exts.append( Extension('rbac', ['pyrbac.c', 'authattr.c', \
1276 + 'execattr.c', 'userattr.c'],
1277 + libraries = ['nsl', 'socket', 'secdb']) )
1279 # Thomas Heller's _ctypes module
1280 self.detect_ctypes(inc_dirs, lib_dirs)
1282 --- /dev/null 2011-02-12 03:13:57.000000000 -0600
1283 +++ Python-2.6.4/Lib/test/privrbactest.py 2011-01-20 13:52:42.862305331 -0600
1285 +#!/usr/bin/python2.7
1287 +# CDDL HEADER START
1289 +# The contents of this file are subject to the terms of the
1290 +# Common Development and Distribution License (the "License").
1291 +# You may not use this file except in compliance with the License.
1293 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1294 +# or http://www.opensolaris.org/os/licensing.
1295 +# See the License for the specific language governing permissions
1296 +# and limitations under the License.
1298 +# When distributing Covered Code, include this CDDL HEADER in each
1299 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1300 +# If applicable, add the following below this CDDL HEADER, with the
1301 +# fields enclosed by brackets "[]" replaced with your own identifying
1302 +# information: Portions Copyright [yyyy] [name of copyright owner]
1307 +# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
1317 +def test_setppriv():
1318 + amchild = os.fork()
1320 + if privileges.setppriv(privileges.PRIV_OFF, privileges.PRIV_EFFECTIVE,
1325 + except OSError, e:
1329 + if child[1] is not 0:
1330 + print "setppriv. Bad exit status from pid %i\n" % child[0]
1334 +def test_getppriv():
1335 + if 'proc_fork' in privileges.getppriv(privileges.PRIV_LIMIT):
1337 + print "getppriv or PRIV_PROC_FORK not in PRIV_LIMIT.\n"
1340 +def test_priv_ineffect():
1341 + if privileges.priv_ineffect('proc_fork'):
1343 + print "priv_ineffect or PRIV_PROC_FORK not in effect\n"
1348 +def test_chkauthattr():
1350 + a = rbac.authattr()
1351 + except Exception, e:
1352 + print "Could not instantiate authattr object: %s\n" % e
1355 + res = a.chkauthattr('solaris.*', 'root')
1356 + except Exception, e:
1357 + print "chkauthattr failed: %s\n" % e
1360 + print "chkauthattr failed or \'root\' lacks \'solaris.*\'\n"
1364 +def test_getauthattr():
1366 + a = rbac.authattr()
1367 + except Exception, e:
1368 + print "Could not instantiate authattr object: %s\n" % e
1371 + res = a.getauthattr()
1372 + except Exception, e:
1373 + print "getauthattr failed: %s\n" % e
1375 + if not 'name' in res.keys():
1376 + print "getauthattr failed\n"
1380 +def test_getauthnam():
1382 + a = rbac.authattr()
1383 + except Exception, e:
1384 + print "Could not instantiate authattr object: %s\n" % e
1387 + res = a.getauthnam('solaris.')
1388 + except Exception, e:
1389 + print "getauthnam failed: %s\n" % e
1392 + print "getauthnam failed or \'solaris.\' not in auth_attr(4)\n"
1396 +def test_authattr_iter():
1398 + a = rbac.authattr()
1399 + except Exception, e:
1400 + print "Could not instantiate authattr object: %s\n" % e
1403 + if not 'name' in res.keys() or type(a) != type(a.__iter__()):
1404 + print "authattr object is not an iterable\n"
1410 +def test_getexecattr():
1412 + a = rbac.execattr()
1413 + except Exception, e:
1414 + print "Could not instantiate execattr object: %s\n" % e
1417 + res = a.getexecattr()
1418 + except Exception, e:
1419 + print "getexecattr failed: %s\n" % e
1421 + if not 'name' in res.keys():
1422 + print "getexecattr failed\n"
1426 +def test_getexecuser():
1428 + a = rbac.execattr()
1429 + except Exception, e:
1430 + print "Could not instantiate execattr object: %s\n" % e
1433 + res = a.getexecuser("root", "act", "*;*;*;*;*")
1434 + except Exception, e:
1435 + print "getexecuser failed: %s\n" % e
1438 + print "getexecuser failed or \'root\' not assigned to \'act\', " \
1439 + "\'*;*;*;*;*\' \n"
1444 +def test_getexecprof():
1446 + a = rbac.execattr()
1447 + except Exception, e:
1448 + print "Could not instantiate execattr object: %s\n" % e
1451 + res = a.getexecprof("All", "cmd", "*")
1452 + except Exception, e:
1453 + print "getexecprof failed: %s\n" % e
1456 + print "getexecprof failed or \'All\' not granted \'cmd\' : \'*\'\n"
1460 +def test_execattr_iter():
1462 + a = rbac.execattr()
1463 + except Exception, e:
1464 + print "Could not instantiate execattr object: %s\n" % e
1467 + if not 'name' in res.keys() or type(a) != type(a.__iter__()):
1468 + print "execattr object is not an iterable\n"
1474 +def test_getuserattr():
1476 + a = rbac.userattr()
1477 + except Exception, e:
1478 + print "Could not instantiate userattr object: %s\n" % e
1481 + res = a.getuserattr()
1482 + except Exception, e:
1483 + print "getuserattr failed: %s\n" % e
1485 + if not 'name' in res.keys():
1486 + print "getuserattr failed\n"
1490 +def test_fgetuserattr():
1491 + temp = tempfile.NamedTemporaryFile()
1492 + temp.write("user::::profiles=Software Installation;roles=foo;"\
1493 + "auths=solaris.foo.bar")
1496 + a = rbac.userattr()
1497 + except Exception, e:
1498 + print "Could not instantiate userattr object: %s\n" % e
1501 + res = a.fgetuserattr(temp.name)
1503 + except Exception, e:
1504 + print "fgetuserattr failed: %s\n" % e
1507 + if not 'name' in res.keys():
1508 + print "fgetuserattr failed\n"
1512 +def test_getuseruid():
1514 + a = rbac.userattr()
1515 + except Exception, e:
1516 + print "Could not instantiate userattr object: %s\n" % e
1519 + res = a.getuseruid(0)
1520 + except Exception, e:
1521 + print "getusernam failed: %s\n" % e
1523 + if not 'name' in res:
1524 + print "getusernam failed or no uid 0\n"
1528 +def test_getusernam():
1530 + a = rbac.userattr()
1531 + except Exception, e:
1532 + print "Could not instantiate userattr object: %s\n" % e
1535 + res = a.getusernam('root')
1536 + except Exception, e:
1537 + print "getusernam failed: %s\n" % e
1539 + if not 'name' in res:
1540 + print "getusernam failed or no \'root\' user\n"
1544 +def test_userattr_iter():
1546 + a = rbac.userattr()
1547 + except Exception, e:
1548 + print "Could not instantiate userattr object: %s\n" % e
1551 + if not 'name' in res.keys() or type(a) != type(a.__iter__()):
1552 + print "userattr object is not an iterable\n"
1556 +if not test_setppriv() or not test_getppriv() or not test_priv_ineffect():
1557 + print "*** Failures detected in privileges module\n"
1560 +if not test_getauthattr() or not test_chkauthattr() or not test_getauthnam() \
1561 + or not test_authattr_iter:
1562 + print "*** Failures detected in rbac.authattr\n"
1565 +if not test_getexecattr() or not test_getexecuser() or not test_getexecprof() \
1566 + or not test_execattr_iter():
1567 + print "*** Failures detected in rbac.execattr\n"
1570 +if not test_getuserattr() or not test_fgetuserattr() or not test_getusernam()\
1571 + or not test_getuseruid() or not test_userattr_iter():
1572 + print "*** Failures detected in rbac.userattr\n"