1 This patch provides Python RBAC support. It may be contributed upstream at
2 some point, but the suitability (or lack thereof) has not yet been determined.
4 diff --git Python-2.6.4/Modules/authattr.c Python-2.6.4/Modules/authattr.c
6 --- Python-3.9.1/Modules/authattr.c
7 +++ Python-3.9.1/Modules/authattr.c
12 + * The contents of this file are subject to the terms of the
13 + * Common Development and Distribution License (the "License").
14 + * You may not use this file except in compliance with the License.
16 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
17 + * or http://www.opensolaris.org/os/licensing.
18 + * See the License for the specific language governing permissions
19 + * and limitations under the License.
21 + * When distributing Covered Code, include this CDDL HEADER in each
22 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
23 + * If applicable, add the following below this CDDL HEADER, with the
24 + * fields enclosed by brackets "[]" replaced with your own identifying
25 + * information: Portions Copyright [yyyy] [name of copyright owner]
31 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
35 + * RBAC Bindings for Python - auth_attr functions
38 +#include <auth_attr.h>
43 +pyrbac_setauthattr(PyObject* self, PyObject* args) {
49 +pyrbac_endauthattr(PyObject* self, PyObject* args) {
55 +pyrbac_getauthnamattr(PyObject* self, char* authname, int mode) {
59 + authattr_t * ret_authattr = (mode == PYRBAC_NAM_MODE) ? getauthnam(authname) : getauthattr();
60 + if (ret_authattr == NULL)
63 + PyObject* kv_data = PyDict_New();
64 + if (kv_data == NULL) {
65 + free_authattr(ret_authattr);
69 + if(ret_authattr->attr != NULL) {
71 + for(len = 0; len < ret_authattr->attr->length; len++) {
72 + kv_t current = ret_authattr->attr->data[len];
74 + PyObject* set = PyList_New(NULL);
76 + char* item = strtok_r(current.value, ",", &saveptr);
77 + PyList_Append(set, PyBytes_FromString(item));
79 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
80 + if(PyList_Append(set, PyBytes_FromString(item)) != 0) {
82 + Py_XDECREF(kv_data);
83 + free_authattr(ret_authattr);
87 + if(PyDict_SetItemString(kv_data, current.key, set)) {
88 + free_authattr(ret_authattr);
93 + PyObject * retval = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:O}",
94 + "name",ret_authattr->name,
95 + "res1",ret_authattr->res1,
96 + "res2",ret_authattr->res2,
97 + "short",ret_authattr->short_desc,
98 + "long",ret_authattr->long_desc,
99 + "attributes",kv_data);
101 + free_authattr(ret_authattr);
107 +pyrbac_getauthattr(PyObject* self, PyObject* args) {
108 + return(pyrbac_getauthnamattr(self, NULL, PYRBAC_ATTR_MODE));
112 +pyrbac_getauthnam(PyObject* self, PyObject* args) {
114 + if(!PyArg_ParseTuple(args, "s:getauthnam", &name))
116 + return(pyrbac_getauthnamattr(self, name, PYRBAC_NAM_MODE));
120 +pyrbac_chkauthattr(PyObject* self, PyObject* args) {
121 + char* authstring = NULL;
122 + char* username = NULL;
123 + if(!PyArg_ParseTuple(args, "ss:chkauthattr", &authstring, &username))
125 + return PyBool_FromLong((long)chkauthattr(authstring, username));
129 +pyrbac_authattr_next(PyObject* self, PyObject* args) {
130 + PyObject* retval = pyrbac_getauthattr(self, args);
131 + if( retval == Py_None ) {
138 +pyrbac_authattr__iter__(PyObject* self, PyObject* args) {
147 +Authattr_dealloc(Authattr* self) {
149 + Py_TYPE(self)->tp_free((PyObject*) self);
153 +Authattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
155 + self = (Authattr*)type->tp_alloc(type, 0);
157 + return ((PyObject *) self);
161 +Authattr_init(Authattr* self, PyObject *args, PyObject *kwargs) {
166 +PyDoc_STRVAR(pyrbac_authattr__doc__, """provides interfaces to the auth_attr \
167 +database. may be iterated over to return all auth_attr entries\n\n\
168 +Methods provided:\n\
175 +PyDoc_STRVAR(pyrbac_setauthattr__doc__,
176 +"\"rewinds\" the auth_attr functions to the first entry in the db. Called \
177 +automatically by the constructor\n\tArguments: None\n\tReturns: None");
179 +PyDoc_STRVAR(pyrbac_endauthattr__doc__,
180 +"closes the auth_attr database, cleans up storage. called automatically by \
181 +the destructor\n\tArguments: None\n\tReturns: None");
183 +PyDoc_STRVAR(pyrbac_chkauthattr__doc__, "verifies if a user has a given \
184 +authorization.\n\tArguments: 2 Python strings, 'authname' and 'username'\n\
185 +\tReturns: True if the user is authorized, False otherwise");
187 +PyDoc_STRVAR(pyrbac_getauthattr__doc__,
188 +"return one entry from the auth_attr database\n\
189 +\tArguments: None\n\
190 +\tReturns: a dict representing the authattr_t struct:\n\
191 +\t\t\"name\": Authorization Name\n\
192 +\t\t\"res1\": reserved\n\
193 +\t\t\"res2\": reserved\n\
194 +\t\t\"short\": Short Description\n\
195 +\t\t\"long\": Long Description\n\
196 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
197 +or a string depending on value");
199 +PyDoc_STRVAR(pyrbac_getauthnam__doc__,
200 +"searches the auth_attr database for a given authorization name\n\
201 +\tArguments: a Python string containing the auth name\n\
202 +\tReturns: a dict representing the authattr_t struct:\n\
203 +\t\t\"name\": Authorization Name\n\
204 +\t\t\"res1\": reserved\n\
205 +\t\t\"res2\": reserved\n\
206 +\t\t\"short\": Short Description\n\
207 +\t\t\"long\": Long Description\n\
208 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
209 +or a string depending on value");
211 +static PyMethodDef Authattr_methods[] = {
212 + {"setauthattr", pyrbac_setauthattr, METH_NOARGS, pyrbac_setauthattr__doc__},
213 + {"endauthattr", pyrbac_endauthattr, METH_NOARGS, pyrbac_endauthattr__doc__},
214 + {"chkauthattr", pyrbac_chkauthattr, METH_VARARGS, pyrbac_chkauthattr__doc__},
215 + {"getauthattr", pyrbac_getauthattr, METH_NOARGS, pyrbac_getauthattr__doc__},
216 + {"getauthnam", pyrbac_getauthnam, METH_VARARGS, pyrbac_getauthnam__doc__},
220 +PyTypeObject AuthattrType = {
221 + PyVarObject_HEAD_INIT(NULL, 0)
222 + "rbac.authattr", /*tp_name*/
223 + sizeof(Authattr), /*tp_basicsize*/
225 + (destructor)Authattr_dealloc, /*tp_dealloc*/
231 + 0, /*tp_as_number*/
232 + 0, /*tp_as_sequence*/
233 + 0, /*tp_as_mapping*/
239 + 0, /*tp_as_buffer*/
240 + Py_TPFLAGS_DEFAULT |
241 + Py_TPFLAGS_BASETYPE, /*tp_flags*/
242 + pyrbac_authattr__doc__, /* tp_doc */
243 + 0, /* tp_traverse */
245 + 0, /* tp_richcompare */
246 + 0, /* tp_weaklistoffset */
247 + pyrbac_authattr__iter__, /* tp_iter */
248 + pyrbac_authattr_next, /* tp_iternext */
249 + Authattr_methods, /* tp_methods */
250 + 0, /* tp_members */
254 + 0, /* tp_descr_get */
255 + 0, /* tp_descr_set */
256 + 0, /* tp_dictoffset */
257 + (initproc)Authattr_init, /* tp_init */
259 + Authattr_new, /* tp_new */
263 --- Python-3.9.1/Modules/execattr.c
264 +++ Python-3.9.1/Modules/execattr.c
267 + * CDDL HEADER START
269 + * The contents of this file are subject to the terms of the
270 + * Common Development and Distribution License (the "License").
271 + * You may not use this file except in compliance with the License.
273 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
274 + * or http://www.opensolaris.org/os/licensing.
275 + * See the License for the specific language governing permissions
276 + * and limitations under the License.
278 + * When distributing Covered Code, include this CDDL HEADER in each
279 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
280 + * If applicable, add the following below this CDDL HEADER, with the
281 + * fields enclosed by brackets "[]" replaced with your own identifying
282 + * information: Portions Copyright [yyyy] [name of copyright owner]
288 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
292 + * RBAC Bindings for Python - exec_attr functions
295 +#include <exec_attr.h>
300 +pyrbac_setexecattr(PyObject* self, PyObject* args) {
306 +pyrbac_endexecattr(PyObject* self, PyObject* args) {
312 +pyrbac_getexecuserprofattr(PyObject* self, char* userprofname, char* type, char* id, int mode) {
314 + PyObject* ep_data = (mode == PYRBAC_ATTR_MODE) ? NULL : PyList_New(0);
316 + if (ep_data == NULL && mode != PYRBAC_ATTR_MODE )
319 + execattr_t *execprof;
320 + if (mode == PYRBAC_USER_MODE)
321 + execprof = getexecuser(userprofname, type, id, GET_ALL);
322 + else if (mode == PYRBAC_PROF_MODE)
323 + execprof = getexecprof(userprofname, type, id, GET_ALL);
324 + else if (mode == PYRBAC_ATTR_MODE)
325 + execprof = getexecattr();
329 + if (execprof == NULL)
332 + execattr_t *execprof_head = execprof;
334 + while(execprof != NULL) {
336 + PyObject* kv_data = PyDict_New();
338 + if(execprof->attr != NULL) {
340 + for(len = 0; len < execprof->attr->length; len++) {
341 + kv_t current = execprof->attr->data[len];
343 + PyObject* set = PyList_New(NULL);
345 + char* item = strtok_r(current.value, ",", &saveptr);
346 + PyList_Append(set, PyBytes_FromString(item));
348 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
349 + if(PyList_Append(set, PyBytes_FromString(item)) != 0) {
351 + Py_XDECREF(kv_data);
352 + free_execattr(execprof_head);
356 + if(PyDict_SetItemString(kv_data, current.key, set)) {
357 + free_execattr(execprof_head);
362 + PyObject* entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:s,s:O}",
363 + "name", execprof->name,
364 + "type", execprof->type,
365 + "policy", execprof->policy,
366 + "res1", execprof->res1,
367 + "res2", execprof->res2,
368 + "id", execprof->id,
369 + "attributes", kv_data);
371 + if (entry == NULL) {
372 + Py_XDECREF(kv_data);
373 + free_execattr(execprof_head);
377 + if (mode == PYRBAC_ATTR_MODE) {
378 + free_execattr(execprof_head);
381 + PyList_Append(ep_data, entry);
382 + execprof = execprof->next;
385 + free_execattr(execprof_head);
391 +pyrbac_getexecuser(PyObject* self, PyObject* args) {
392 + char* username = NULL;
396 + if(!PyArg_ParseTuple(args, "sss:getexecuser", &username, &type, &id))
399 + return (pyrbac_getexecuserprofattr(self, username, type, id, PYRBAC_USER_MODE));
403 +pyrbac_getexecprof(PyObject* self, PyObject* args) {
405 + char* profname = NULL;
409 + if(!PyArg_ParseTuple(args, "sss:getexecprof", &profname, &type, &id))
412 + return (pyrbac_getexecuserprofattr(self, profname, type, id, PYRBAC_PROF_MODE));
416 +pyrbac_getexecattr(PyObject* self, PyObject* args) {
417 + return pyrbac_getexecuserprofattr(self, NULL, NULL, NULL, PYRBAC_ATTR_MODE);
421 +pyrbac_execattr_next(PyObject* self, PyObject* args) {
422 + PyObject* retval = pyrbac_getexecattr(self, args);
423 + if( retval == Py_None ) {
430 +pyrbac_execattr__iter__(PyObject* self, PyObject* args) {
439 +Execattr_dealloc(Execattr* self) {
441 + Py_TYPE(self)->tp_free((PyObject*) self);
445 +Execattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
447 + self = (Execattr*)type->tp_alloc(type, 0);
449 + return ((PyObject *) self);
453 +Execattr_init(Execattr* self, PyObject *args, PyObject *kwargs) {
458 +PyDoc_STRVAR(pyrbac_execattr__doc__, "provides functions for \
459 +interacting with the execution profiles database. May be iterated over to \
460 +enumerate exec_attr(4) entries\n\n\
461 +Methods provided:\n\
469 +PyDoc_STRVAR(pyrbac_setexecattr__doc__,
470 +"\"rewinds\" the exec_attr functions to the first entry in the db. Called \
471 +automatically by the constructor.\n\
475 +PyDoc_STRVAR(pyrbac_endexecattr__doc__,
476 +"closes the exec_attr database, cleans up storage. called automatically by \
481 +PyDoc_STRVAR(pyrbac_getexecuser__doc__, "corresponds with getexecuser(3SECDB)\
482 +\nTakes: \'username\', \'type\', \'id\'\n\
483 +Return: a single exec_attr entry\n\
484 +\tArguments: None\n\
485 +\tReturns: a dict representation of an execattr_t struct:\n\
486 +\t\t\"name\": Authorization Name\n\
487 +\t\t\"type\": Profile Type\n\
488 +\t\t\"policy\": Policy attributes are relevant in\n\
489 +\t\t\"res1\": reserved\n\
490 +\t\t\"res2\": reserved\n\
491 +\t\t\"id\": unique identifier\n\
492 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
493 +either a list or a string depending on value");
495 +PyDoc_STRVAR(pyrbac_getexecprof__doc__, "corresponds with getexecprof(3SECDB)\
496 +\nTakes: \'profile name\', \'type\', \'id\'\n\
497 +\tReturns: a dict representation of an execattr_t struct:\n\
498 +\t\t\"name\": Authorization Name\n\
499 +\t\t\"type\": Profile Type\n\
500 +\t\t\"policy\": Policy attributes are relevant in\n\
501 +\t\t\"res1\": reserved\n\
502 +\t\t\"res2\": reserved\n\
503 +\t\t\"id\": unique identifier\n\
504 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
505 +either a list or a string depending on value");
507 +PyDoc_STRVAR(pyrbac_getexecattr__doc__, "corresponds with getexecattr(3SECDB)\
508 +\nTakes 0 arguments\n\
509 +\tReturns: a dict representation of an execattr_t struct:\n\
510 +\t\t\"name\": Authorization Name\n\
511 +\t\t\"type\": Profile Type\n\
512 +\t\t\"policy\": Policy attributes are relevant in\n\
513 +\t\t\"res1\": reserved\n\
514 +\t\t\"res2\": reserved\n\
515 +\t\t\"id\": unique identifier\n\
516 +\t\t\"attributes\": A Python dict keyed by attribute & valued as\
517 +either a list or a string depending on value");
519 +static PyMethodDef Execattr_methods[] = {
520 + {"setexecattr", pyrbac_setexecattr, METH_NOARGS, pyrbac_setexecattr__doc__},
521 + {"endexecattr", pyrbac_endexecattr, METH_NOARGS, pyrbac_endexecattr__doc__},
522 + {"getexecprof", pyrbac_getexecprof, METH_VARARGS, pyrbac_getexecprof__doc__},
523 + {"getexecuser", pyrbac_getexecuser, METH_VARARGS, pyrbac_getexecuser__doc__},
524 + {"getexecattr", pyrbac_getexecattr, METH_NOARGS, pyrbac_getexecattr__doc__},
528 +PyTypeObject ExecattrType = {
529 + PyVarObject_HEAD_INIT(NULL, 0)
530 + "rbac.execattr", /*tp_name*/
531 + sizeof(Execattr), /*tp_basicsize*/
533 + (destructor)Execattr_dealloc, /*tp_dealloc*/
539 + 0, /*tp_as_number*/
540 + 0, /*tp_as_sequence*/
541 + 0, /*tp_as_mapping*/
547 + 0, /*tp_as_buffer*/
548 + Py_TPFLAGS_DEFAULT |
549 + Py_TPFLAGS_BASETYPE, /*tp_flags*/
550 + pyrbac_execattr__doc__, /* tp_doc */
551 + 0, /* tp_traverse */
553 + 0, /* tp_richcompare */
554 + 0, /* tp_weaklistoffset */
555 + pyrbac_execattr__iter__, /* tp_iter */
556 + pyrbac_execattr_next, /* tp_iternext */
557 + Execattr_methods, /* tp_methods */
558 + 0, /* tp_members */
562 + 0, /* tp_descr_get */
563 + 0, /* tp_descr_set */
564 + 0, /* tp_dictoffset */
565 + (initproc)Execattr_init, /* tp_init */
567 + Execattr_new, /* tp_new */
571 --- Python-3.9.1/Modules/privileges.c
572 +++ Python-3.9.1/Modules/privileges.c
575 + * CDDL HEADER START
577 + * The contents of this file are subject to the terms of the
578 + * Common Development and Distribution License (the "License").
579 + * You may not use this file except in compliance with the License.
581 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
582 + * or http://www.opensolaris.org/os/licensing.
583 + * See the License for the specific language governing permissions
584 + * and limitations under the License.
586 + * When distributing Covered Code, include this CDDL HEADER in each
587 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
588 + * If applicable, add the following below this CDDL HEADER, with the
589 + * fields enclosed by brackets "[]" replaced with your own identifying
590 + * information: Portions Copyright [yyyy] [name of copyright owner]
596 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
600 + * privileges(5) bindings for Python
607 +pyprivileges_setppriv( PyObject *self, PyObject *args) {
608 + priv_op_t op = -1 ;
609 + priv_ptype_t which = NULL;
611 + PyObject* set_list = NULL;
613 + priv_set_t * set = NULL;
615 + if(!PyArg_ParseTuple(args, "iiO:setppriv", &op, &which, &set_list))
618 + if((op != PRIV_ON && op != PRIV_OFF && op != PRIV_SET) ||
619 + (which != PRIV_PERMITTED && which != PRIV_EFFECTIVE &&
620 + which != PRIV_INHERITABLE && which != PRIV_LIMIT))
623 + PyObject* set_string = PyList_GetItem(set_list, 0);
625 + for (i = 1; i < PyList_Size(set_list); ++i) {
626 + PyBytes_Concat(&set_string, PyBytes_FromString(","));
627 + PyBytes_Concat(&set_string, PyList_GetItem(set_list, i));
630 + set = priv_str_to_set(PyBytes_AsString(set_string), ",", NULL );
635 + long ret = (long) setppriv(op, which, set);
637 + // Python inverts true & false
645 +pyprivileges_getppriv( PyObject *self, PyObject *args) {
647 + char* set_str = NULL;
648 + priv_ptype_t which = NULL;
649 + priv_set_t * set = priv_allocset();
653 + if(!PyArg_ParseTuple(args, "i:getppriv", &which))
656 + if (which != PRIV_PERMITTED && which != PRIV_EFFECTIVE &&
657 + which != PRIV_INHERITABLE && which != PRIV_LIMIT)
660 + if (getppriv(which, set) != 0)
663 + set_str = priv_set_to_str(set, ',', PRIV_STR_LIT);
666 + PyObject* set_list = PyList_New(NULL);
668 + char* item = strtok_r(set_str, ",", &saveptr);
669 + PyList_Append(set_list, PyBytes_FromString(item));
671 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
672 + if(PyList_Append(set_list, PyBytes_FromString(item)) != 0) {
673 + Py_XDECREF(set_list);
682 +pyprivileges_priv_inverse( PyObject *self, PyObject *args ) {
684 + PyObject* set_list_in = NULL;
685 + if(!PyArg_ParseTuple(args, "O:priv_inverse", &set_list_in))
688 + PyObject* set_string = PyList_GetItem(set_list_in, 0);
690 + for (i = 1; i < PyList_Size(set_list_in); ++i) {
691 + PyBytes_Concat(set_string, PyBytes_FromString(","));
692 + PyBytes_Concat(set_string, PyList_GetItem(set_list_in, i));
695 + priv_set_t * set = priv_str_to_set(PyBytes_AsString(set_string), ",", NULL);
699 + char * ret_str = priv_set_to_str(set, ',', PRIV_STR_LIT);
702 + PyObject* set_list_out = PyList_New(NULL);
704 + char* item = strtok_r(ret_str, ",", &saveptr);
705 + PyList_Append(set_list_out, PyBytes_FromString(item));
707 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
708 + if(PyList_Append(set_list_out, PyBytes_FromString(item)) != 0) {
709 + Py_XDECREF(set_list_out);
714 + Py_XDECREF(set_list_in);
716 + return(set_list_out);
719 +/* priv_ineffect is a convienient wrapper to priv_get
720 + * however priv_set is, in the context of python, not
721 + * much of a convienience, so it's omitted
724 +pyprivileges_priv_ineffect(PyObject* self, PyObject* args) {
725 + char* privstring=NULL;
726 + if (!PyArg_ParseTuple(args, "s:priv_ineffect", &privstring))
728 + return PyBool_FromLong(priv_ineffect(privstring));
732 +PyDoc_STRVAR(pyprivileges__doc__,
733 +"Provides functions for interacting with the Solaris privileges(5) framework\n\
734 +Functions provided:\n\
740 +PyDoc_STRVAR(pyprivileges_setppriv__doc__,
741 +"Facilitates setting the permitted/inheritable/limit/effective privileges set\n\
743 +\t\tone of (PRIV_ON|PRIV_OFF|PRIV_SET)\n\
744 +\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\
745 +\t\tset of privileges: a list of strings\n\
746 +\tReturns: True on success, False on failure\
749 +PyDoc_STRVAR(pyprivileges_getppriv__doc__,
750 +"Return the process privilege set\n\
752 +\t\tone of (PRIV_PERMITTED|PRIV_INHERITABLE|PRIV_LIMIT|PRIV_EFFECTIVE)\n\
753 +\tReturns: a Python list of strings");
755 +PyDoc_STRVAR(pyprivileges_priv_ineffect__doc__,
756 +"Checks for a privileges presence in the effective set\n\
757 +\tArguments: a String\n\
758 +\tReturns: True if the privilege is in effect, False otherwise");
760 +PyDoc_STRVAR(pyprivileges_priv_inverse__doc__,
761 +"The complement of the set of privileges\n\
762 +\tArguments: a list of strings\n\tReturns: a list of strings");
764 +static PyMethodDef module_methods[] = {
765 + {"setppriv", pyprivileges_setppriv, METH_VARARGS, pyprivileges_setppriv__doc__},
766 + {"getppriv", pyprivileges_getppriv, METH_VARARGS, pyprivileges_getppriv__doc__},
767 + {"priv_ineffect", pyprivileges_priv_ineffect, METH_VARARGS, pyprivileges_priv_ineffect__doc__},
768 + {"priv_inverse", pyprivileges_priv_inverse, METH_VARARGS, pyprivileges_priv_inverse__doc__},
773 +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
774 +#define PyMODINIT_FUNC void
777 +PyInit_privileges (void) {
780 + static struct PyModuleDef moduledef = {
781 + PyModuleDef_HEAD_INIT,
783 + pyprivileges__doc__,
792 + m = PyModule_Create(&moduledef);
796 + PyObject* d = PyModule_GetDict(m);
800 + PyDict_SetItemString(d, "PRIV_ON", PyLong_FromLong((long)PRIV_ON));
801 + PyDict_SetItemString(d, "PRIV_OFF", PyLong_FromLong((long)PRIV_OFF));
802 + PyDict_SetItemString(d, "PRIV_SET", PyLong_FromLong((long)PRIV_SET));
804 + PyDict_SetItemString(d, "PRIV_PERMITTED", PyLong_FromLong((long)PRIV_PERMITTED));
805 + PyDict_SetItemString(d, "PRIV_INHERITABLE", PyLong_FromLong((long)PRIV_INHERITABLE));
806 + PyDict_SetItemString(d, "PRIV_LIMIT", PyLong_FromLong((long)PRIV_LIMIT));
807 + PyDict_SetItemString(d, "PRIV_EFFECTIVE", PyLong_FromLong((long)PRIV_EFFECTIVE));
811 --- Python-3.9.1/Modules/pyrbac.c
812 +++ Python-3.9.1/Modules/pyrbac.c
815 + * CDDL HEADER START
817 + * The contents of this file are subject to the terms of the
818 + * Common Development and Distribution License (the "License").
819 + * You may not use this file except in compliance with the License.
821 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
822 + * or http://www.opensolaris.org/os/licensing.
823 + * See the License for the specific language governing permissions
824 + * and limitations under the License.
826 + * When distributing Covered Code, include this CDDL HEADER in each
827 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
828 + * If applicable, add the following below this CDDL HEADER, with the
829 + * fields enclosed by brackets "[]" replaced with your own identifying
830 + * information: Portions Copyright [yyyy] [name of copyright owner]
836 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
840 + * RBAC Bindings for Python
846 +static PyMethodDef module_methods[] = {NULL};
848 +PyDoc_STRVAR(pyrbac__doc__, "provides access to some objects \
849 +for interaction with the Solaris Role-Based Access Control \
850 +framework.\n\nDynamic objects:\n\
851 +userattr -- for interacting with user_attr(4)\n\
852 +authattr -- for interacting with auth_attr(4)\n\
853 +execattr -- for interacting with exec_attr(4)\n");
855 +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
856 +#define PyMODINIT_FUNC void
859 +PyInit_rbac (void) {
862 + if (PyType_Ready(&AuthattrType) < 0 ||
863 + PyType_Ready(&ExecattrType) < 0 ||
864 + PyType_Ready(&UserattrType) < 0 )
867 + static struct PyModuleDef moduledef = {
868 + PyModuleDef_HEAD_INIT,
879 + m = PyModule_Create(&moduledef);
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);
895 --- Python-3.9.1/Modules/pyrbac.h
896 +++ Python-3.9.1/Modules/pyrbac.h
899 + * CDDL HEADER START
901 + * The contents of this file are subject to the terms of the
902 + * Common Development and Distribution License (the "License").
903 + * You may not use this file except in compliance with the License.
905 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
906 + * or http://www.opensolaris.org/os/licensing.
907 + * See the License for the specific language governing permissions
908 + * and limitations under the License.
910 + * When distributing Covered Code, include this CDDL HEADER in each
911 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
912 + * If applicable, add the following below this CDDL HEADER, with the
913 + * fields enclosed by brackets "[]" replaced with your own identifying
914 + * information: Portions Copyright [yyyy] [name of copyright owner]
920 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
924 + * RBAC bindings for python
932 +#define PYRBAC_USER_MODE 1
933 +#define PYRBAC_PROF_MODE 2
934 +#define PYRBAC_ATTR_MODE 3
935 +#define PYRBAC_NAM_MODE 4
936 +#define PYRBAC_UID_MODE 5
938 +extern PyTypeObject AuthattrType;
939 +extern PyTypeObject ExecattrType;
940 +extern PyTypeObject UserattrType;
943 --- Python-3.9.1/Modules/userattr.c
944 +++ Python-3.9.1/Modules/userattr.c
947 + * CDDL HEADER START
949 + * The contents of this file are subject to the terms of the
950 + * Common Development and Distribution License (the "License").
951 + * You may not use this file except in compliance with the License.
953 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
954 + * or http://www.opensolaris.org/os/licensing.
955 + * See the License for the specific language governing permissions
956 + * and limitations under the License.
958 + * When distributing Covered Code, include this CDDL HEADER in each
959 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
960 + * If applicable, add the following below this CDDL HEADER, with the
961 + * fields enclosed by brackets "[]" replaced with your own identifying
962 + * information: Portions Copyright [yyyy] [name of copyright owner]
968 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
972 + * RBAC Bindings for Python - user_attr functions
976 +#include <user_attr.h>
981 +pyrbac_setuserattr(PyObject* self, PyObject* args) {
987 +pyrbac_enduserattr(PyObject* self, PyObject* args) {
993 +pyrbac_getuseruidnamattr(PyObject* self, void* arg, int mode, char* filename) {
995 + userattr_t *ret_userattr;
997 + if (mode == PYRBAC_ATTR_MODE) {
998 + if (filename != NULL) {
999 + FILE* file = fopen(filename, "r");
1002 + ret_userattr = fgetuserattr(file);
1007 + ret_userattr = getuserattr();
1009 + else if (mode == PYRBAC_NAM_MODE)
1010 + ret_userattr = getusernam((char*) arg);
1011 + else if (mode == PYRBAC_UID_MODE)
1012 + ret_userattr = getuseruid(*((uid_t*) arg));
1014 + if (ret_userattr == NULL)
1017 + PyObject* entry = PyTuple_New(5);
1018 + if (entry == NULL) {
1019 + free_userattr(ret_userattr);
1023 + PyObject* kv_data = PyDict_New();
1025 + if(ret_userattr->attr != NULL) {
1027 + for(len = 0; len < ret_userattr->attr->length; len++) {
1028 + kv_t current = ret_userattr->attr->data[len];
1030 + PyObject* set = PyList_New(NULL);
1032 + char* item = strtok_r(current.value, ",", &saveptr);
1033 + PyList_Append(set, PyBytes_FromString(item));
1035 + while((item = strtok_r(NULL, ",", &saveptr)) != NULL) {
1036 + if(PyList_Append(set, PyBytes_FromString(item)) != 0) {
1038 + Py_XDECREF(kv_data);
1039 + free_userattr(ret_userattr);
1043 + if(PyDict_SetItemString(kv_data, current.key, set)) {
1044 + free_userattr(ret_userattr);
1049 + entry = Py_BuildValue("{s:s,s:s,s:s,s:s,s:O}",
1050 + "name", ret_userattr->name,
1051 + "qualifier", ret_userattr->qualifier,
1052 + "res1", ret_userattr->res1,
1053 + "res2", ret_userattr->res2,
1054 + "attributes", kv_data);
1056 + free_userattr(ret_userattr);
1063 +pyrbac_getuserattr(PyObject* self, PyObject* args) {
1064 + return(pyrbac_getuseruidnamattr(self, (void*) NULL, PYRBAC_ATTR_MODE, NULL));
1068 +pyrbac_fgetuserattr(PyObject* self, PyObject* args) {
1069 + char* filename = NULL;
1070 + if(!PyArg_ParseTuple(args, "s:fgetuserattr", &filename))
1072 + return(pyrbac_getuseruidnamattr(self, NULL, PYRBAC_ATTR_MODE, filename));
1076 +pyrbac_getusernam(PyObject* self, PyObject* args) {
1077 + char* name = NULL;
1078 + if(!PyArg_ParseTuple(args, "s:getusernam", &name))
1080 + return(pyrbac_getuseruidnamattr(self, (void*) name, PYRBAC_NAM_MODE, NULL));
1084 +pyrbac_getuseruid(PyObject* self, PyObject* args) {
1086 + if(!PyArg_ParseTuple(args, "i:getuseruid", &uid))
1088 + return(pyrbac_getuseruidnamattr(self, (void*) &uid, PYRBAC_UID_MODE, NULL));
1092 +pyrbac_userattr_next(PyObject* self, PyObject* args) {
1093 + PyObject* retval = pyrbac_getuserattr(self, args);
1094 + if( retval == Py_None ) {
1101 +pyrbac_userattr__iter__(PyObject* self, PyObject* args) {
1110 +Userattr_dealloc(Userattr* self) {
1112 + Py_TYPE(self)->tp_free((PyObject*) self);
1116 +Userattr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
1118 + self = (Userattr*)type->tp_alloc(type, 0);
1120 + return ((PyObject *) self);
1124 +Userattr_init(Userattr* self, PyObject *args, PyObject *kwargs) {
1129 +PyDoc_STRVAR(pyrbac_userattr__doc__, "provides functions for \
1130 +interacting with the extended user attributes database. May be iterated over \
1131 +to enumerate user_attr(4) entries\n\n\
1132 +Methods provided:\n\
1140 +PyDoc_STRVAR(pyrbac_setuserattr__doc__, "\"rewinds\" the user_attr functions \
1141 +to the first entry in the db. Called automatically by the constructor.\n\
1142 +\tArguments: None\n\
1145 +PyDoc_STRVAR(pyrbac_enduserattr__doc__, "closes the user_attr database, \
1146 +cleans up storage. called automatically by the destructor\n\
1147 +\tArguments: None\n\
1150 +PyDoc_STRVAR(pyrbac_getuserattr__doc__, "Return a single user_attr entry\n \
1151 +\tArguments: None\n\
1152 +\tReturns: a dict representation of a userattr_t struct:\n\
1153 +\t\t\"name\": username\n\
1154 +\t\t\"qualifier\": reserved\n\
1155 +\t\t\"res1\": reserved\n\
1156 +\t\t\"res2\": reserved\n\
1157 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1158 +or a string depending on value"
1161 +PyDoc_STRVAR(pyrbac_fgetuserattr__doc__, "Return a single user_attr entry \
1162 +from a file, bypassing nsswitch.conf\n\
1163 +\tArguments: \'filename\'\n\
1164 +\tReturns: a dict representation of a userattr_t struct:\n\
1165 +\t\t\"name\": username\n\
1166 +\t\t\"qualifier\": reserved\n\
1167 +\t\t\"res1\": reserved\n\
1168 +\t\t\"res2\": reserved\n\
1169 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1170 +or a string depending on value");
1172 +PyDoc_STRVAR(pyrbac_getusernam__doc__, "Searches for a user_attr entry with a \
1174 +\tArgument: \'username\'\n\
1175 +\tReturns: a dict representation of a userattr_t struct:\n\
1176 +\t\t\"name\": username\n\
1177 +\t\t\"qualifier\": reserved\n\
1178 +\t\t\"res1\": reserved\n\
1179 +\t\t\"res2\": reserved\n\
1180 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1181 +or a string depending on value");
1183 +PyDoc_STRVAR(pyrbac_getuseruid__doc__, "Searches for a user_attr entry with a \
1186 +\tReturns: a dict representation of a userattr_t struct:\n\
1187 +\t\t\"name\": username\n\
1188 +\t\t\"qualifier\": reserved\n\
1189 +\t\t\"res1\": reserved\n\
1190 +\t\t\"res2\": reserved\n\
1191 +\t\t\"attributes\": A Python dict keyed by attribute & valued as either a list \
1192 +or a string depending on value");
1194 +static PyMethodDef Userattr_methods[] = {
1195 + {"setuserattr", pyrbac_setuserattr, METH_NOARGS, pyrbac_setuserattr__doc__},
1196 + {"enduserattr", pyrbac_enduserattr, METH_NOARGS, pyrbac_enduserattr__doc__},
1197 + {"getuserattr", pyrbac_getuserattr, METH_NOARGS, pyrbac_getuserattr__doc__},
1198 + {"fgetuserattr", pyrbac_fgetuserattr, METH_VARARGS, pyrbac_fgetuserattr__doc__},
1199 + {"getusernam", pyrbac_getusernam, METH_VARARGS, pyrbac_getusernam__doc__},
1200 + {"getuseruid", pyrbac_getuseruid, METH_VARARGS, pyrbac_getuseruid__doc__},
1204 +PyTypeObject UserattrType = {
1205 + PyVarObject_HEAD_INIT(NULL, 0)
1206 + "rbac.userattr", /*tp_name*/
1207 + sizeof(Userattr), /*tp_basicsize*/
1208 + 0, /*tp_itemsize*/
1209 + (destructor)Userattr_dealloc, /*tp_dealloc*/
1213 + 0, /*tp_reserved*/
1215 + 0, /*tp_as_number*/
1216 + 0, /*tp_as_sequence*/
1217 + 0, /*tp_as_mapping*/
1221 + 0, /*tp_getattro*/
1222 + 0, /*tp_setattro*/
1223 + 0, /*tp_as_buffer*/
1224 + Py_TPFLAGS_DEFAULT |
1225 + Py_TPFLAGS_BASETYPE, /*tp_flags*/
1226 + pyrbac_userattr__doc__, /* tp_doc */
1227 + 0, /* tp_traverse */
1229 + 0, /* tp_richcompare */
1230 + 0, /* tp_weaklistoffset */
1231 + pyrbac_userattr__iter__, /* tp_iter */
1232 + pyrbac_userattr_next, /* tp_iternext */
1233 + Userattr_methods, /* tp_methods */
1234 + 0, /* tp_members */
1235 + 0, /* tp_getset */
1238 + 0, /* tp_descr_get */
1239 + 0, /* tp_descr_set */
1240 + 0, /* tp_dictoffset */
1241 + (initproc)Userattr_init, /* tp_init */
1243 + Userattr_new, /* tp_new */
1247 --- Python-3.9.1/setup.py
1248 +++ Python-3.9.1/setup.py
1249 @@ -1827,6 +1827,24 @@ class PyBuildExt(build_ext):
1250 if dlpi_inc is not None:
1251 self.add(Extension('dlpi', ['dlpimodule.c'], libraries=['dlpi']))
1253 + def detect_priv(self):
1254 + # privileges module (Solaris)
1255 + priv_inc = find_file('priv.h', [], self.inc_dirs)
1256 + if priv_inc is not None:
1257 + self.add(Extension('privileges', ['privileges.c']))
1259 + def detect_rbac(self):
1260 + # rbac module (Solaris)
1261 + secdb_inc = find_file('secdb.h', [], self.inc_dirs)
1262 + aa_inc = find_file('auth_attr.h', [], self.inc_dirs)
1263 + ea_inc = find_file('exec_attr.h', [], self.inc_dirs)
1264 + ua_inc = find_file('user_attr.h', [], self.inc_dirs)
1265 + if secdb_inc is not None and aa_inc is not None and \
1266 + ea_inc is not None and ua_inc is not None:
1267 + self.add(Extension('rbac', ['pyrbac.c', 'authattr.c', \
1268 + 'execattr.c', 'userattr.c'],
1269 + libraries=['nsl', 'socket', 'secdb']))
1271 def detect_modules(self):
1272 self.configure_compiler()
1273 self.init_inc_lib_dirs()
1274 @@ -1849,6 +1867,8 @@ class PyBuildExt(build_ext):
1275 self.detect_decimal()
1278 + self.detect_priv()
1279 + self.detect_rbac()
1280 self.detect_ctypes()
1281 self.detect_multiprocessing()
1282 if not self.detect_tkinter():
1283 --- Python-3.9.1/Lib/test/privrbactest.py
1284 +++ Python-3.9.1/Lib/test/privrbactest.py
1286 +#!/usr/bin/python3.9
1288 +# CDDL HEADER START
1290 +# The contents of this file are subject to the terms of the
1291 +# Common Development and Distribution License (the "License").
1292 +# You may not use this file except in compliance with the License.
1294 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1295 +# or http://www.opensolaris.org/os/licensing.
1296 +# See the License for the specific language governing permissions
1297 +# and limitations under the License.
1299 +# When distributing Covered Code, include this CDDL HEADER in each
1300 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1301 +# If applicable, add the following below this CDDL HEADER, with the
1302 +# fields enclosed by brackets "[]" replaced with your own identifying
1303 +# information: Portions Copyright [yyyy] [name of copyright owner]
1308 +# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
1318 +def test_setppriv():
1319 + amchild = os.fork()
1321 + if privileges.setppriv(privileges.PRIV_OFF, privileges.PRIV_EFFECTIVE,
1326 + except OSError as e:
1330 + if child[1] is not 0:
1331 + print("setppriv. Bad exit status from pid %i\n" % child[0])
1335 +def test_getppriv():
1336 + if 'proc_fork' in privileges.getppriv(privileges.PRIV_LIMIT):
1338 + print("getppriv or PRIV_PROC_FORK not in PRIV_LIMIT.\n")
1341 +def test_priv_ineffect():
1342 + if privileges.priv_ineffect('proc_fork'):
1344 + print("priv_ineffect or PRIV_PROC_FORK not in effect\n")
1349 +def test_chkauthattr():
1351 + a = rbac.authattr()
1352 + except Exception as e:
1353 + print("Could not instantiate authattr object: %s\n" % e)
1356 + res = a.chkauthattr('solaris.*', 'root')
1357 + except Exception as e:
1358 + print("chkauthattr failed: %s\n" % e)
1361 + print("chkauthattr failed or \'root\' lacks \'solaris.*\'\n")
1365 +def test_getauthattr():
1367 + a = rbac.authattr()
1368 + except Exception as e:
1369 + print("Could not instantiate authattr object: %s\n" % e)
1372 + res = a.getauthattr()
1373 + except Exception as e:
1374 + print("getauthattr failed: %s\n" % e)
1376 + if not 'name' in list(res.keys()):
1377 + print("getauthattr failed\n")
1381 +def test_getauthnam():
1383 + a = rbac.authattr()
1384 + except Exception as e:
1385 + print("Could not instantiate authattr object: %s\n" % e)
1388 + res = a.getauthnam('solaris.')
1389 + except Exception as e:
1390 + print("getauthnam failed: %s\n" % e)
1393 + print("getauthnam failed or \'solaris.\' not in auth_attr(4)\n")
1397 +def test_authattr_iter():
1399 + a = rbac.authattr()
1400 + except Exception as e:
1401 + print("Could not instantiate authattr object: %s\n" % e)
1404 + if not 'name' in list(res.keys()) or type(a) != type(a.__iter__()):
1405 + print("authattr object is not an iterable\n")
1411 +def test_getexecattr():
1413 + a = rbac.execattr()
1414 + except Exception as e:
1415 + print("Could not instantiate execattr object: %s\n" % e)
1418 + res = a.getexecattr()
1419 + except Exception as e:
1420 + print("getexecattr failed: %s\n" % e)
1422 + if not 'name' in list(res.keys()):
1423 + print("getexecattr failed\n")
1427 +def test_getexecuser():
1429 + a = rbac.execattr()
1430 + except Exception as e:
1431 + print("Could not instantiate execattr object: %s\n" % e)
1434 + res = a.getexecuser("root", "act", "*;*;*;*;*")
1435 + except Exception as e:
1436 + print("getexecuser failed: %s\n" % e)
1439 + print("getexecuser failed or \'root\' not assigned to \'act\', " \
1440 + "\'*;*;*;*;*\' \n")
1445 +def test_getexecprof():
1447 + a = rbac.execattr()
1448 + except Exception as e:
1449 + print("Could not instantiate execattr object: %s\n" % e)
1452 + res = a.getexecprof("All", "cmd", "*")
1453 + except Exception as e:
1454 + print("getexecprof failed: %s\n" % e)
1457 + print("getexecprof failed or \'All\' not granted \'cmd\' : \'*\'\n")
1461 +def test_execattr_iter():
1463 + a = rbac.execattr()
1464 + except Exception as e:
1465 + print("Could not instantiate execattr object: %s\n" % e)
1468 + if not 'name' in list(res.keys()) or type(a) != type(a.__iter__()):
1469 + print("execattr object is not an iterable\n")
1475 +def test_getuserattr():
1477 + a = rbac.userattr()
1478 + except Exception as e:
1479 + print("Could not instantiate userattr object: %s\n" % e)
1482 + res = a.getuserattr()
1483 + except Exception as e:
1484 + print("getuserattr failed: %s\n" % e)
1486 + if not 'name' in list(res.keys()):
1487 + print("getuserattr failed\n")
1491 +def test_fgetuserattr():
1492 + temp = tempfile.NamedTemporaryFile()
1493 + temp.write("user::::profiles=Software Installation;roles=foo;"\
1494 + "auths=solaris.foo.bar")
1497 + a = rbac.userattr()
1498 + except Exception as e:
1499 + print("Could not instantiate userattr object: %s\n" % e)
1502 + res = a.fgetuserattr(temp.name)
1504 + except Exception as e:
1505 + print("fgetuserattr failed: %s\n" % e)
1508 + if not 'name' in list(res.keys()):
1509 + print("fgetuserattr failed\n")
1513 +def test_getuseruid():
1515 + a = rbac.userattr()
1516 + except Exception as e:
1517 + print("Could not instantiate userattr object: %s\n" % e)
1520 + res = a.getuseruid(0)
1521 + except Exception as e:
1522 + print("getusernam failed: %s\n" % e)
1524 + if not 'name' in res:
1525 + print("getusernam failed or no uid 0\n")
1529 +def test_getusernam():
1531 + a = rbac.userattr()
1532 + except Exception as e:
1533 + print("Could not instantiate userattr object: %s\n" % e)
1536 + res = a.getusernam('root')
1537 + except Exception as e:
1538 + print("getusernam failed: %s\n" % e)
1540 + if not 'name' in res:
1541 + print("getusernam failed or no \'root\' user\n")
1545 +def test_userattr_iter():
1547 + a = rbac.userattr()
1548 + except Exception as e:
1549 + print("Could not instantiate userattr object: %s\n" % e)
1552 + if not 'name' in list(res.keys()) or type(a) != type(a.__iter__()):
1553 + print("userattr object is not an iterable\n")
1557 +if not test_setppriv() or not test_getppriv() or not test_priv_ineffect():
1558 + print("*** Failures detected in privileges module\n")
1561 +if not test_getauthattr() or not test_chkauthattr() or not test_getauthnam() \
1562 + or not test_authattr_iter:
1563 + print("*** Failures detected in rbac.authattr\n")
1566 +if not test_getexecattr() or not test_getexecuser() or not test_getexecprof() \
1567 + or not test_execattr_iter():
1568 + print("*** Failures detected in rbac.execattr\n")
1571 +if not test_getuserattr() or not test_fgetuserattr() or not test_getusernam()\
1572 + or not test_getuseruid() or not test_userattr_iter():
1573 + print("*** Failures detected in rbac.userattr\n")