Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 :
5 : Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2010
6 : Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
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 "lib/replace/system/python.h"
23 : #include "python/py3compat.h"
24 : #include "includes.h"
25 : #include "python/modules.h"
26 : #include <pyldb.h>
27 : #include <pytalloc.h>
28 : #include "libnet.h"
29 : #include "auth/credentials/pycredentials.h"
30 : #include "libcli/security/security.h"
31 : #include "lib/events/events.h"
32 : #include "param/pyparam.h"
33 : #include "auth/gensec/gensec.h"
34 : #include "librpc/rpc/pyrpc_util.h"
35 : #include "libcli/resolve/resolve.h"
36 : #include "libcli/finddc.h"
37 : #include "dsdb/samdb/samdb.h"
38 : #include "py_net.h"
39 : #include "librpc/rpc/pyrpc_util.h"
40 : #include "libcli/drsuapi/drsuapi.h"
41 :
42 4 : static void PyErr_SetDsExtendedError(enum drsuapi_DsExtendedError ext_err, const char *error_description)
43 : {
44 4 : PyObject *mod = NULL;
45 4 : PyObject *error = NULL;
46 4 : mod = PyImport_ImportModule("samba");
47 4 : if (mod) {
48 4 : error = PyObject_GetAttrString(mod, "DsExtendedError");
49 : }
50 4 : if (error_description == NULL) {
51 4 : switch (ext_err) {
52 : /* Copied out of ndr_drsuapi.c:ndr_print_drsuapi_DsExtendedError() */
53 0 : case DRSUAPI_EXOP_ERR_NONE:
54 0 : error_description = "DRSUAPI_EXOP_ERR_NONE";
55 0 : break;
56 0 : case DRSUAPI_EXOP_ERR_SUCCESS:
57 0 : error_description = "DRSUAPI_EXOP_ERR_SUCCESS";
58 0 : break;
59 0 : case DRSUAPI_EXOP_ERR_UNKNOWN_OP:
60 0 : error_description = "DRSUAPI_EXOP_ERR_UNKNOWN_OP";
61 0 : break;
62 4 : case DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER:
63 4 : error_description = "DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER";
64 4 : break;
65 0 : case DRSUAPI_EXOP_ERR_UPDATE_ERR:
66 0 : error_description = "DRSUAPI_EXOP_ERR_UPDATE_ERR";
67 0 : break;
68 0 : case DRSUAPI_EXOP_ERR_EXCEPTION:
69 0 : error_description = "DRSUAPI_EXOP_ERR_EXCEPTION";
70 0 : break;
71 0 : case DRSUAPI_EXOP_ERR_UNKNOWN_CALLER:
72 0 : error_description = "DRSUAPI_EXOP_ERR_UNKNOWN_CALLER";
73 0 : break;
74 0 : case DRSUAPI_EXOP_ERR_RID_ALLOC:
75 0 : error_description = "DRSUAPI_EXOP_ERR_RID_ALLOC";
76 0 : break;
77 0 : case DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED:
78 0 : error_description = "DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED";
79 0 : break;
80 0 : case DRSUAPI_EXOP_ERR_FMSO_PENDING_OP:
81 0 : error_description = "DRSUAPI_EXOP_ERR_FMSO_PENDING_OP";
82 0 : break;
83 0 : case DRSUAPI_EXOP_ERR_MISMATCH:
84 0 : error_description = "DRSUAPI_EXOP_ERR_MISMATCH";
85 0 : break;
86 0 : case DRSUAPI_EXOP_ERR_COULDNT_CONTACT:
87 0 : error_description = "DRSUAPI_EXOP_ERR_COULDNT_CONTACT";
88 0 : break;
89 0 : case DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES:
90 0 : error_description = "DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES";
91 0 : break;
92 0 : case DRSUAPI_EXOP_ERR_DIR_ERROR:
93 0 : error_description = "DRSUAPI_EXOP_ERR_DIR_ERROR";
94 0 : break;
95 0 : case DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS:
96 0 : error_description = "DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS";
97 0 : break;
98 0 : case DRSUAPI_EXOP_ERR_ACCESS_DENIED:
99 0 : error_description = "DRSUAPI_EXOP_ERR_ACCESS_DENIED";
100 0 : break;
101 0 : case DRSUAPI_EXOP_ERR_PARAM_ERROR:
102 0 : error_description = "DRSUAPI_EXOP_ERR_PARAM_ERROR";
103 0 : break;
104 : }
105 : }
106 4 : if (error) {
107 0 : PyObject *value =
108 4 : Py_BuildValue(discard_const_p(char, "(i,s)"),
109 : ext_err,
110 : error_description);
111 4 : PyErr_SetObject(error, value);
112 4 : if (value) {
113 4 : Py_DECREF(value);
114 : }
115 4 : Py_DECREF(error);
116 : }
117 4 : }
118 :
119 13 : static PyObject *py_net_join_member(py_net_Object *self, PyObject *args, PyObject *kwargs)
120 : {
121 0 : struct libnet_Join_member r;
122 13 : int _level = 0;
123 0 : NTSTATUS status;
124 0 : PyObject *result;
125 0 : TALLOC_CTX *mem_ctx;
126 13 : const char *kwnames[] = { "domain_name", "netbios_name", "level", "machinepass", NULL };
127 :
128 13 : ZERO_STRUCT(r);
129 :
130 13 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssi|z:Join", discard_const_p(char *, kwnames),
131 : &r.in.domain_name, &r.in.netbios_name,
132 : &_level,
133 : &r.in.account_pass)) {
134 0 : return NULL;
135 : }
136 13 : r.in.level = _level;
137 :
138 13 : mem_ctx = talloc_new(self->mem_ctx);
139 13 : if (mem_ctx == NULL) {
140 0 : PyErr_NoMemory();
141 0 : return NULL;
142 : }
143 :
144 13 : status = libnet_Join_member(self->libnet_ctx, mem_ctx, &r);
145 13 : if (NT_STATUS_IS_ERR(status)) {
146 2 : PyErr_SetNTSTATUS_and_string(status,
147 : r.out.error_string
148 : ? r.out.error_string
149 : : nt_errstr(status));
150 2 : talloc_free(mem_ctx);
151 2 : return NULL;
152 : }
153 :
154 11 : result = Py_BuildValue("sss", r.out.join_password,
155 11 : dom_sid_string(mem_ctx, r.out.domain_sid),
156 : r.out.domain_name);
157 :
158 11 : talloc_free(mem_ctx);
159 :
160 11 : return result;
161 : }
162 :
163 : static const char py_net_join_member_doc[] = "join_member(domain_name, netbios_name, level) -> (join_password, domain_sid, domain_name)\n\n" \
164 : "Join the domain with the specified name.";
165 :
166 54 : static PyObject *py_net_change_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
167 : {
168 0 : union libnet_ChangePassword r;
169 0 : NTSTATUS status;
170 54 : TALLOC_CTX *mem_ctx = NULL;
171 54 : struct tevent_context *ev = NULL;
172 54 : const char *kwnames[] = { "newpassword", "oldpassword", "domain", "username", NULL };
173 54 : const char *newpass = NULL;
174 54 : const char *oldpass = NULL;
175 54 : ZERO_STRUCT(r);
176 54 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, PYARG_STR_UNI
177 : "|"PYARG_STR_UNI"ss:change_password",
178 : discard_const_p(char *, kwnames),
179 : "utf8",
180 : &newpass,
181 : "utf8",
182 : &oldpass,
183 : &r.generic.in.domain_name,
184 : &r.generic.in.account_name)) {
185 0 : return NULL;
186 : }
187 :
188 54 : r.generic.in.newpassword = newpass;
189 54 : r.generic.in.oldpassword = oldpass;
190 :
191 54 : r.generic.level = LIBNET_CHANGE_PASSWORD_GENERIC;
192 54 : if (r.generic.in.account_name == NULL) {
193 0 : r.generic.in.account_name
194 28 : = cli_credentials_get_username(self->libnet_ctx->cred);
195 : }
196 54 : if (r.generic.in.domain_name == NULL) {
197 0 : r.generic.in.domain_name
198 54 : = cli_credentials_get_domain(self->libnet_ctx->cred);
199 : }
200 54 : if (r.generic.in.oldpassword == NULL) {
201 0 : r.generic.in.oldpassword
202 28 : = cli_credentials_get_password(self->libnet_ctx->cred);
203 : }
204 :
205 : /* FIXME: we really need to get a context from the caller or we may end
206 : * up with 2 event contexts */
207 54 : ev = s4_event_context_init(NULL);
208 :
209 54 : mem_ctx = talloc_new(ev);
210 54 : if (mem_ctx == NULL) {
211 0 : PyMem_Free(discard_const_p(char, newpass));
212 0 : PyMem_Free(discard_const_p(char, oldpass));
213 0 : PyErr_NoMemory();
214 0 : return NULL;
215 : }
216 :
217 54 : status = libnet_ChangePassword(self->libnet_ctx, mem_ctx, &r);
218 :
219 54 : PyMem_Free(discard_const_p(char, newpass));
220 54 : PyMem_Free(discard_const_p(char, oldpass));
221 :
222 54 : if (NT_STATUS_IS_ERR(status)) {
223 24 : PyErr_SetNTSTATUS_and_string(status,
224 : r.generic.out.error_string
225 : ? r.generic.out.error_string
226 : : nt_errstr(status));
227 24 : talloc_free(mem_ctx);
228 24 : return NULL;
229 : }
230 :
231 30 : talloc_free(mem_ctx);
232 30 : Py_RETURN_NONE;
233 : }
234 :
235 : static const char py_net_change_password_doc[] = "change_password(newpassword) -> True\n\n" \
236 : "Change password for a user. You must supply credential with enough rights to do this.\n\n" \
237 : "Sample usage is:\n" \
238 : "net.change_password(newpassword=<new_password>)\n";
239 :
240 :
241 119 : static PyObject *py_net_set_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
242 : {
243 0 : union libnet_SetPassword r;
244 0 : NTSTATUS status;
245 0 : TALLOC_CTX *mem_ctx;
246 0 : struct tevent_context *ev;
247 119 : const char *kwnames[] = { "account_name", "domain_name", "newpassword", "force_samr_18", NULL };
248 119 : PyObject *py_force_samr_18 = Py_False;
249 :
250 119 : ZERO_STRUCT(r);
251 :
252 119 : r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
253 :
254 119 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|O:set_password",
255 : discard_const_p(char *, kwnames),
256 : &r.generic.in.account_name,
257 : &r.generic.in.domain_name,
258 : &r.generic.in.newpassword,
259 : &py_force_samr_18)) {
260 0 : return NULL;
261 : }
262 :
263 119 : if (py_force_samr_18) {
264 119 : if (!PyBool_Check(py_force_samr_18)) {
265 0 : PyErr_SetString(PyExc_TypeError, "Expected boolean force_samr_18");
266 0 : return NULL;
267 : }
268 119 : if (py_force_samr_18 == Py_True) {
269 114 : r.generic.samr_level = LIBNET_SET_PASSWORD_SAMR_HANDLE_18;
270 : }
271 : }
272 :
273 : /* FIXME: we really need to get a context from the caller or we may end
274 : * up with 2 event contexts */
275 119 : ev = s4_event_context_init(NULL);
276 :
277 119 : mem_ctx = talloc_new(ev);
278 119 : if (mem_ctx == NULL) {
279 0 : PyErr_NoMemory();
280 0 : return NULL;
281 : }
282 :
283 119 : status = libnet_SetPassword(self->libnet_ctx, mem_ctx, &r);
284 119 : if (NT_STATUS_IS_ERR(status)) {
285 1 : PyErr_SetNTSTATUS_and_string(status,
286 : r.generic.out.error_string
287 : ? r.generic.out.error_string
288 : : nt_errstr(status));
289 1 : talloc_free(mem_ctx);
290 1 : return NULL;
291 : }
292 :
293 118 : talloc_free(mem_ctx);
294 :
295 118 : Py_RETURN_NONE;
296 : }
297 :
298 : static const char py_net_set_password_doc[] = "set_password(account_name, domain_name, newpassword) -> True\n\n" \
299 : "Set password for a user. You must supply credential with enough rights to do this.\n\n" \
300 : "Sample usage is:\n" \
301 : "net.set_password(account_name=account_name, domain_name=domain_name, newpassword=new_pass)\n";
302 :
303 :
304 15 : static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
305 : {
306 15 : const char *kwnames[] = { "server_name", NULL };
307 0 : union libnet_RemoteTOD r;
308 0 : NTSTATUS status;
309 0 : TALLOC_CTX *mem_ctx;
310 0 : char timestr[64];
311 0 : PyObject *ret;
312 0 : struct tm *tm;
313 0 : size_t len;
314 :
315 15 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
316 : discard_const_p(char *, kwnames), &r.generic.in.server_name))
317 0 : return NULL;
318 :
319 15 : r.generic.level = LIBNET_REMOTE_TOD_GENERIC;
320 :
321 15 : mem_ctx = talloc_new(NULL);
322 15 : if (mem_ctx == NULL) {
323 0 : PyErr_NoMemory();
324 0 : return NULL;
325 : }
326 :
327 15 : status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
328 15 : if (!NT_STATUS_IS_OK(status)) {
329 1 : PyErr_SetNTSTATUS_and_string(status,
330 : r.generic.out.error_string
331 : ? r.generic.out.error_string
332 : : nt_errstr(status));
333 1 : talloc_free(mem_ctx);
334 1 : return NULL;
335 : }
336 :
337 14 : ZERO_STRUCT(timestr);
338 14 : tm = localtime(&r.generic.out.time);
339 :
340 14 : len = strftime(timestr, sizeof(timestr), "%c %Z", tm);
341 14 : if (len == 0) {
342 0 : PyErr_NoMemory();
343 0 : ret = NULL;
344 : } else {
345 14 : ret = PyUnicode_FromStringAndSize(timestr, (Py_ssize_t)len);
346 : }
347 :
348 14 : talloc_free(mem_ctx);
349 14 : return ret;
350 : }
351 :
352 : static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
353 : "Retrieve the remote time on a server";
354 :
355 0 : static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
356 : {
357 0 : const char *kwnames[] = { "username", NULL };
358 0 : NTSTATUS status;
359 0 : TALLOC_CTX *mem_ctx;
360 0 : struct libnet_CreateUser r;
361 :
362 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
363 : &r.in.user_name))
364 0 : return NULL;
365 :
366 0 : r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
367 :
368 0 : mem_ctx = talloc_new(NULL);
369 0 : if (mem_ctx == NULL) {
370 0 : PyErr_NoMemory();
371 0 : return NULL;
372 : }
373 :
374 0 : status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
375 0 : if (!NT_STATUS_IS_OK(status)) {
376 0 : PyErr_SetNTSTATUS_and_string(status,
377 : r.out.error_string
378 : ? r.out.error_string
379 : : nt_errstr(status));
380 0 : talloc_free(mem_ctx);
381 0 : return NULL;
382 : }
383 :
384 0 : talloc_free(mem_ctx);
385 :
386 0 : Py_RETURN_NONE;
387 : }
388 :
389 : static const char py_net_create_user_doc[] = "create_user(username)\n"
390 : "Create a new user.";
391 :
392 0 : static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
393 : {
394 0 : const char *kwnames[] = { "username", NULL };
395 0 : NTSTATUS status;
396 0 : TALLOC_CTX *mem_ctx;
397 0 : struct libnet_DeleteUser r;
398 :
399 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
400 : &r.in.user_name))
401 0 : return NULL;
402 :
403 0 : r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
404 :
405 0 : mem_ctx = talloc_new(NULL);
406 0 : if (mem_ctx == NULL) {
407 0 : PyErr_NoMemory();
408 0 : return NULL;
409 : }
410 :
411 0 : status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
412 0 : if (!NT_STATUS_IS_OK(status)) {
413 0 : PyErr_SetNTSTATUS_and_string(status,
414 : r.out.error_string
415 : ? r.out.error_string
416 : : nt_errstr(status));
417 0 : talloc_free(mem_ctx);
418 0 : return NULL;
419 : }
420 :
421 0 : talloc_free(mem_ctx);
422 :
423 0 : Py_RETURN_NONE;
424 : }
425 :
426 : static const char py_net_delete_user_doc[] = "delete_user(username)\n"
427 : "Delete a user.";
428 :
429 : struct replicate_state {
430 : void *vampire_state;
431 : dcerpc_InterfaceObject *drs_pipe;
432 : struct libnet_BecomeDC_StoreChunk chunk;
433 : DATA_BLOB gensec_skey;
434 : struct libnet_BecomeDC_Partition partition;
435 : struct libnet_BecomeDC_Forest forest;
436 : struct libnet_BecomeDC_DestDSA dest_dsa;
437 : };
438 :
439 : /*
440 : setup for replicate_chunk() calls
441 : */
442 130 : static PyObject *py_net_replicate_init(py_net_Object *self, PyObject *args, PyObject *kwargs)
443 : {
444 130 : const char *kwnames[] = { "samdb", "lp", "drspipe", "invocation_id", NULL };
445 0 : PyObject *py_ldb, *py_lp, *py_drspipe, *py_invocation_id;
446 0 : struct ldb_context *samdb;
447 0 : struct loadparm_context *lp;
448 0 : struct replicate_state *s;
449 0 : NTSTATUS status;
450 :
451 130 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO",
452 : discard_const_p(char *, kwnames),
453 : &py_ldb, &py_lp, &py_drspipe,
454 : &py_invocation_id)) {
455 0 : return NULL;
456 : }
457 :
458 130 : s = talloc_zero(NULL, struct replicate_state);
459 130 : if (!s) return NULL;
460 :
461 130 : lp = lpcfg_from_py_object(s, py_lp);
462 130 : if (lp == NULL) {
463 0 : PyErr_SetString(PyExc_TypeError, "Expected lp object");
464 0 : talloc_free(s);
465 0 : return NULL;
466 : }
467 :
468 130 : samdb = pyldb_Ldb_AsLdbContext(py_ldb);
469 130 : if (samdb == NULL) {
470 0 : PyErr_SetString(PyExc_TypeError, "Expected ldb object");
471 0 : talloc_free(s);
472 0 : return NULL;
473 : }
474 130 : if (!py_check_dcerpc_type(py_invocation_id, "samba.dcerpc.misc", "GUID")) {
475 :
476 0 : talloc_free(s);
477 0 : return NULL;
478 : }
479 130 : s->dest_dsa.invocation_id = *pytalloc_get_type(py_invocation_id, struct GUID);
480 :
481 130 : s->drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);
482 :
483 130 : s->vampire_state = libnet_vampire_replicate_init(s, samdb, lp);
484 130 : if (s->vampire_state == NULL) {
485 0 : PyErr_SetString(PyExc_TypeError, "Failed to initialise vampire_state");
486 0 : talloc_free(s);
487 0 : return NULL;
488 : }
489 :
490 130 : status = gensec_session_key(s->drs_pipe->pipe->conn->security_state.generic_state,
491 : s,
492 : &s->gensec_skey);
493 130 : if (!NT_STATUS_IS_OK(status)) {
494 0 : char *error_string = talloc_asprintf(s,
495 : "Unable to get session key from drspipe: %s",
496 : nt_errstr(status));
497 0 : PyErr_SetNTSTATUS_and_string(status, error_string);
498 0 : talloc_free(s);
499 0 : return NULL;
500 : }
501 :
502 130 : s->forest.dns_name = samdb_dn_to_dns_domain(s, ldb_get_root_basedn(samdb));
503 130 : s->forest.root_dn_str = ldb_dn_get_linearized(ldb_get_root_basedn(samdb));
504 130 : s->forest.config_dn_str = ldb_dn_get_linearized(ldb_get_config_basedn(samdb));
505 130 : s->forest.schema_dn_str = ldb_dn_get_linearized(ldb_get_schema_basedn(samdb));
506 :
507 130 : s->chunk.gensec_skey = &s->gensec_skey;
508 130 : s->chunk.partition = &s->partition;
509 130 : s->chunk.forest = &s->forest;
510 130 : s->chunk.dest_dsa = &s->dest_dsa;
511 :
512 130 : return pytalloc_GenericObject_steal(s);
513 : }
514 :
515 :
516 : /*
517 : process one replication chunk
518 : */
519 1704 : static PyObject *py_net_replicate_chunk(py_net_Object *self, PyObject *args, PyObject *kwargs)
520 : {
521 1704 : const char *kwnames[] = { "state", "level", "ctr",
522 : "schema", "req_level", "req",
523 : NULL };
524 1704 : PyObject *py_state, *py_ctr, *py_schema = Py_None, *py_req = Py_None;
525 0 : struct replicate_state *s;
526 0 : unsigned level;
527 1704 : unsigned req_level = 0;
528 0 : WERROR (*chunk_handler)(void *private_data, const struct libnet_BecomeDC_StoreChunk *c);
529 0 : WERROR werr;
530 1704 : enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
531 1704 : enum drsuapi_DsExtendedOperation exop = DRSUAPI_EXOP_NONE;
532 :
533 1704 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OIO|OIO",
534 : discard_const_p(char *, kwnames),
535 : &py_state, &level, &py_ctr,
536 : &py_schema, &req_level, &py_req)) {
537 0 : return NULL;
538 : }
539 :
540 1704 : s = pytalloc_get_type(py_state, struct replicate_state);
541 1704 : if (!s) {
542 0 : return NULL;
543 : }
544 :
545 1704 : switch (level) {
546 0 : case 1:
547 0 : if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr1")) {
548 0 : return NULL;
549 : }
550 0 : s->chunk.ctr1 = pytalloc_get_ptr(py_ctr);
551 0 : if (s->chunk.ctr1->naming_context != NULL) {
552 0 : s->partition.nc = *s->chunk.ctr1->naming_context;
553 : }
554 0 : extended_ret = s->chunk.ctr1->extended_ret;
555 0 : s->partition.more_data = s->chunk.ctr1->more_data;
556 0 : s->partition.source_dsa_guid = s->chunk.ctr1->source_dsa_guid;
557 0 : s->partition.source_dsa_invocation_id = s->chunk.ctr1->source_dsa_invocation_id;
558 0 : s->partition.highwatermark = s->chunk.ctr1->new_highwatermark;
559 0 : break;
560 1704 : case 6:
561 1704 : if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr6")) {
562 0 : return NULL;
563 : }
564 1704 : s->chunk.ctr6 = pytalloc_get_ptr(py_ctr);
565 1704 : if (s->chunk.ctr6->naming_context != NULL) {
566 1700 : s->partition.nc = *s->chunk.ctr6->naming_context;
567 : }
568 1704 : extended_ret = s->chunk.ctr6->extended_ret;
569 1704 : s->partition.more_data = s->chunk.ctr6->more_data;
570 1704 : s->partition.source_dsa_guid = s->chunk.ctr6->source_dsa_guid;
571 1704 : s->partition.source_dsa_invocation_id = s->chunk.ctr6->source_dsa_invocation_id;
572 1704 : s->partition.highwatermark = s->chunk.ctr6->new_highwatermark;
573 1704 : break;
574 0 : default:
575 0 : PyErr_Format(PyExc_TypeError, "Bad level %u in replicate_chunk", level);
576 0 : return NULL;
577 : }
578 :
579 1704 : s->chunk.req5 = NULL;
580 1704 : s->chunk.req8 = NULL;
581 1704 : s->chunk.req10 = NULL;
582 1704 : if (py_req != Py_None) {
583 1704 : switch (req_level) {
584 0 : case 0:
585 0 : break;
586 0 : case 5:
587 0 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest5")) {
588 0 : return NULL;
589 : }
590 :
591 0 : s->chunk.req5 = pytalloc_get_ptr(py_req);
592 0 : exop = s->chunk.req5->extended_op;
593 0 : break;
594 0 : case 8:
595 0 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest8")) {
596 0 : return NULL;
597 : }
598 :
599 0 : s->chunk.req8 = pytalloc_get_ptr(py_req);
600 0 : exop = s->chunk.req8->extended_op;
601 0 : break;
602 1704 : case 10:
603 1704 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest10")) {
604 0 : return NULL;
605 : }
606 :
607 1704 : s->chunk.req10 = pytalloc_get_ptr(py_req);
608 1704 : exop = s->chunk.req10->extended_op;
609 1704 : break;
610 0 : default:
611 0 : PyErr_Format(PyExc_TypeError, "Bad req_level %u in replicate_chunk", req_level);
612 0 : return NULL;
613 : }
614 : }
615 :
616 1704 : if (exop != DRSUAPI_EXOP_NONE && extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
617 4 : PyErr_SetDsExtendedError(extended_ret, NULL);
618 4 : return NULL;
619 : }
620 :
621 1700 : s->chunk.req_level = req_level;
622 :
623 1700 : chunk_handler = libnet_vampire_cb_store_chunk;
624 1700 : if (py_schema) {
625 1700 : if (!PyBool_Check(py_schema)) {
626 0 : PyErr_SetString(PyExc_TypeError, "Expected boolean schema");
627 0 : return NULL;
628 : }
629 1700 : if (py_schema == Py_True) {
630 344 : chunk_handler = libnet_vampire_cb_schema_chunk;
631 : }
632 : }
633 :
634 1700 : s->chunk.ctr_level = level;
635 :
636 1700 : werr = chunk_handler(s->vampire_state, &s->chunk);
637 1700 : if (!W_ERROR_IS_OK(werr)) {
638 0 : char *error_string
639 29 : = talloc_asprintf(NULL,
640 : "Failed to process 'chunk' of DRS replicated objects: %s",
641 : win_errstr(werr));
642 29 : PyErr_SetWERROR_and_string(werr, error_string);
643 29 : TALLOC_FREE(error_string);
644 29 : return NULL;
645 : }
646 :
647 1671 : Py_RETURN_NONE;
648 : }
649 :
650 :
651 : /*
652 : just do the decryption of a DRS replicated attribute
653 : */
654 5756 : static PyObject *py_net_replicate_decrypt(py_net_Object *self, PyObject *args, PyObject *kwargs)
655 : {
656 5756 : const char *kwnames[] = { "drspipe", "attribute", "rid", NULL };
657 0 : PyObject *py_drspipe, *py_attribute;
658 0 : NTSTATUS status;
659 0 : dcerpc_InterfaceObject *drs_pipe;
660 0 : TALLOC_CTX *frame;
661 0 : TALLOC_CTX *context;
662 0 : DATA_BLOB gensec_skey;
663 0 : unsigned int rid;
664 0 : struct drsuapi_DsReplicaAttribute *attribute;
665 0 : WERROR werr;
666 :
667 5756 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOI",
668 : discard_const_p(char *, kwnames),
669 : &py_drspipe,
670 : &py_attribute, &rid)) {
671 0 : return NULL;
672 : }
673 :
674 5756 : frame = talloc_stackframe();
675 :
676 5756 : if (!py_check_dcerpc_type(py_drspipe,
677 : "samba.dcerpc.base",
678 : "ClientConnection")) {
679 0 : return NULL;
680 : }
681 5756 : drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);
682 :
683 5756 : status = gensec_session_key(drs_pipe->pipe->conn->security_state.generic_state,
684 : frame,
685 : &gensec_skey);
686 5756 : if (!NT_STATUS_IS_OK(status)) {
687 0 : char *error_string
688 0 : = talloc_asprintf(frame,
689 : "Unable to get session key from drspipe: %s",
690 : nt_errstr(status));
691 0 : PyErr_SetNTSTATUS_and_string(status, error_string);
692 0 : talloc_free(frame);
693 0 : return NULL;
694 : }
695 :
696 5756 : if (!py_check_dcerpc_type(py_attribute, "samba.dcerpc.drsuapi",
697 : "DsReplicaAttribute")) {
698 0 : return NULL;
699 : }
700 :
701 5756 : attribute = pytalloc_get_ptr(py_attribute);
702 5756 : context = pytalloc_get_mem_ctx(py_attribute);
703 5756 : werr = drsuapi_decrypt_attribute(context, &gensec_skey,
704 : rid, 0, attribute);
705 5756 : if (!W_ERROR_IS_OK(werr)) {
706 0 : char *error_string = talloc_asprintf(frame,
707 : "Unable to get decrypt attribute: %s",
708 : win_errstr(werr));
709 0 : PyErr_SetWERROR_and_string(werr, error_string);
710 0 : talloc_free(frame);
711 0 : return NULL;
712 : }
713 :
714 5756 : talloc_free(frame);
715 :
716 5756 : Py_RETURN_NONE;
717 :
718 : }
719 :
720 : /*
721 : find a DC given a domain name and server type
722 : */
723 491 : static PyObject *py_net_finddc(py_net_Object *self, PyObject *args, PyObject *kwargs)
724 : {
725 491 : const char *domain = NULL, *address = NULL;
726 0 : unsigned server_type;
727 0 : NTSTATUS status;
728 0 : struct finddcs *io;
729 0 : TALLOC_CTX *mem_ctx;
730 0 : PyObject *ret;
731 491 : const char * const kwnames[] = { "flags", "domain", "address", NULL };
732 :
733 491 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I|zz",
734 : discard_const_p(char *, kwnames),
735 : &server_type, &domain, &address)) {
736 0 : return NULL;
737 : }
738 :
739 491 : mem_ctx = talloc_new(self->mem_ctx);
740 491 : if (mem_ctx == NULL) {
741 0 : PyErr_NoMemory();
742 0 : return NULL;
743 : }
744 :
745 491 : io = talloc_zero(mem_ctx, struct finddcs);
746 491 : if (io == NULL) {
747 0 : TALLOC_FREE(mem_ctx);
748 0 : PyErr_NoMemory();
749 0 : return NULL;
750 : }
751 :
752 491 : if (domain != NULL) {
753 182 : io->in.domain_name = domain;
754 : }
755 491 : if (address != NULL) {
756 317 : io->in.server_address = address;
757 : }
758 491 : io->in.minimum_dc_flags = server_type;
759 :
760 491 : status = finddcs_cldap(io, io,
761 491 : lpcfg_resolve_context(self->libnet_ctx->lp_ctx), self->ev);
762 491 : if (NT_STATUS_IS_ERR(status)) {
763 0 : PyErr_SetNTSTATUS(status);
764 0 : talloc_free(mem_ctx);
765 0 : return NULL;
766 : }
767 :
768 491 : ret = py_return_ndr_struct("samba.dcerpc.nbt", "NETLOGON_SAM_LOGON_RESPONSE_EX",
769 491 : io, &io->out.netlogon.data.nt5_ex);
770 491 : talloc_free(mem_ctx);
771 :
772 491 : return ret;
773 : }
774 :
775 :
776 : static const char py_net_replicate_init_doc[] = "replicate_init(samdb, lp, drspipe)\n"
777 : "Setup for replicate_chunk calls.";
778 :
779 : static const char py_net_replicate_chunk_doc[] = "replicate_chunk(state, level, ctr, schema)\n"
780 : "Process replication for one chunk";
781 :
782 : static const char py_net_replicate_decrypt_doc[] = "replicate_decrypt(drs, attribute, rid)\n"
783 : "Decrypt (in place) a DsReplicaAttribute replicated with drs.GetNCChanges()";
784 :
785 : static const char py_net_finddc_doc[] = "finddc(flags=server_type, domain=None, address=None)\n"
786 : "Find a DC with the specified 'server_type' bits. The 'domain' and/or 'address' have to be used as additional search criteria. Returns the whole netlogon struct";
787 :
788 : static PyMethodDef net_obj_methods[] = {
789 : {
790 : .ml_name = "join_member",
791 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
792 : py_net_join_member),
793 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
794 : .ml_doc = py_net_join_member_doc
795 : },
796 : {
797 : .ml_name = "change_password",
798 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
799 : py_net_change_password),
800 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
801 : .ml_doc = py_net_change_password_doc
802 : },
803 : {
804 : .ml_name = "set_password",
805 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
806 : py_net_set_password),
807 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
808 : .ml_doc = py_net_set_password_doc
809 : },
810 : {
811 : .ml_name = "time",
812 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, py_net_time),
813 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
814 : .ml_doc = py_net_time_doc
815 : },
816 : {
817 : .ml_name = "create_user",
818 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
819 : py_net_user_create),
820 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
821 : .ml_doc = py_net_create_user_doc
822 : },
823 : {
824 : .ml_name = "delete_user",
825 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
826 : py_net_user_delete),
827 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
828 : .ml_doc = py_net_delete_user_doc
829 : },
830 : {
831 : .ml_name = "replicate_init",
832 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
833 : py_net_replicate_init),
834 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
835 : .ml_doc = py_net_replicate_init_doc
836 : },
837 : {
838 : .ml_name = "replicate_chunk",
839 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
840 : py_net_replicate_chunk),
841 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
842 : .ml_doc = py_net_replicate_chunk_doc
843 : },
844 : {
845 : .ml_name = "replicate_decrypt",
846 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
847 : py_net_replicate_decrypt),
848 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
849 : .ml_doc = py_net_replicate_decrypt_doc
850 : },
851 : {
852 : .ml_name = "finddc",
853 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
854 : py_net_finddc),
855 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
856 : .ml_doc = py_net_finddc_doc
857 : },
858 : { .ml_name = NULL }
859 : };
860 :
861 3951 : static void py_net_dealloc(py_net_Object *self)
862 : {
863 3951 : talloc_free(self->ev);
864 3951 : PyObject_Del(self);
865 3951 : }
866 :
867 3951 : static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
868 : {
869 3951 : PyObject *py_creds, *py_lp = Py_None;
870 3951 : const char *kwnames[] = { "creds", "lp", "server", NULL };
871 0 : py_net_Object *ret;
872 0 : struct loadparm_context *lp;
873 3951 : const char *server_address = NULL;
874 :
875 3951 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oz",
876 : discard_const_p(char *, kwnames), &py_creds, &py_lp,
877 : &server_address))
878 0 : return NULL;
879 :
880 3951 : ret = PyObject_New(py_net_Object, type);
881 3951 : if (ret == NULL) {
882 0 : return NULL;
883 : }
884 :
885 : /* FIXME: we really need to get a context from the caller or we may end
886 : * up with 2 event contexts */
887 3951 : ret->ev = s4_event_context_init(NULL);
888 3951 : ret->mem_ctx = talloc_new(ret->ev);
889 :
890 3951 : lp = lpcfg_from_py_object(ret->mem_ctx, py_lp);
891 3951 : if (lp == NULL) {
892 0 : Py_DECREF(ret);
893 0 : return NULL;
894 : }
895 :
896 3951 : ret->libnet_ctx = libnet_context_init(ret->ev, lp);
897 3951 : if (ret->libnet_ctx == NULL) {
898 0 : PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
899 0 : Py_DECREF(ret);
900 0 : return NULL;
901 : }
902 :
903 3951 : ret->libnet_ctx->server_address = server_address;
904 :
905 3951 : ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
906 3951 : if (ret->libnet_ctx->cred == NULL) {
907 0 : PyErr_SetString(PyExc_TypeError, "Expected credentials object");
908 0 : Py_DECREF(ret);
909 0 : return NULL;
910 : }
911 :
912 3951 : return (PyObject *)ret;
913 : }
914 :
915 :
916 : PyTypeObject py_net_Type = {
917 : PyVarObject_HEAD_INIT(NULL, 0)
918 : .tp_name = "net.Net",
919 : .tp_basicsize = sizeof(py_net_Object),
920 : .tp_dealloc = (destructor)py_net_dealloc,
921 : .tp_methods = net_obj_methods,
922 : .tp_new = net_obj_new,
923 : };
924 :
925 : static struct PyModuleDef moduledef = {
926 : PyModuleDef_HEAD_INIT,
927 : .m_name = "net",
928 : .m_size = -1,
929 : };
930 :
931 4526 : MODULE_INIT_FUNC(net)
932 : {
933 130 : PyObject *m;
934 :
935 4526 : if (PyType_Ready(&py_net_Type) < 0)
936 0 : return NULL;
937 :
938 4526 : m = PyModule_Create(&moduledef);
939 4526 : if (m == NULL)
940 0 : return NULL;
941 :
942 3495 : Py_INCREF(&py_net_Type);
943 4526 : PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
944 4526 : PyModule_AddIntConstant(m, "LIBNET_JOINDOMAIN_AUTOMATIC", LIBNET_JOINDOMAIN_AUTOMATIC);
945 4526 : PyModule_AddIntConstant(m, "LIBNET_JOINDOMAIN_SPECIFIED", LIBNET_JOINDOMAIN_SPECIFIED);
946 4526 : PyModule_AddIntConstant(m, "LIBNET_JOIN_AUTOMATIC", LIBNET_JOIN_AUTOMATIC);
947 4526 : PyModule_AddIntConstant(m, "LIBNET_JOIN_SPECIFIED", LIBNET_JOIN_SPECIFIED);
948 :
949 4526 : return m;
950 : }
|