Line data Source code
1 : /*
2 : Authors:
3 : Sumit Bose <sbose@redhat.com>
4 : Alexander Bokovoy <abokovoy@redhat.com>
5 :
6 : Copyright (C) 2013 Red Hat
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <Python.h>
23 : #include "util/sss_python.h"
24 :
25 : #include "sss_client/idmap/sss_nss_idmap.h"
26 :
27 : #define SSS_NAME_KEY "name"
28 : #define SSS_SID_KEY "sid"
29 : #define SSS_ID_KEY "id"
30 : #define SSS_TYPE_KEY "type"
31 :
32 : enum lookup_type {
33 : SIDBYNAME,
34 : SIDBYID,
35 : NAMEBYSID,
36 : IDBYSID
37 : };
38 :
39 0 : static int add_dict(PyObject *py_result, PyObject *key, PyObject *res_type,
40 : PyObject *res, PyObject *id_type)
41 : {
42 : int ret;
43 : PyObject *py_dict;
44 :
45 0 : py_dict = PyDict_New();
46 0 : if (py_dict == NULL) {
47 0 : return ENOMEM;
48 : }
49 :
50 0 : ret = PyDict_SetItem(py_dict, res_type, res);
51 0 : if (ret != 0) {
52 0 : Py_XDECREF(py_dict);
53 0 : return ret;
54 : }
55 :
56 0 : ret = PyDict_SetItem(py_dict, PyBytes_FromString(SSS_TYPE_KEY), id_type);
57 0 : if (ret != 0) {
58 0 : Py_XDECREF(py_dict);
59 0 : return ret;
60 : }
61 :
62 0 : ret = PyDict_SetItem(py_result, key, py_dict);
63 :
64 0 : return ret;
65 : }
66 :
67 0 : static char *py_string_or_unicode_as_string(PyObject *inp)
68 : {
69 0 : PyObject *py_str = NULL;
70 :
71 0 : if (PyUnicode_Check(inp)) {
72 0 : py_str = PyUnicode_AsUTF8String(inp);
73 0 : } else if (PyBytes_Check(inp)) {
74 0 : py_str = inp;
75 : } else {
76 0 : PyErr_Format(PyExc_TypeError, "input must be unicode or a string");
77 0 : return NULL;
78 : }
79 :
80 0 : return PyBytes_AS_STRING(py_str);
81 : }
82 :
83 0 : static int do_getsidbyname(PyObject *py_result, PyObject *py_name)
84 : {
85 : int ret;
86 : const char *name;
87 0 : char *sid = NULL;
88 : enum sss_id_type id_type;
89 :
90 0 : name = py_string_or_unicode_as_string(py_name);
91 0 : if (name == NULL) {
92 0 : return EINVAL;
93 : }
94 :
95 0 : ret = sss_nss_getsidbyname(name, &sid, &id_type);
96 0 : if (ret == 0) {
97 0 : ret = add_dict(py_result, py_name, PyBytes_FromString(SSS_SID_KEY),
98 : PyUnicode_FromString(sid), PYNUMBER_FROMLONG(id_type));
99 : }
100 0 : free(sid);
101 :
102 0 : return ret;
103 : }
104 :
105 0 : static int do_getnamebysid(PyObject *py_result, PyObject *py_sid)
106 : {
107 : int ret;
108 : const char *sid;
109 0 : char *name = NULL;
110 : enum sss_id_type id_type;
111 :
112 0 : sid = py_string_or_unicode_as_string(py_sid);
113 0 : if (sid == NULL) {
114 0 : return EINVAL;
115 : }
116 :
117 0 : ret = sss_nss_getnamebysid(sid, &name, &id_type);
118 0 : if (ret == 0) {
119 0 : ret = add_dict(py_result, py_sid, PyBytes_FromString(SSS_NAME_KEY),
120 : PyUnicode_FromString(name), PYNUMBER_FROMLONG(id_type));
121 : }
122 0 : free(name);
123 :
124 0 : return ret;
125 : }
126 :
127 0 : static int do_getsidbyid(PyObject *py_result, PyObject *py_id)
128 : {
129 : long id;
130 : const char *id_str;
131 : char *endptr;
132 0 : char *sid = NULL;
133 : int ret;
134 : enum sss_id_type id_type;
135 :
136 : #ifndef IS_PY3K
137 0 : if (PyInt_Check(py_id)) {
138 0 : id = PyInt_AS_LONG(py_id);
139 : } else
140 : #endif
141 0 : if (PyLong_Check(py_id)) {
142 0 : id = PyLong_AsLong(py_id);
143 : } else {
144 0 : id_str = py_string_or_unicode_as_string(py_id);
145 0 : if (id_str == NULL) {
146 0 : return EINVAL;
147 : }
148 0 : errno = 0;
149 0 : id = strtol(id_str, &endptr, 10);
150 0 : if (errno != 0 || *endptr != '\0') {
151 0 : return EINVAL;
152 : }
153 : }
154 :
155 0 : if (id < 0 || id > UINT32_MAX) {
156 0 : return EINVAL;
157 : }
158 :
159 0 : ret = sss_nss_getsidbyid((uint32_t) id, &sid, &id_type);
160 0 : if (ret == 0) {
161 0 : ret = add_dict(py_result, py_id, PyBytes_FromString(SSS_SID_KEY),
162 : PyUnicode_FromString(sid), PYNUMBER_FROMLONG(id_type));
163 : }
164 0 : free(sid);
165 :
166 0 : return ret;
167 : }
168 :
169 0 : static int do_getidbysid(PyObject *py_result, PyObject *py_sid)
170 : {
171 : const char *sid;
172 : uint32_t id;
173 : enum sss_id_type id_type;
174 : int ret;
175 :
176 0 : sid = py_string_or_unicode_as_string(py_sid);
177 0 : if (sid == NULL) {
178 0 : return EINVAL;
179 : }
180 :
181 0 : ret = sss_nss_getidbysid(sid, &id, &id_type);
182 0 : if (ret == 0) {
183 0 : ret = add_dict(py_result, py_sid, PyBytes_FromString(SSS_ID_KEY),
184 : PYNUMBER_FROMLONG(id), PYNUMBER_FROMLONG(id_type));
185 : }
186 :
187 0 : return ret;
188 : }
189 :
190 0 : static int do_lookup(enum lookup_type type, PyObject *py_result,
191 : PyObject *py_inp)
192 : {
193 0 : switch(type) {
194 : case SIDBYNAME:
195 0 : return do_getsidbyname(py_result, py_inp);
196 : break;
197 : case NAMEBYSID:
198 0 : return do_getnamebysid(py_result, py_inp);
199 : break;
200 : case SIDBYID:
201 0 : return do_getsidbyid(py_result, py_inp);
202 : break;
203 : case IDBYSID:
204 0 : return do_getidbysid(py_result, py_inp);
205 : break;
206 : default:
207 0 : return ENOSYS;
208 : }
209 :
210 : return ENOSYS;
211 : }
212 :
213 0 : static PyObject *check_args(enum lookup_type type, PyObject *args)
214 : {
215 : PyObject *obj, *py_value;
216 : int ret;
217 : Py_ssize_t len, i;
218 : PyObject *py_result;
219 :
220 0 : if (!PyArg_ParseTuple(args, sss_py_const_p(char, "O"), &obj)) {
221 0 : PyErr_Format(PyExc_ValueError, "Unable to retrieve argument\n");
222 0 : return NULL;
223 : }
224 :
225 0 : if (!(PyList_Check(obj) || PyTuple_Check(obj) ||
226 0 : PyBytes_Check(obj) || PyUnicode_Check(obj) ||
227 0 : (type == SIDBYID && (PYNUMBER_CHECK(obj))))) {
228 0 : PyErr_Format(PyExc_ValueError,
229 : "Only string, long or list or tuples of them " \
230 : "are accepted\n");
231 0 : return NULL;
232 : }
233 :
234 0 : py_result = PyDict_New();
235 0 : Py_XINCREF(py_result);
236 0 : if (py_result == NULL) {
237 0 : PyErr_Format(PyExc_MemoryError,
238 : "Unable to allocate resulting dictionary\n");
239 0 : return NULL;
240 : }
241 :
242 0 : if (PyList_Check(obj) || PyTuple_Check(obj)) {
243 0 : len = PySequence_Size(obj);
244 0 : for(i=0; i < len; i++) {
245 0 : py_value = PySequence_GetItem(obj, i);
246 0 : if ((py_value != NULL) &&
247 0 : (PyBytes_Check(py_value) || PyUnicode_Check(py_value) ||
248 0 : (type == SIDBYID && PYNUMBER_CHECK(py_value)))) {
249 0 : ret = do_lookup(type, py_result, py_value);
250 0 : if (ret != 0) {
251 : /* Skip this name */
252 0 : continue;
253 : }
254 : }
255 : }
256 : } else {
257 0 : ret = do_lookup(type, py_result, obj);
258 0 : switch (ret) {
259 : case 0:
260 : case ENOENT: /* nothing found, return empty dict */
261 0 : break;
262 : case EINVAL:
263 0 : PyErr_Format(PyExc_ValueError, "Unable to retrieve argument\n");
264 0 : Py_XDECREF(py_result);
265 0 : return NULL;
266 : break;
267 : default:
268 0 : PyErr_Format(PyExc_IOError, "Operation not supported\n");
269 0 : Py_XDECREF(py_result);
270 0 : return NULL;
271 : }
272 : }
273 :
274 0 : Py_XDECREF(py_result);
275 0 : return py_result;
276 :
277 : }
278 :
279 : PyDoc_STRVAR(getsidbyname_doc,
280 : "getsidbyname(name or list/tuple of names) -> dict(name => dict(results))\n\
281 : \n\
282 : Returns a dictionary with a dictonary of results for each given name.\n\
283 : The result dictonary contain the SID and the type of the object which can be\n\
284 : accessed with the key constants SID_KEY and TYPE_KEY, respectively.\n\
285 : \n\
286 : The return type can be one of the following constants:\n\
287 : - ID_NOT_SPECIFIED\n\
288 : - ID_USER\n\
289 : - ID_GROUP\n\
290 : - ID_BOTH"
291 : );
292 :
293 0 : static PyObject * py_getsidbyname(PyObject *module, PyObject *args)
294 : {
295 0 : return check_args(SIDBYNAME, args);
296 : }
297 :
298 : PyDoc_STRVAR(getsidbyid_doc,
299 : "getsidbyid(id or list/tuple of id) -> dict(id => dict(results))\n\
300 : \n\
301 : Returns a dictionary with a dictonary of results for each given POSIX ID.\n\
302 : The result dictonary contain the SID and the type of the object which can be\n\
303 : accessed with the key constants SID_KEY and TYPE_KEY, respectively."
304 : );
305 :
306 0 : static PyObject * py_getsidbyid(PyObject *module, PyObject *args)
307 : {
308 0 : return check_args(SIDBYID, args);
309 : }
310 :
311 : PyDoc_STRVAR(getnamebysid_doc,
312 : "getnamebysid(sid or list/tuple of sid) -> dict(sid => dict(results))\n\
313 : \n\
314 : Returns a dictionary with a dictonary of results for each given SID.\n\
315 : The result dictonary contain the name and the type of the object which can be\n\
316 : accessed with the key constants NAME_KEY and TYPE_KEY, respectively.\n\
317 : \n\
318 : NOTE: getnamebysid currently works only with id_provider set as \"ad\" or \"ipa\""
319 : );
320 :
321 0 : static PyObject * py_getnamebysid(PyObject *module, PyObject *args)
322 : {
323 0 : return check_args(NAMEBYSID, args);
324 : }
325 :
326 : PyDoc_STRVAR(getidbysid_doc,
327 : "getidbysid(sid) -> POSIX ID\n\
328 : \n\
329 : Returns the POSIX ID of the object with the given SID."
330 : "getidbysid(sid or list/tuple of sid) -> dict(sid => dict(results))\n\
331 : \n\
332 : Returns a dictionary with a dictonary of results for each given SID.\n\
333 : The result dictonary contain the POSIX ID and the type of the object which\n\
334 : can be accessed with the key constants ID_KEY and TYPE_KEY, respectively."
335 : );
336 :
337 0 : static PyObject * py_getidbysid(PyObject *module, PyObject *args)
338 : {
339 0 : return check_args(IDBYSID, args);
340 : }
341 :
342 : static PyMethodDef methods[] = {
343 : { sss_py_const_p(char, "getsidbyname"), (PyCFunction) py_getsidbyname,
344 : METH_VARARGS, getsidbyname_doc },
345 : { sss_py_const_p(char, "getsidbyid"), (PyCFunction) py_getsidbyid,
346 : METH_VARARGS, getsidbyid_doc },
347 : { sss_py_const_p(char, "getnamebysid"), (PyCFunction) py_getnamebysid,
348 : METH_VARARGS, getnamebysid_doc },
349 : { sss_py_const_p(char, "getidbysid"), (PyCFunction) py_getidbysid,
350 : METH_VARARGS, getidbysid_doc },
351 : { NULL,NULL, 0, NULL }
352 : };
353 :
354 : #ifdef IS_PY3K
355 : static struct PyModuleDef pysss_nss_idmap_def = {
356 : PyModuleDef_HEAD_INIT,
357 : "pysss_nss_idmap",
358 : NULL,
359 : -1,
360 : methods,
361 : NULL,
362 : NULL,
363 : NULL,
364 : NULL
365 : };
366 :
367 : PyMODINIT_FUNC
368 0 : PyInit_pysss_nss_idmap(void)
369 : #else
370 : PyMODINIT_FUNC
371 0 : initpysss_nss_idmap(void)
372 : #endif
373 : {
374 : PyObject *module;
375 :
376 : #ifdef IS_PY3K
377 0 : module = PyModule_Create(&pysss_nss_idmap_def);
378 : #else
379 0 : module = Py_InitModule3(sss_py_const_p(char, "pysss_nss_idmap"),
380 : methods,
381 : sss_py_const_p(char, "SSSD ID-mapping functions"));
382 : #endif
383 0 : if (module == NULL)
384 0 : MODINITERROR;
385 :
386 0 : PyModule_AddIntConstant(module, "ID_NOT_SPECIFIED",
387 : SSS_ID_TYPE_NOT_SPECIFIED);
388 0 : PyModule_AddIntConstant(module, "ID_USER", SSS_ID_TYPE_UID);
389 0 : PyModule_AddIntConstant(module, "ID_GROUP", SSS_ID_TYPE_GID);
390 0 : PyModule_AddIntConstant(module, "ID_BOTH", SSS_ID_TYPE_BOTH);
391 :
392 0 : PyModule_AddStringConstant(module, "SID_KEY", SSS_SID_KEY);
393 0 : PyModule_AddStringConstant(module, "NAME_KEY", SSS_NAME_KEY);
394 0 : PyModule_AddStringConstant(module, "ID_KEY", SSS_ID_KEY);
395 0 : PyModule_AddStringConstant(module, "TYPE_KEY", SSS_TYPE_KEY);
396 :
397 : #ifdef IS_PY3K
398 0 : return module;
399 : #endif
400 : }
|