2 Unix SMB/CIFS implementation.
3 Copyright (C) Luke Morrison <luc785@hotmail.com> 2013
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "param/pyparam.h"
26 #include "../libds/common/flags.h"
27 #include "librpc/rpc/pyrpc_util.h"
28 #include "auth/credentials/pycredentials.h"
29 #include "libcli/util/pyerrors.h"
31 /* A Python C API module to use LIBGPO */
33 #define GPO_getter(ATTR) \
34 static PyObject* GPO_get_##ATTR(PyObject *self, void *closure) \
36 struct GROUP_POLICY_OBJECT *gpo_ptr \
37 = pytalloc_get_ptr(self); \
40 return PyString_FromString(gpo_ptr->ATTR); \
45 GPO_getter(file_sys_path
)
46 GPO_getter(display_name
)
49 GPO_getter(user_extensions
)
50 GPO_getter(machine_extensions
)
52 static PyGetSetDef GPO_setters
[] = {
53 {discard_const_p(char, "ds_path"), (getter
)GPO_get_ds_path
, NULL
, NULL
,
55 {discard_const_p(char, "file_sys_path"), (getter
)GPO_get_file_sys_path
,
57 {discard_const_p(char, "display_name"), (getter
)GPO_get_display_name
, NULL
,
59 {discard_const_p(char, "name"), (getter
)GPO_get_name
, NULL
, NULL
, NULL
},
60 {discard_const_p(char, "link"), (getter
)GPO_get_link
, NULL
, NULL
, NULL
},
61 {discard_const_p(char, "user_extensions"), (getter
)GPO_get_user_extensions
,
63 {discard_const_p(char, "machine_extensions"),
64 (getter
)GPO_get_machine_extensions
, NULL
, NULL
, NULL
},
68 static PyObject
*py_gpo_get_unix_path(PyObject
*self
, PyObject
*args
,
72 const char *cache_dir
= NULL
;
73 PyObject
*ret
= Py_None
;
74 char *unix_path
= NULL
;
75 TALLOC_CTX
*frame
= NULL
;
76 static const char *kwlist
[] = {"cache_dir", NULL
};
77 struct GROUP_POLICY_OBJECT
*gpo_ptr \
78 = (struct GROUP_POLICY_OBJECT
*)pytalloc_get_ptr(self
);
80 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|s",
81 discard_const_p(char *, kwlist
),
83 PyErr_SetString(PyExc_SystemError
,
84 "Failed to parse arguments to gpo_get_unix_path()");
89 cache_dir
= cache_path(GPO_CACHE_DIR
);
91 PyErr_SetString(PyExc_MemoryError
,
92 "Failed to determine gpo cache dir");
97 frame
= talloc_stackframe();
99 status
= gpo_get_unix_path(frame
, cache_dir
, gpo_ptr
, &unix_path
);
103 if (!NT_STATUS_IS_OK(status
)) {
104 PyErr_SetString(PyExc_SystemError
,
105 "Failed to determine gpo unix path");
109 ret
= PyString_FromString(unix_path
);
115 static PyMethodDef GPO_methods
[] = {
116 {"get_unix_path", (PyCFunction
)py_gpo_get_unix_path
, METH_KEYWORDS
, NULL
},
120 static PyTypeObject GPOType
= {
121 PyVarObject_HEAD_INIT(NULL
, 0)
122 .tp_name
= "gpo.GROUP_POLICY_OBJECT",
123 .tp_doc
= "GROUP_POLICY_OBJECT",
124 .tp_getset
= GPO_setters
,
125 .tp_methods
= GPO_methods
,
126 .tp_flags
= Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
132 struct cli_credentials
*cli_creds
;
135 static void py_ads_dealloc(ADS
* self
)
137 ads_destroy(&(self
->ads_ptr
));
138 Py_TYPE(self
)->tp_free((PyObject
*)self
);
141 static PyObject
* py_ads_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
144 self
= (ADS
*)type
->tp_alloc(type
, 0);
145 return (PyObject
*)self
;
148 static PyObject
* py_ads_connect(ADS
*self
);
149 static int py_ads_init(ADS
*self
, PyObject
*args
, PyObject
*kwds
)
151 const char *realm
= NULL
;
152 const char *workgroup
= NULL
;
153 const char *ldap_server
= NULL
;
154 PyObject
*py_creds
= NULL
;
155 PyObject
*lp_obj
= NULL
;
156 struct loadparm_context
*lp_ctx
= NULL
;
158 static const char *kwlist
[] = {"ldap_server", "loadparm_context",
159 "credentials", NULL
};
160 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "sO|O",
161 discard_const_p(char *, kwlist
),
162 &ldap_server
, &lp_obj
, &py_creds
))
166 if (!py_check_dcerpc_type(py_creds
, "samba.credentials",
168 PyErr_Format(PyExc_TypeError
,
169 "Expected samba.credentaials "
170 "for credentials argument");
174 = PyCredentials_AsCliCredentials(py_creds
);
179 lp_ctx
= pytalloc_get_type(lp_obj
, struct loadparm_context
);
180 if (lp_ctx
== NULL
) {
183 ok
= lp_load_initial_only(lp_ctx
->szConfigFile
);
189 if (self
->cli_creds
) {
190 realm
= cli_credentials_get_realm(self
->cli_creds
);
191 workgroup
= cli_credentials_get_domain(self
->cli_creds
);
194 workgroup
= lp_workgroup();
195 if (!ldap_server
) return -1;
198 if ( !(self
->ads_ptr
= ads_init(realm
, workgroup
, ldap_server
)) )
204 static PyObject
* py_ads_connect(ADS
*self
)
207 TALLOC_CTX
*frame
= talloc_stackframe();
208 if (self
->cli_creds
) {
209 self
->ads_ptr
->auth
.user_name
=
210 SMB_STRDUP(cli_credentials_get_username(self
->cli_creds
));
211 self
->ads_ptr
->auth
.flags
|= ADS_AUTH_USER_CREDS
;
212 self
->ads_ptr
->auth
.password
=
213 SMB_STRDUP(cli_credentials_get_password(self
->cli_creds
));
214 self
->ads_ptr
->auth
.realm
=
215 SMB_STRDUP(cli_credentials_get_realm(self
->cli_creds
));
217 status
= ads_connect_user_creds(self
->ads_ptr
);
218 if (!ADS_ERR_OK(status
)) {
219 PyErr_SetString(PyExc_SystemError
, "ads_connect() failed");
226 if (asprintf(&(self
->ads_ptr
->auth
.user_name
), "%s$",
227 lp_netbios_name()) == -1) {
228 PyErr_SetString(PyExc_SystemError
, "Failed to asprintf");
232 self
->ads_ptr
->auth
.flags
|= ADS_AUTH_USER_CREDS
;
233 if (!secrets_init()) {
234 PyErr_SetString(PyExc_SystemError
, "secrets_init() failed");
239 secrets_fetch_machine_password(self
->ads_ptr
->server
.workgroup
,
241 PyErr_SetString(PyExc_SystemError
,
242 "Failed to fetch the machine account password");
246 self
->ads_ptr
->auth
.password
= smb_xstrdup(passwd
);
247 self
->ads_ptr
->auth
.realm
= smb_xstrdup(self
->ads_ptr
->server
.realm
);
248 if (!strupper_m(self
->ads_ptr
->auth
.realm
)) {
249 PyErr_SetString(PyExc_SystemError
, "Failed to strdup");
255 status
= ads_connect(self
->ads_ptr
);
256 if (!ADS_ERR_OK(status
)) {
257 PyErr_SetString(PyExc_SystemError
, "ads_connect() failed");
268 /* Parameter mapping and functions for the GP_EXT struct */
271 /* Global methods aka do not need a special pyobject type */
272 static PyObject
*py_gpo_get_sysvol_gpt_version(PyObject
* self
,
275 TALLOC_CTX
*tmp_ctx
= NULL
;
277 char *display_name
= NULL
;
278 uint32_t sysvol_version
= 0;
282 tmp_ctx
= talloc_new(NULL
);
284 if (!PyArg_ParseTuple(args
, "s", &unix_path
)) {
287 status
= gpo_get_sysvol_gpt_version(tmp_ctx
, unix_path
,
290 if (!NT_STATUS_IS_OK(status
)) {
291 PyErr_SetNTSTATUS(status
);
292 TALLOC_FREE(tmp_ctx
);
296 talloc_free(tmp_ctx
);
297 result
= Py_BuildValue("[s,i]", display_name
, sysvol_version
);
301 static ADS_STATUS
find_samaccount(ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
,
302 const char *samaccountname
,
303 uint32_t *uac_ret
, const char **dn_ret
)
306 const char *attrs
[] = { "userAccountControl", NULL
};
308 LDAPMessage
*res
= NULL
;
312 filter
= talloc_asprintf(mem_ctx
, "(sAMAccountName=%s)", samaccountname
);
313 if (filter
== NULL
) {
314 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
318 status
= ads_do_search_all(ads
, ads
->config
.bind_path
, LDAP_SCOPE_SUBTREE
,
319 filter
, attrs
, &res
);
321 if (!ADS_ERR_OK(status
)) {
325 if (ads_count_replies(ads
, res
) != 1) {
326 status
= ADS_ERROR(LDAP_NO_RESULTS_RETURNED
);
330 dn
= ads_get_dn(ads
, talloc_tos(), res
);
332 status
= ADS_ERROR(LDAP_NO_MEMORY
);
336 if (!ads_pull_uint32(ads
, res
, "userAccountControl", &uac
)) {
337 status
= ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE
);
346 *dn_ret
= talloc_strdup(mem_ctx
, dn
);
348 status
= ADS_ERROR(LDAP_NO_MEMORY
);
354 ads_msgfree(ads
, res
);
359 static PyObject
*py_ads_get_gpo_list(ADS
*self
, PyObject
*args
, PyObject
*kwds
)
361 TALLOC_CTX
*frame
= NULL
;
362 struct GROUP_POLICY_OBJECT
*gpo
= NULL
, *gpo_list
= NULL
;
364 const char *samaccountname
= NULL
;
365 const char *dn
= NULL
;
368 struct security_token
*token
= NULL
;
369 PyObject
*ret
= Py_None
;
374 static const char *kwlist
[] = {"samaccountname", NULL
};
375 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s",
376 discard_const_p(char *, kwlist
),
378 PyErr_SetString(PyExc_SystemError
,
379 "Failed to parse arguments to py_ads_get_gpo_list()");
383 frame
= talloc_stackframe();
385 status
= find_samaccount(self
->ads_ptr
, frame
, samaccountname
, &uac
, &dn
);
386 if (!ADS_ERR_OK(status
)) {
388 PyErr_SetString(PyExc_SystemError
, "Failed to find samAccountName");
392 if (uac
& UF_WORKSTATION_TRUST_ACCOUNT
|| uac
& UF_SERVER_TRUST_ACCOUNT
) {
393 flags
|= GPO_LIST_FLAG_MACHINE
;
394 status
= gp_get_machine_token(self
->ads_ptr
, frame
, dn
, &token
);
396 status
= ads_get_sid_token(self
->ads_ptr
, frame
, dn
, &token
);
398 if (!ADS_ERR_OK(status
)) {
400 PyErr_SetString(PyExc_SystemError
, "Failed to get token");
404 gpo_ctx
= talloc_new(frame
);
405 status
= ads_get_gpo_list(self
->ads_ptr
, gpo_ctx
, dn
, flags
, token
,
407 if (!ADS_ERR_OK(status
)) {
409 PyErr_SetString(PyExc_SystemError
, "Failed to fetch GPO list");
413 /* Convert the C linked list into a python list */
415 for (gpo
= gpo_list
; gpo
!= NULL
; gpo
= gpo
->next
) {
420 ret
= PyList_New(list_size
);
426 for (gpo
= gpo_list
; gpo
!= NULL
; gpo
= gpo
->next
) {
427 PyObject
*obj
= pytalloc_reference_ex(&GPOType
,
434 PyList_SetItem(ret
, i
, obj
);
444 static PyMethodDef ADS_methods
[] = {
445 { "connect", (PyCFunction
)py_ads_connect
, METH_NOARGS
,
446 "Connect to the LDAP server" },
447 { "get_gpo_list", (PyCFunction
)py_ads_get_gpo_list
, METH_KEYWORDS
, NULL
},
451 static PyTypeObject ads_ADSType
= {
452 .tp_name
= "gpo.ADS_STRUCT",
453 .tp_basicsize
= sizeof(ADS
),
454 .tp_dealloc
= (destructor
)py_ads_dealloc
,
455 .tp_flags
= Py_TPFLAGS_DEFAULT
,
456 .tp_doc
= "ADS struct",
457 .tp_methods
= ADS_methods
,
458 .tp_init
= (initproc
)py_ads_init
,
459 .tp_new
= py_ads_new
,
462 static PyMethodDef py_gpo_methods
[] = {
463 {"gpo_get_sysvol_gpt_version", (PyCFunction
) py_gpo_get_sysvol_gpt_version
,
468 /* Will be called by python when loading this module */
473 debug_setup_talloc_log();
474 /* Instantiate the types */
475 m
= Py_InitModule3("gpo", py_gpo_methods
, "libgpo python bindings");
476 if (m
== NULL
) return;
477 PyModule_AddObject(m
, "version",
478 PyString_FromString(SAMBA_VERSION_STRING
));
480 if (PyType_Ready(&ads_ADSType
) < 0)
482 PyModule_AddObject(m
, "ADS_STRUCT", (PyObject
*)&ads_ADSType
);
484 if (pytalloc_BaseObject_PyType_Ready(&GPOType
) < 0)
487 Py_INCREF((PyObject
*)(void *)&GPOType
);
488 PyModule_AddObject(m
, "GROUP_POLICY_OBJECT",
489 (PyObject
*)&GPOType
);