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 <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 4 : PyObject *value =
108 0 : 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 7 : static PyObject *py_net_join_member(py_net_Object *self, PyObject *args, PyObject *kwargs)
120 : {
121 : struct libnet_Join_member r;
122 7 : int _level = 0;
123 : NTSTATUS status;
124 : PyObject *result;
125 : TALLOC_CTX *mem_ctx;
126 7 : const char *kwnames[] = { "domain_name", "netbios_name", "level", "machinepass", NULL };
127 :
128 7 : ZERO_STRUCT(r);
129 :
130 7 : 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 7 : r.in.level = _level;
137 :
138 7 : mem_ctx = talloc_new(self->mem_ctx);
139 7 : if (mem_ctx == NULL) {
140 0 : PyErr_NoMemory();
141 0 : return NULL;
142 : }
143 :
144 7 : status = libnet_Join_member(self->libnet_ctx, mem_ctx, &r);
145 7 : if (NT_STATUS_IS_ERR(status)) {
146 0 : PyErr_SetNTSTATUS_and_string(status,
147 : r.out.error_string
148 : ? r.out.error_string
149 : : nt_errstr(status));
150 0 : talloc_free(mem_ctx);
151 0 : return NULL;
152 : }
153 :
154 11 : result = Py_BuildValue("sss", r.out.join_password,
155 7 : dom_sid_string(mem_ctx, r.out.domain_sid),
156 : r.out.domain_name);
157 :
158 7 : talloc_free(mem_ctx);
159 :
160 7 : 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 38 : static PyObject *py_net_change_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
167 : {
168 : union libnet_ChangePassword r;
169 : NTSTATUS status;
170 38 : TALLOC_CTX *mem_ctx = NULL;
171 38 : struct tevent_context *ev = NULL;
172 38 : const char *kwnames[] = { "newpassword", "oldpassword", "domain", "username", NULL };
173 38 : const char *newpass = NULL;
174 38 : const char *oldpass = NULL;
175 38 : ZERO_STRUCT(r);
176 38 : 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 38 : r.generic.in.newpassword = newpass;
189 38 : r.generic.in.oldpassword = oldpass;
190 :
191 38 : r.generic.level = LIBNET_CHANGE_PASSWORD_GENERIC;
192 38 : if (r.generic.in.account_name == NULL) {
193 : r.generic.in.account_name
194 18 : = cli_credentials_get_username(self->libnet_ctx->cred);
195 : }
196 38 : if (r.generic.in.domain_name == NULL) {
197 : r.generic.in.domain_name
198 38 : = cli_credentials_get_domain(self->libnet_ctx->cred);
199 : }
200 38 : if (r.generic.in.oldpassword == NULL) {
201 : r.generic.in.oldpassword
202 18 : = 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 38 : ev = s4_event_context_init(NULL);
208 :
209 38 : mem_ctx = talloc_new(ev);
210 38 : 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 38 : status = libnet_ChangePassword(self->libnet_ctx, mem_ctx, &r);
218 :
219 38 : PyMem_Free(discard_const_p(char, newpass));
220 38 : PyMem_Free(discard_const_p(char, oldpass));
221 :
222 38 : if (NT_STATUS_IS_ERR(status)) {
223 18 : PyErr_SetNTSTATUS_and_string(status,
224 : r.generic.out.error_string
225 : ? r.generic.out.error_string
226 : : nt_errstr(status));
227 18 : talloc_free(mem_ctx);
228 18 : return NULL;
229 : }
230 :
231 20 : talloc_free(mem_ctx);
232 20 : 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 40 : static PyObject *py_net_set_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
242 : {
243 : union libnet_SetPassword r;
244 : NTSTATUS status;
245 : TALLOC_CTX *mem_ctx;
246 : struct tevent_context *ev;
247 40 : const char *kwnames[] = { "account_name", "domain_name", "newpassword", "force_samr_18", NULL };
248 40 : PyObject *py_force_samr_18 = Py_False;
249 :
250 40 : ZERO_STRUCT(r);
251 :
252 40 : r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
253 :
254 40 : 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 40 : if (py_force_samr_18) {
264 40 : if (!PyBool_Check(py_force_samr_18)) {
265 0 : PyErr_SetString(PyExc_TypeError, "Expected boolean force_samr_18");
266 0 : return NULL;
267 : }
268 40 : if (py_force_samr_18 == Py_True) {
269 38 : 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 40 : ev = s4_event_context_init(NULL);
276 :
277 40 : mem_ctx = talloc_new(ev);
278 40 : if (mem_ctx == NULL) {
279 0 : PyErr_NoMemory();
280 0 : return NULL;
281 : }
282 :
283 40 : status = libnet_SetPassword(self->libnet_ctx, mem_ctx, &r);
284 40 : if (NT_STATUS_IS_ERR(status)) {
285 0 : PyErr_SetNTSTATUS_and_string(status,
286 : r.generic.out.error_string
287 : ? r.generic.out.error_string
288 : : nt_errstr(status));
289 0 : talloc_free(mem_ctx);
290 0 : return NULL;
291 : }
292 :
293 40 : talloc_free(mem_ctx);
294 :
295 40 : 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 14 : static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
305 : {
306 14 : const char *kwnames[] = { "server_name", NULL };
307 : union libnet_RemoteTOD r;
308 : NTSTATUS status;
309 : TALLOC_CTX *mem_ctx;
310 : char timestr[64];
311 : PyObject *ret;
312 : struct tm *tm;
313 :
314 14 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
315 : discard_const_p(char *, kwnames), &r.generic.in.server_name))
316 0 : return NULL;
317 :
318 14 : r.generic.level = LIBNET_REMOTE_TOD_GENERIC;
319 :
320 14 : mem_ctx = talloc_new(NULL);
321 14 : if (mem_ctx == NULL) {
322 0 : PyErr_NoMemory();
323 0 : return NULL;
324 : }
325 :
326 14 : status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
327 14 : if (!NT_STATUS_IS_OK(status)) {
328 1 : PyErr_SetNTSTATUS_and_string(status,
329 : r.generic.out.error_string
330 : ? r.generic.out.error_string
331 : : nt_errstr(status));
332 1 : talloc_free(mem_ctx);
333 1 : return NULL;
334 : }
335 :
336 13 : ZERO_STRUCT(timestr);
337 13 : tm = localtime(&r.generic.out.time);
338 13 : strftime(timestr, sizeof(timestr)-1, "%c %Z",tm);
339 :
340 13 : ret = PyUnicode_FromString(timestr);
341 :
342 13 : talloc_free(mem_ctx);
343 :
344 13 : return ret;
345 : }
346 :
347 : static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
348 : "Retrieve the remote time on a server";
349 :
350 0 : static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
351 : {
352 0 : const char *kwnames[] = { "username", NULL };
353 : NTSTATUS status;
354 : TALLOC_CTX *mem_ctx;
355 : struct libnet_CreateUser r;
356 :
357 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
358 : &r.in.user_name))
359 0 : return NULL;
360 :
361 0 : r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
362 :
363 0 : mem_ctx = talloc_new(NULL);
364 0 : if (mem_ctx == NULL) {
365 0 : PyErr_NoMemory();
366 0 : return NULL;
367 : }
368 :
369 0 : status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
370 0 : if (!NT_STATUS_IS_OK(status)) {
371 0 : PyErr_SetNTSTATUS_and_string(status,
372 : r.out.error_string
373 : ? r.out.error_string
374 : : nt_errstr(status));
375 0 : talloc_free(mem_ctx);
376 0 : return NULL;
377 : }
378 :
379 0 : talloc_free(mem_ctx);
380 :
381 0 : Py_RETURN_NONE;
382 : }
383 :
384 : static const char py_net_create_user_doc[] = "create_user(username)\n"
385 : "Create a new user.";
386 :
387 0 : static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
388 : {
389 0 : const char *kwnames[] = { "username", NULL };
390 : NTSTATUS status;
391 : TALLOC_CTX *mem_ctx;
392 : struct libnet_DeleteUser r;
393 :
394 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
395 : &r.in.user_name))
396 0 : return NULL;
397 :
398 0 : r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
399 :
400 0 : mem_ctx = talloc_new(NULL);
401 0 : if (mem_ctx == NULL) {
402 0 : PyErr_NoMemory();
403 0 : return NULL;
404 : }
405 :
406 0 : status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
407 0 : if (!NT_STATUS_IS_OK(status)) {
408 0 : PyErr_SetNTSTATUS_and_string(status,
409 : r.out.error_string
410 : ? r.out.error_string
411 : : nt_errstr(status));
412 0 : talloc_free(mem_ctx);
413 0 : return NULL;
414 : }
415 :
416 0 : talloc_free(mem_ctx);
417 :
418 0 : Py_RETURN_NONE;
419 : }
420 :
421 : static const char py_net_delete_user_doc[] = "delete_user(username)\n"
422 : "Delete a user.";
423 :
424 : struct replicate_state {
425 : void *vampire_state;
426 : dcerpc_InterfaceObject *drs_pipe;
427 : struct libnet_BecomeDC_StoreChunk chunk;
428 : DATA_BLOB gensec_skey;
429 : struct libnet_BecomeDC_Partition partition;
430 : struct libnet_BecomeDC_Forest forest;
431 : struct libnet_BecomeDC_DestDSA dest_dsa;
432 : };
433 :
434 : /*
435 : setup for replicate_chunk() calls
436 : */
437 124 : static PyObject *py_net_replicate_init(py_net_Object *self, PyObject *args, PyObject *kwargs)
438 : {
439 124 : const char *kwnames[] = { "samdb", "lp", "drspipe", "invocation_id", NULL };
440 : PyObject *py_ldb, *py_lp, *py_drspipe, *py_invocation_id;
441 : struct ldb_context *samdb;
442 : struct loadparm_context *lp;
443 : struct replicate_state *s;
444 : NTSTATUS status;
445 :
446 124 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO",
447 : discard_const_p(char *, kwnames),
448 : &py_ldb, &py_lp, &py_drspipe,
449 : &py_invocation_id)) {
450 0 : return NULL;
451 : }
452 :
453 124 : s = talloc_zero(NULL, struct replicate_state);
454 124 : if (!s) return NULL;
455 :
456 124 : lp = lpcfg_from_py_object(s, py_lp);
457 124 : if (lp == NULL) {
458 0 : PyErr_SetString(PyExc_TypeError, "Expected lp object");
459 0 : talloc_free(s);
460 0 : return NULL;
461 : }
462 :
463 124 : samdb = pyldb_Ldb_AsLdbContext(py_ldb);
464 124 : if (samdb == NULL) {
465 0 : PyErr_SetString(PyExc_TypeError, "Expected ldb object");
466 0 : talloc_free(s);
467 0 : return NULL;
468 : }
469 124 : if (!py_check_dcerpc_type(py_invocation_id, "samba.dcerpc.misc", "GUID")) {
470 :
471 0 : talloc_free(s);
472 0 : return NULL;
473 : }
474 124 : s->dest_dsa.invocation_id = *pytalloc_get_type(py_invocation_id, struct GUID);
475 :
476 124 : s->drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);
477 :
478 124 : s->vampire_state = libnet_vampire_replicate_init(s, samdb, lp);
479 124 : if (s->vampire_state == NULL) {
480 0 : PyErr_SetString(PyExc_TypeError, "Failed to initialise vampire_state");
481 0 : talloc_free(s);
482 0 : return NULL;
483 : }
484 :
485 124 : status = gensec_session_key(s->drs_pipe->pipe->conn->security_state.generic_state,
486 : s,
487 : &s->gensec_skey);
488 124 : if (!NT_STATUS_IS_OK(status)) {
489 0 : char *error_string = talloc_asprintf(s,
490 : "Unable to get session key from drspipe: %s",
491 : nt_errstr(status));
492 0 : PyErr_SetNTSTATUS_and_string(status, error_string);
493 0 : talloc_free(s);
494 0 : return NULL;
495 : }
496 :
497 124 : s->forest.dns_name = samdb_dn_to_dns_domain(s, ldb_get_root_basedn(samdb));
498 124 : s->forest.root_dn_str = ldb_dn_get_linearized(ldb_get_root_basedn(samdb));
499 124 : s->forest.config_dn_str = ldb_dn_get_linearized(ldb_get_config_basedn(samdb));
500 124 : s->forest.schema_dn_str = ldb_dn_get_linearized(ldb_get_schema_basedn(samdb));
501 :
502 124 : s->chunk.gensec_skey = &s->gensec_skey;
503 124 : s->chunk.partition = &s->partition;
504 124 : s->chunk.forest = &s->forest;
505 124 : s->chunk.dest_dsa = &s->dest_dsa;
506 :
507 124 : return pytalloc_GenericObject_steal(s);
508 : }
509 :
510 :
511 : /*
512 : process one replication chunk
513 : */
514 1495 : static PyObject *py_net_replicate_chunk(py_net_Object *self, PyObject *args, PyObject *kwargs)
515 : {
516 1495 : const char *kwnames[] = { "state", "level", "ctr",
517 : "schema", "req_level", "req",
518 : NULL };
519 1495 : PyObject *py_state, *py_ctr, *py_schema = Py_None, *py_req = Py_None;
520 : struct replicate_state *s;
521 : unsigned level;
522 1495 : unsigned req_level = 0;
523 : WERROR (*chunk_handler)(void *private_data, const struct libnet_BecomeDC_StoreChunk *c);
524 : WERROR werr;
525 1495 : enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
526 1495 : enum drsuapi_DsExtendedOperation exop = DRSUAPI_EXOP_NONE;
527 :
528 1495 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OIO|OIO",
529 : discard_const_p(char *, kwnames),
530 : &py_state, &level, &py_ctr,
531 : &py_schema, &req_level, &py_req)) {
532 0 : return NULL;
533 : }
534 :
535 1495 : s = pytalloc_get_type(py_state, struct replicate_state);
536 1495 : if (!s) {
537 0 : return NULL;
538 : }
539 :
540 1495 : switch (level) {
541 0 : case 1:
542 0 : if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr1")) {
543 0 : return NULL;
544 : }
545 0 : s->chunk.ctr1 = pytalloc_get_ptr(py_ctr);
546 0 : if (s->chunk.ctr1->naming_context != NULL) {
547 0 : s->partition.nc = *s->chunk.ctr1->naming_context;
548 : }
549 0 : extended_ret = s->chunk.ctr1->extended_ret;
550 0 : s->partition.more_data = s->chunk.ctr1->more_data;
551 0 : s->partition.source_dsa_guid = s->chunk.ctr1->source_dsa_guid;
552 0 : s->partition.source_dsa_invocation_id = s->chunk.ctr1->source_dsa_invocation_id;
553 0 : s->partition.highwatermark = s->chunk.ctr1->new_highwatermark;
554 0 : break;
555 1495 : case 6:
556 1495 : if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr6")) {
557 0 : return NULL;
558 : }
559 1495 : s->chunk.ctr6 = pytalloc_get_ptr(py_ctr);
560 1495 : if (s->chunk.ctr6->naming_context != NULL) {
561 1491 : s->partition.nc = *s->chunk.ctr6->naming_context;
562 : }
563 1495 : extended_ret = s->chunk.ctr6->extended_ret;
564 1495 : s->partition.more_data = s->chunk.ctr6->more_data;
565 1495 : s->partition.source_dsa_guid = s->chunk.ctr6->source_dsa_guid;
566 1495 : s->partition.source_dsa_invocation_id = s->chunk.ctr6->source_dsa_invocation_id;
567 1495 : s->partition.highwatermark = s->chunk.ctr6->new_highwatermark;
568 1495 : break;
569 0 : default:
570 0 : PyErr_Format(PyExc_TypeError, "Bad level %u in replicate_chunk", level);
571 0 : return NULL;
572 : }
573 :
574 1495 : s->chunk.req5 = NULL;
575 1495 : s->chunk.req8 = NULL;
576 1495 : s->chunk.req10 = NULL;
577 1495 : if (py_req != Py_None) {
578 1495 : switch (req_level) {
579 0 : case 0:
580 0 : break;
581 0 : case 5:
582 0 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest5")) {
583 0 : return NULL;
584 : }
585 :
586 0 : s->chunk.req5 = pytalloc_get_ptr(py_req);
587 0 : exop = s->chunk.req5->extended_op;
588 0 : break;
589 0 : case 8:
590 0 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest8")) {
591 0 : return NULL;
592 : }
593 :
594 0 : s->chunk.req8 = pytalloc_get_ptr(py_req);
595 0 : exop = s->chunk.req8->extended_op;
596 0 : break;
597 1495 : case 10:
598 1495 : if (!py_check_dcerpc_type(py_req, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest10")) {
599 0 : return NULL;
600 : }
601 :
602 1495 : s->chunk.req10 = pytalloc_get_ptr(py_req);
603 1495 : exop = s->chunk.req10->extended_op;
604 1495 : break;
605 0 : default:
606 0 : PyErr_Format(PyExc_TypeError, "Bad req_level %u in replicate_chunk", req_level);
607 0 : return NULL;
608 : }
609 0 : }
610 :
611 1495 : if (exop != DRSUAPI_EXOP_NONE && extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
612 4 : PyErr_SetDsExtendedError(extended_ret, NULL);
613 4 : return NULL;
614 : }
615 :
616 1491 : s->chunk.req_level = req_level;
617 :
618 1491 : chunk_handler = libnet_vampire_cb_store_chunk;
619 1491 : if (py_schema) {
620 1491 : if (!PyBool_Check(py_schema)) {
621 0 : PyErr_SetString(PyExc_TypeError, "Expected boolean schema");
622 0 : return NULL;
623 : }
624 1491 : if (py_schema == Py_True) {
625 328 : chunk_handler = libnet_vampire_cb_schema_chunk;
626 : }
627 : }
628 :
629 1491 : s->chunk.ctr_level = level;
630 :
631 1491 : werr = chunk_handler(s->vampire_state, &s->chunk);
632 1491 : if (!W_ERROR_IS_OK(werr)) {
633 27 : char *error_string
634 27 : = talloc_asprintf(NULL,
635 : "Failed to process 'chunk' of DRS replicated objects: %s",
636 : win_errstr(werr));
637 27 : PyErr_SetWERROR_and_string(werr, error_string);
638 27 : TALLOC_FREE(error_string);
639 27 : return NULL;
640 : }
641 :
642 1464 : Py_RETURN_NONE;
643 : }
644 :
645 :
646 : /*
647 : just do the decryption of a DRS replicated attribute
648 : */
649 604 : static PyObject *py_net_replicate_decrypt(py_net_Object *self, PyObject *args, PyObject *kwargs)
650 : {
651 604 : const char *kwnames[] = { "drspipe", "attribute", "rid", NULL };
652 : PyObject *py_drspipe, *py_attribute;
653 : NTSTATUS status;
654 : dcerpc_InterfaceObject *drs_pipe;
655 : TALLOC_CTX *frame;
656 : TALLOC_CTX *context;
657 : DATA_BLOB gensec_skey;
658 : unsigned int rid;
659 : struct drsuapi_DsReplicaAttribute *attribute;
660 : WERROR werr;
661 :
662 604 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOI",
663 : discard_const_p(char *, kwnames),
664 : &py_drspipe,
665 : &py_attribute, &rid)) {
666 0 : return NULL;
667 : }
668 :
669 604 : frame = talloc_stackframe();
670 :
671 604 : if (!py_check_dcerpc_type(py_drspipe,
672 : "samba.dcerpc.base",
673 : "ClientConnection")) {
674 0 : return NULL;
675 : }
676 604 : drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);
677 :
678 604 : status = gensec_session_key(drs_pipe->pipe->conn->security_state.generic_state,
679 : frame,
680 : &gensec_skey);
681 604 : if (!NT_STATUS_IS_OK(status)) {
682 0 : char *error_string
683 0 : = talloc_asprintf(frame,
684 : "Unable to get session key from drspipe: %s",
685 : nt_errstr(status));
686 0 : PyErr_SetNTSTATUS_and_string(status, error_string);
687 0 : talloc_free(frame);
688 0 : return NULL;
689 : }
690 :
691 604 : if (!py_check_dcerpc_type(py_attribute, "samba.dcerpc.drsuapi",
692 : "DsReplicaAttribute")) {
693 0 : return NULL;
694 : }
695 :
696 604 : attribute = pytalloc_get_ptr(py_attribute);
697 604 : context = pytalloc_get_mem_ctx(py_attribute);
698 604 : werr = drsuapi_decrypt_attribute(context, &gensec_skey,
699 : rid, 0, attribute);
700 604 : if (!W_ERROR_IS_OK(werr)) {
701 0 : char *error_string = talloc_asprintf(frame,
702 : "Unable to get decrypt attribute: %s",
703 : win_errstr(werr));
704 0 : PyErr_SetWERROR_and_string(werr, error_string);
705 0 : talloc_free(frame);
706 0 : return NULL;
707 : }
708 :
709 604 : talloc_free(frame);
710 :
711 604 : Py_RETURN_NONE;
712 :
713 : }
714 :
715 : /*
716 : find a DC given a domain name and server type
717 : */
718 266 : static PyObject *py_net_finddc(py_net_Object *self, PyObject *args, PyObject *kwargs)
719 : {
720 266 : const char *domain = NULL, *address = NULL;
721 : unsigned server_type;
722 : NTSTATUS status;
723 : struct finddcs *io;
724 : TALLOC_CTX *mem_ctx;
725 : PyObject *ret;
726 266 : const char * const kwnames[] = { "flags", "domain", "address", NULL };
727 :
728 266 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I|zz",
729 : discard_const_p(char *, kwnames),
730 : &server_type, &domain, &address)) {
731 0 : return NULL;
732 : }
733 :
734 266 : mem_ctx = talloc_new(self->mem_ctx);
735 266 : if (mem_ctx == NULL) {
736 0 : PyErr_NoMemory();
737 0 : return NULL;
738 : }
739 :
740 266 : io = talloc_zero(mem_ctx, struct finddcs);
741 266 : if (io == NULL) {
742 0 : TALLOC_FREE(mem_ctx);
743 0 : PyErr_NoMemory();
744 0 : return NULL;
745 : }
746 :
747 266 : if (domain != NULL) {
748 55 : io->in.domain_name = domain;
749 : }
750 266 : if (address != NULL) {
751 211 : io->in.server_address = address;
752 : }
753 266 : io->in.minimum_dc_flags = server_type;
754 :
755 522 : status = finddcs_cldap(io, io,
756 266 : lpcfg_resolve_context(self->libnet_ctx->lp_ctx), self->ev);
757 266 : if (NT_STATUS_IS_ERR(status)) {
758 0 : PyErr_SetNTSTATUS(status);
759 0 : talloc_free(mem_ctx);
760 0 : return NULL;
761 : }
762 :
763 266 : ret = py_return_ndr_struct("samba.dcerpc.nbt", "NETLOGON_SAM_LOGON_RESPONSE_EX",
764 266 : io, &io->out.netlogon.data.nt5_ex);
765 266 : talloc_free(mem_ctx);
766 :
767 266 : return ret;
768 : }
769 :
770 :
771 : static const char py_net_replicate_init_doc[] = "replicate_init(samdb, lp, drspipe)\n"
772 : "Setup for replicate_chunk calls.";
773 :
774 : static const char py_net_replicate_chunk_doc[] = "replicate_chunk(state, level, ctr, schema)\n"
775 : "Process replication for one chunk";
776 :
777 : static const char py_net_replicate_decrypt_doc[] = "replicate_decrypt(drs, attribute, rid)\n"
778 : "Decrypt (in place) a DsReplicaAttribute replicated with drs.GetNCChanges()";
779 :
780 : static const char py_net_finddc_doc[] = "finddc(flags=server_type, domain=None, address=None)\n"
781 : "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";
782 :
783 : static PyMethodDef net_obj_methods[] = {
784 : {
785 : .ml_name = "join_member",
786 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
787 : py_net_join_member),
788 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
789 : .ml_doc = py_net_join_member_doc
790 : },
791 : {
792 : .ml_name = "change_password",
793 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
794 : py_net_change_password),
795 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
796 : .ml_doc = py_net_change_password_doc
797 : },
798 : {
799 : .ml_name = "set_password",
800 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
801 : py_net_set_password),
802 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
803 : .ml_doc = py_net_set_password_doc
804 : },
805 : {
806 : .ml_name = "time",
807 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, py_net_time),
808 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
809 : .ml_doc = py_net_time_doc
810 : },
811 : {
812 : .ml_name = "create_user",
813 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
814 : py_net_user_create),
815 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
816 : .ml_doc = py_net_create_user_doc
817 : },
818 : {
819 : .ml_name = "delete_user",
820 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
821 : py_net_user_delete),
822 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
823 : .ml_doc = py_net_delete_user_doc
824 : },
825 : {
826 : .ml_name = "replicate_init",
827 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
828 : py_net_replicate_init),
829 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
830 : .ml_doc = py_net_replicate_init_doc
831 : },
832 : {
833 : .ml_name = "replicate_chunk",
834 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
835 : py_net_replicate_chunk),
836 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
837 : .ml_doc = py_net_replicate_chunk_doc
838 : },
839 : {
840 : .ml_name = "replicate_decrypt",
841 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
842 : py_net_replicate_decrypt),
843 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
844 : .ml_doc = py_net_replicate_decrypt_doc
845 : },
846 : {
847 : .ml_name = "finddc",
848 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction,
849 : py_net_finddc),
850 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
851 : .ml_doc = py_net_finddc_doc
852 : },
853 : { .ml_name = NULL }
854 : };
855 :
856 1008 : static void py_net_dealloc(py_net_Object *self)
857 : {
858 1008 : talloc_free(self->ev);
859 1008 : PyObject_Del(self);
860 1008 : }
861 :
862 1008 : static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
863 : {
864 1008 : PyObject *py_creds, *py_lp = Py_None;
865 1008 : const char *kwnames[] = { "creds", "lp", "server", NULL };
866 : py_net_Object *ret;
867 : struct loadparm_context *lp;
868 1008 : const char *server_address = NULL;
869 :
870 1008 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oz",
871 : discard_const_p(char *, kwnames), &py_creds, &py_lp,
872 : &server_address))
873 0 : return NULL;
874 :
875 1008 : ret = PyObject_New(py_net_Object, type);
876 1008 : if (ret == NULL) {
877 0 : return NULL;
878 : }
879 :
880 : /* FIXME: we really need to get a context from the caller or we may end
881 : * up with 2 event contexts */
882 1008 : ret->ev = s4_event_context_init(NULL);
883 1008 : ret->mem_ctx = talloc_new(ret->ev);
884 :
885 1008 : lp = lpcfg_from_py_object(ret->mem_ctx, py_lp);
886 1008 : if (lp == NULL) {
887 0 : Py_DECREF(ret);
888 0 : return NULL;
889 : }
890 :
891 1008 : ret->libnet_ctx = libnet_context_init(ret->ev, lp);
892 1008 : if (ret->libnet_ctx == NULL) {
893 0 : PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
894 0 : Py_DECREF(ret);
895 0 : return NULL;
896 : }
897 :
898 1008 : ret->libnet_ctx->server_address = server_address;
899 :
900 1008 : ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
901 1008 : if (ret->libnet_ctx->cred == NULL) {
902 0 : PyErr_SetString(PyExc_TypeError, "Expected credentials object");
903 0 : Py_DECREF(ret);
904 0 : return NULL;
905 : }
906 :
907 1008 : return (PyObject *)ret;
908 : }
909 :
910 :
911 : PyTypeObject py_net_Type = {
912 : PyVarObject_HEAD_INIT(NULL, 0)
913 : .tp_name = "net.Net",
914 : .tp_basicsize = sizeof(py_net_Object),
915 : .tp_dealloc = (destructor)py_net_dealloc,
916 : .tp_methods = net_obj_methods,
917 : .tp_new = net_obj_new,
918 : };
919 :
920 : static struct PyModuleDef moduledef = {
921 : PyModuleDef_HEAD_INIT,
922 : .m_name = "net",
923 : .m_size = -1,
924 : };
925 :
926 3040 : MODULE_INIT_FUNC(net)
927 : {
928 : PyObject *m;
929 :
930 3040 : if (PyType_Ready(&py_net_Type) < 0)
931 0 : return NULL;
932 :
933 3040 : m = PyModule_Create(&moduledef);
934 3040 : if (m == NULL)
935 0 : return NULL;
936 :
937 3040 : Py_INCREF(&py_net_Type);
938 3040 : PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
939 3040 : PyModule_AddIntConstant(m, "LIBNET_JOINDOMAIN_AUTOMATIC", LIBNET_JOINDOMAIN_AUTOMATIC);
940 3040 : PyModule_AddIntConstant(m, "LIBNET_JOINDOMAIN_SPECIFIED", LIBNET_JOINDOMAIN_SPECIFIED);
941 3040 : PyModule_AddIntConstant(m, "LIBNET_JOIN_AUTOMATIC", LIBNET_JOIN_AUTOMATIC);
942 3040 : PyModule_AddIntConstant(m, "LIBNET_JOIN_SPECIFIED", LIBNET_JOIN_SPECIFIED);
943 :
944 3040 : return m;
945 : }
|