2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2010
6 Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
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.
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.
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/>.
22 #include "lib/replace/system/python.h"
23 #include "python/py3compat.h"
25 #include "python/modules.h"
29 #include "libnet_join_proto.h"
30 #include "auth/credentials/pycredentials.h"
31 #include "libcli/security/security.h"
32 #include "lib/events/events.h"
33 #include "param/pyparam.h"
34 #include "auth/gensec/gensec.h"
35 #include "librpc/rpc/pyrpc_util.h"
36 #include "libcli/resolve/resolve.h"
37 #include "libcli/finddc.h"
38 #include "dsdb/samdb/samdb.h"
40 #include "librpc/rpc/pyrpc_util.h"
41 #include "libcli/drsuapi/drsuapi.h"
43 static void PyErr_SetDsExtendedError(enum drsuapi_DsExtendedError ext_err
, const char *error_description
)
46 PyObject
*error
= NULL
;
47 mod
= PyImport_ImportModule("samba");
49 error
= PyObject_GetAttrString(mod
, "DsExtendedError");
51 if (error_description
== NULL
) {
53 /* Copied out of ndr_drsuapi.c:ndr_print_drsuapi_DsExtendedError() */
54 case DRSUAPI_EXOP_ERR_NONE
:
55 error_description
= "DRSUAPI_EXOP_ERR_NONE";
57 case DRSUAPI_EXOP_ERR_SUCCESS
:
58 error_description
= "DRSUAPI_EXOP_ERR_SUCCESS";
60 case DRSUAPI_EXOP_ERR_UNKNOWN_OP
:
61 error_description
= "DRSUAPI_EXOP_ERR_UNKNOWN_OP";
63 case DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER
:
64 error_description
= "DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER";
66 case DRSUAPI_EXOP_ERR_UPDATE_ERR
:
67 error_description
= "DRSUAPI_EXOP_ERR_UPDATE_ERR";
69 case DRSUAPI_EXOP_ERR_EXCEPTION
:
70 error_description
= "DRSUAPI_EXOP_ERR_EXCEPTION";
72 case DRSUAPI_EXOP_ERR_UNKNOWN_CALLER
:
73 error_description
= "DRSUAPI_EXOP_ERR_UNKNOWN_CALLER";
75 case DRSUAPI_EXOP_ERR_RID_ALLOC
:
76 error_description
= "DRSUAPI_EXOP_ERR_RID_ALLOC";
78 case DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED
:
79 error_description
= "DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED";
81 case DRSUAPI_EXOP_ERR_FMSO_PENDING_OP
:
82 error_description
= "DRSUAPI_EXOP_ERR_FMSO_PENDING_OP";
84 case DRSUAPI_EXOP_ERR_MISMATCH
:
85 error_description
= "DRSUAPI_EXOP_ERR_MISMATCH";
87 case DRSUAPI_EXOP_ERR_COULDNT_CONTACT
:
88 error_description
= "DRSUAPI_EXOP_ERR_COULDNT_CONTACT";
90 case DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES
:
91 error_description
= "DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES";
93 case DRSUAPI_EXOP_ERR_DIR_ERROR
:
94 error_description
= "DRSUAPI_EXOP_ERR_DIR_ERROR";
96 case DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS
:
97 error_description
= "DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS";
99 case DRSUAPI_EXOP_ERR_ACCESS_DENIED
:
100 error_description
= "DRSUAPI_EXOP_ERR_ACCESS_DENIED";
102 case DRSUAPI_EXOP_ERR_PARAM_ERROR
:
103 error_description
= "DRSUAPI_EXOP_ERR_PARAM_ERROR";
109 Py_BuildValue(discard_const_p(char, "(i,s)"),
112 PyErr_SetObject(error
, value
);
120 static PyObject
*py_net_join_member(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
122 struct libnet_Join_member r
;
127 const char *kwnames
[] = { "domain_name", "netbios_name", "level", "machinepass", NULL
};
131 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "ssi|z:Join", discard_const_p(char *, kwnames
),
132 &r
.in
.domain_name
, &r
.in
.netbios_name
,
134 &r
.in
.account_pass
)) {
139 mem_ctx
= talloc_new(self
->mem_ctx
);
140 if (mem_ctx
== NULL
) {
145 status
= libnet_Join_member(self
->libnet_ctx
, mem_ctx
, &r
);
146 if (NT_STATUS_IS_ERR(status
)) {
147 PyErr_SetNTSTATUS_and_string(status
,
150 : nt_errstr(status
));
151 talloc_free(mem_ctx
);
155 result
= Py_BuildValue("sss", r
.out
.join_password
,
156 dom_sid_string(mem_ctx
, r
.out
.domain_sid
),
159 talloc_free(mem_ctx
);
164 static const char py_net_join_member_doc
[] = "join_member(domain_name, netbios_name, level) -> (join_password, domain_sid, domain_name)\n\n" \
165 "Join the domain with the specified name.";
167 static PyObject
*py_net_change_password(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
169 union libnet_ChangePassword r
;
171 TALLOC_CTX
*mem_ctx
= NULL
;
172 struct tevent_context
*ev
= NULL
;
173 const char *kwnames
[] = { "newpassword", "oldpassword", "domain", "username", NULL
};
174 const char *newpass
= NULL
;
175 const char *oldpass
= NULL
;
177 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, PYARG_STR_UNI
178 "|"PYARG_STR_UNI
"ss:change_password",
179 discard_const_p(char *, kwnames
),
184 &r
.generic
.in
.domain_name
,
185 &r
.generic
.in
.account_name
)) {
189 r
.generic
.in
.newpassword
= newpass
;
190 r
.generic
.in
.oldpassword
= oldpass
;
192 r
.generic
.level
= LIBNET_CHANGE_PASSWORD_GENERIC
;
193 if (r
.generic
.in
.account_name
== NULL
) {
194 r
.generic
.in
.account_name
195 = cli_credentials_get_username(self
->libnet_ctx
->cred
);
197 if (r
.generic
.in
.domain_name
== NULL
) {
198 r
.generic
.in
.domain_name
199 = cli_credentials_get_domain(self
->libnet_ctx
->cred
);
201 if (r
.generic
.in
.oldpassword
== NULL
) {
202 r
.generic
.in
.oldpassword
203 = cli_credentials_get_password(self
->libnet_ctx
->cred
);
206 /* FIXME: we really need to get a context from the caller or we may end
207 * up with 2 event contexts */
208 ev
= s4_event_context_init(NULL
);
210 mem_ctx
= talloc_new(ev
);
211 if (mem_ctx
== NULL
) {
212 PyMem_Free(discard_const_p(char, newpass
));
213 PyMem_Free(discard_const_p(char, oldpass
));
218 status
= libnet_ChangePassword(self
->libnet_ctx
, mem_ctx
, &r
);
220 PyMem_Free(discard_const_p(char, newpass
));
221 PyMem_Free(discard_const_p(char, oldpass
));
223 if (NT_STATUS_IS_ERR(status
)) {
224 PyErr_SetNTSTATUS_and_string(status
,
225 r
.generic
.out
.error_string
226 ? r
.generic
.out
.error_string
227 : nt_errstr(status
));
228 talloc_free(mem_ctx
);
232 talloc_free(mem_ctx
);
236 static const char py_net_change_password_doc
[] = "change_password(newpassword) -> True\n\n" \
237 "Change password for a user. You must supply credential with enough rights to do this.\n\n" \
238 "Sample usage is:\n" \
239 "net.change_password(newpassword=<new_password>)\n";
242 static PyObject
*py_net_set_password(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
244 union libnet_SetPassword r
;
247 struct tevent_context
*ev
;
248 const char *kwnames
[] = { "account_name", "domain_name", "newpassword", "force_samr_18", NULL
};
249 PyObject
*py_force_samr_18
= Py_False
;
253 r
.generic
.level
= LIBNET_SET_PASSWORD_GENERIC
;
255 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sss|O:set_password",
256 discard_const_p(char *, kwnames
),
257 &r
.generic
.in
.account_name
,
258 &r
.generic
.in
.domain_name
,
259 &r
.generic
.in
.newpassword
,
260 &py_force_samr_18
)) {
264 if (py_force_samr_18
) {
265 if (!PyBool_Check(py_force_samr_18
)) {
266 PyErr_SetString(PyExc_TypeError
, "Expected boolean force_samr_18");
269 if (py_force_samr_18
== Py_True
) {
270 r
.generic
.samr_level
= LIBNET_SET_PASSWORD_SAMR_HANDLE_18
;
274 /* FIXME: we really need to get a context from the caller or we may end
275 * up with 2 event contexts */
276 ev
= s4_event_context_init(NULL
);
278 mem_ctx
= talloc_new(ev
);
279 if (mem_ctx
== NULL
) {
284 status
= libnet_SetPassword(self
->libnet_ctx
, mem_ctx
, &r
);
285 if (NT_STATUS_IS_ERR(status
)) {
286 PyErr_SetNTSTATUS_and_string(status
,
287 r
.generic
.out
.error_string
288 ? r
.generic
.out
.error_string
289 : nt_errstr(status
));
290 talloc_free(mem_ctx
);
294 talloc_free(mem_ctx
);
299 static const char py_net_set_password_doc
[] = "set_password(account_name, domain_name, newpassword) -> True\n\n" \
300 "Set password for a user. You must supply credential with enough rights to do this.\n\n" \
301 "Sample usage is:\n" \
302 "net.set_password(account_name=account_name, domain_name=domain_name, newpassword=new_pass)\n";
305 static PyObject
*py_net_time(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
307 const char *kwnames
[] = { "server_name", NULL
};
308 union libnet_RemoteTOD r
;
316 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s",
317 discard_const_p(char *, kwnames
), &r
.generic
.in
.server_name
))
320 r
.generic
.level
= LIBNET_REMOTE_TOD_GENERIC
;
322 mem_ctx
= talloc_new(NULL
);
323 if (mem_ctx
== NULL
) {
328 status
= libnet_RemoteTOD(self
->libnet_ctx
, mem_ctx
, &r
);
329 if (!NT_STATUS_IS_OK(status
)) {
330 PyErr_SetNTSTATUS_and_string(status
,
331 r
.generic
.out
.error_string
332 ? r
.generic
.out
.error_string
333 : nt_errstr(status
));
334 talloc_free(mem_ctx
);
338 ZERO_STRUCT(timestr
);
339 tm
= localtime(&r
.generic
.out
.time
);
341 len
= strftime(timestr
, sizeof(timestr
), "%c %Z", tm
);
346 ret
= PyUnicode_FromStringAndSize(timestr
, (Py_ssize_t
)len
);
349 talloc_free(mem_ctx
);
353 static const char py_net_time_doc
[] = "time(server_name) -> timestr\n"
354 "Retrieve the remote time on a server";
356 static PyObject
*py_net_user_create(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
358 const char *kwnames
[] = { "username", NULL
};
361 struct libnet_CreateUser r
;
363 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s", discard_const_p(char *, kwnames
),
367 r
.in
.domain_name
= cli_credentials_get_domain(self
->libnet_ctx
->cred
);
369 mem_ctx
= talloc_new(NULL
);
370 if (mem_ctx
== NULL
) {
375 status
= libnet_CreateUser(self
->libnet_ctx
, mem_ctx
, &r
);
376 if (!NT_STATUS_IS_OK(status
)) {
377 PyErr_SetNTSTATUS_and_string(status
,
380 : nt_errstr(status
));
381 talloc_free(mem_ctx
);
385 talloc_free(mem_ctx
);
390 static const char py_net_create_user_doc
[] = "create_user(username)\n"
391 "Create a new user.";
393 static PyObject
*py_net_user_delete(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
395 const char *kwnames
[] = { "username", NULL
};
398 struct libnet_DeleteUser r
;
400 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s", discard_const_p(char *, kwnames
),
404 r
.in
.domain_name
= cli_credentials_get_domain(self
->libnet_ctx
->cred
);
406 mem_ctx
= talloc_new(NULL
);
407 if (mem_ctx
== NULL
) {
412 status
= libnet_DeleteUser(self
->libnet_ctx
, mem_ctx
, &r
);
413 if (!NT_STATUS_IS_OK(status
)) {
414 PyErr_SetNTSTATUS_and_string(status
,
417 : nt_errstr(status
));
418 talloc_free(mem_ctx
);
422 talloc_free(mem_ctx
);
427 static const char py_net_delete_user_doc
[] = "delete_user(username)\n"
430 struct replicate_state
{
432 dcerpc_InterfaceObject
*drs_pipe
;
433 struct libnet_BecomeDC_StoreChunk chunk
;
434 DATA_BLOB gensec_skey
;
435 struct libnet_BecomeDC_Partition partition
;
436 struct libnet_BecomeDC_Forest forest
;
437 struct libnet_BecomeDC_DestDSA dest_dsa
;
441 setup for replicate_chunk() calls
443 static PyObject
*py_net_replicate_init(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
445 const char *kwnames
[] = { "samdb", "lp", "drspipe", "invocation_id", NULL
};
446 PyObject
*py_ldb
, *py_lp
, *py_drspipe
, *py_invocation_id
;
447 struct ldb_context
*samdb
;
448 struct loadparm_context
*lp
;
449 struct replicate_state
*s
;
452 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "OOOO",
453 discard_const_p(char *, kwnames
),
454 &py_ldb
, &py_lp
, &py_drspipe
,
455 &py_invocation_id
)) {
459 s
= talloc_zero(NULL
, struct replicate_state
);
462 lp
= lpcfg_from_py_object(s
, py_lp
);
464 PyErr_SetString(PyExc_TypeError
, "Expected lp object");
469 samdb
= pyldb_Ldb_AsLdbContext(py_ldb
);
471 PyErr_SetString(PyExc_TypeError
, "Expected ldb object");
475 if (!py_check_dcerpc_type(py_invocation_id
, "samba.dcerpc.misc", "GUID")) {
480 s
->dest_dsa
.invocation_id
= *pytalloc_get_type(py_invocation_id
, struct GUID
);
482 s
->drs_pipe
= (dcerpc_InterfaceObject
*)(py_drspipe
);
484 s
->vampire_state
= libnet_vampire_replicate_init(s
, samdb
, lp
);
485 if (s
->vampire_state
== NULL
) {
486 PyErr_SetString(PyExc_TypeError
, "Failed to initialise vampire_state");
491 status
= dcerpc_binding_handle_auth_session_key(s
->drs_pipe
->binding_handle
,
494 if (!NT_STATUS_IS_OK(status
)) {
495 char *error_string
= talloc_asprintf(s
,
496 "Unable to get session key from drspipe: %s",
498 PyErr_SetNTSTATUS_and_string(status
, error_string
);
503 s
->forest
.dns_name
= samdb_dn_to_dns_domain(s
, ldb_get_root_basedn(samdb
));
504 s
->forest
.root_dn_str
= ldb_dn_get_linearized(ldb_get_root_basedn(samdb
));
505 s
->forest
.config_dn_str
= ldb_dn_get_linearized(ldb_get_config_basedn(samdb
));
506 s
->forest
.schema_dn_str
= ldb_dn_get_linearized(ldb_get_schema_basedn(samdb
));
508 s
->chunk
.gensec_skey
= &s
->gensec_skey
;
509 s
->chunk
.partition
= &s
->partition
;
510 s
->chunk
.forest
= &s
->forest
;
511 s
->chunk
.dest_dsa
= &s
->dest_dsa
;
513 return pytalloc_GenericObject_steal(s
);
518 process one replication chunk
520 static PyObject
*py_net_replicate_chunk(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
522 const char *kwnames
[] = { "state", "level", "ctr",
523 "schema", "req_level", "req",
525 PyObject
*py_state
, *py_ctr
, *py_schema
= Py_None
, *py_req
= Py_None
;
526 struct replicate_state
*s
;
528 unsigned req_level
= 0;
529 WERROR (*chunk_handler
)(void *private_data
, const struct libnet_BecomeDC_StoreChunk
*c
);
531 enum drsuapi_DsExtendedError extended_ret
= DRSUAPI_EXOP_ERR_NONE
;
532 enum drsuapi_DsExtendedOperation exop
= DRSUAPI_EXOP_NONE
;
534 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "OIO|OIO",
535 discard_const_p(char *, kwnames
),
536 &py_state
, &level
, &py_ctr
,
537 &py_schema
, &req_level
, &py_req
)) {
541 s
= pytalloc_get_type(py_state
, struct replicate_state
);
548 if (!py_check_dcerpc_type(py_ctr
, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr1")) {
551 s
->chunk
.ctr1
= pytalloc_get_ptr(py_ctr
);
552 if (s
->chunk
.ctr1
->naming_context
!= NULL
) {
553 s
->partition
.nc
= *s
->chunk
.ctr1
->naming_context
;
555 extended_ret
= s
->chunk
.ctr1
->extended_ret
;
556 s
->partition
.more_data
= s
->chunk
.ctr1
->more_data
;
557 s
->partition
.source_dsa_guid
= s
->chunk
.ctr1
->source_dsa_guid
;
558 s
->partition
.source_dsa_invocation_id
= s
->chunk
.ctr1
->source_dsa_invocation_id
;
559 s
->partition
.highwatermark
= s
->chunk
.ctr1
->new_highwatermark
;
562 if (!py_check_dcerpc_type(py_ctr
, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr6")) {
565 s
->chunk
.ctr6
= pytalloc_get_ptr(py_ctr
);
566 if (s
->chunk
.ctr6
->naming_context
!= NULL
) {
567 s
->partition
.nc
= *s
->chunk
.ctr6
->naming_context
;
569 extended_ret
= s
->chunk
.ctr6
->extended_ret
;
570 s
->partition
.more_data
= s
->chunk
.ctr6
->more_data
;
571 s
->partition
.source_dsa_guid
= s
->chunk
.ctr6
->source_dsa_guid
;
572 s
->partition
.source_dsa_invocation_id
= s
->chunk
.ctr6
->source_dsa_invocation_id
;
573 s
->partition
.highwatermark
= s
->chunk
.ctr6
->new_highwatermark
;
576 PyErr_Format(PyExc_TypeError
, "Bad level %u in replicate_chunk", level
);
580 s
->chunk
.req5
= NULL
;
581 s
->chunk
.req8
= NULL
;
582 s
->chunk
.req10
= NULL
;
583 if (py_req
!= Py_None
) {
588 if (!py_check_dcerpc_type(py_req
, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest5")) {
592 s
->chunk
.req5
= pytalloc_get_ptr(py_req
);
593 exop
= s
->chunk
.req5
->extended_op
;
596 if (!py_check_dcerpc_type(py_req
, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest8")) {
600 s
->chunk
.req8
= pytalloc_get_ptr(py_req
);
601 exop
= s
->chunk
.req8
->extended_op
;
604 if (!py_check_dcerpc_type(py_req
, "samba.dcerpc.drsuapi", "DsGetNCChangesRequest10")) {
608 s
->chunk
.req10
= pytalloc_get_ptr(py_req
);
609 exop
= s
->chunk
.req10
->extended_op
;
612 PyErr_Format(PyExc_TypeError
, "Bad req_level %u in replicate_chunk", req_level
);
617 if (exop
!= DRSUAPI_EXOP_NONE
&& extended_ret
!= DRSUAPI_EXOP_ERR_SUCCESS
) {
618 PyErr_SetDsExtendedError(extended_ret
, NULL
);
622 s
->chunk
.req_level
= req_level
;
624 chunk_handler
= libnet_vampire_cb_store_chunk
;
626 if (!PyBool_Check(py_schema
)) {
627 PyErr_SetString(PyExc_TypeError
, "Expected boolean schema");
630 if (py_schema
== Py_True
) {
631 chunk_handler
= libnet_vampire_cb_schema_chunk
;
635 s
->chunk
.ctr_level
= level
;
637 werr
= chunk_handler(s
->vampire_state
, &s
->chunk
);
638 if (!W_ERROR_IS_OK(werr
)) {
640 = talloc_asprintf(NULL
,
641 "Failed to process 'chunk' of DRS replicated objects: %s",
643 PyErr_SetWERROR_and_string(werr
, error_string
);
644 TALLOC_FREE(error_string
);
653 just do the decryption of a DRS replicated attribute
655 static PyObject
*py_net_replicate_decrypt(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
657 const char *kwnames
[] = { "drspipe", "attribute", "rid", NULL
};
658 PyObject
*py_drspipe
, *py_attribute
;
660 dcerpc_InterfaceObject
*drs_pipe
;
663 DATA_BLOB gensec_skey
;
665 struct drsuapi_DsReplicaAttribute
*attribute
;
668 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "OOI",
669 discard_const_p(char *, kwnames
),
671 &py_attribute
, &rid
)) {
675 frame
= talloc_stackframe();
677 if (!py_check_dcerpc_type(py_drspipe
,
679 "ClientConnection")) {
682 drs_pipe
= (dcerpc_InterfaceObject
*)(py_drspipe
);
684 status
= dcerpc_binding_handle_auth_session_key(drs_pipe
->binding_handle
,
687 if (!NT_STATUS_IS_OK(status
)) {
689 = talloc_asprintf(frame
,
690 "Unable to get session key from drspipe: %s",
692 PyErr_SetNTSTATUS_and_string(status
, error_string
);
697 if (!py_check_dcerpc_type(py_attribute
, "samba.dcerpc.drsuapi",
698 "DsReplicaAttribute")) {
702 attribute
= pytalloc_get_ptr(py_attribute
);
703 context
= pytalloc_get_mem_ctx(py_attribute
);
704 werr
= drsuapi_decrypt_attribute(context
, &gensec_skey
,
706 if (!W_ERROR_IS_OK(werr
)) {
707 char *error_string
= talloc_asprintf(frame
,
708 "Unable to get decrypt attribute: %s",
710 PyErr_SetWERROR_and_string(werr
, error_string
);
722 find a DC given a domain name and server type
724 static PyObject
*py_net_finddc(py_net_Object
*self
, PyObject
*args
, PyObject
*kwargs
)
726 const char *domain
= NULL
, *address
= NULL
;
727 unsigned server_type
;
732 const char * const kwnames
[] = { "flags", "domain", "address", NULL
};
734 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "I|zz",
735 discard_const_p(char *, kwnames
),
736 &server_type
, &domain
, &address
)) {
740 mem_ctx
= talloc_new(self
->mem_ctx
);
741 if (mem_ctx
== NULL
) {
746 io
= talloc_zero(mem_ctx
, struct finddcs
);
748 TALLOC_FREE(mem_ctx
);
753 if (domain
!= NULL
) {
754 io
->in
.domain_name
= domain
;
756 if (address
!= NULL
) {
757 io
->in
.server_address
= address
;
759 io
->in
.minimum_dc_flags
= server_type
;
760 io
->in
.proto
= lpcfg_client_netlogon_ping_protocol(
761 self
->libnet_ctx
->lp_ctx
);
763 status
= finddcs_cldap(io
, io
,
764 lpcfg_resolve_context(self
->libnet_ctx
->lp_ctx
), self
->ev
);
765 if (NT_STATUS_IS_ERR(status
)) {
766 PyErr_SetNTSTATUS(status
);
767 talloc_free(mem_ctx
);
771 ret
= py_return_ndr_struct("samba.dcerpc.nbt",
772 "NETLOGON_SAM_LOGON_RESPONSE_EX",
774 &io
->out
.netlogon
->data
.nt5_ex
);
775 talloc_free(mem_ctx
);
781 static const char py_net_replicate_init_doc
[] = "replicate_init(samdb, lp, drspipe)\n"
782 "Setup for replicate_chunk calls.";
784 static const char py_net_replicate_chunk_doc
[] = "replicate_chunk(state, level, ctr, schema)\n"
785 "Process replication for one chunk";
787 static const char py_net_replicate_decrypt_doc
[] = "replicate_decrypt(drs, attribute, rid)\n"
788 "Decrypt (in place) a DsReplicaAttribute replicated with drs.GetNCChanges()";
790 static const char py_net_finddc_doc
[] = "finddc(flags=server_type, domain=None, address=None)\n"
791 "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";
793 static PyMethodDef net_obj_methods
[] = {
795 .ml_name
= "join_member",
796 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
798 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
799 .ml_doc
= py_net_join_member_doc
802 .ml_name
= "change_password",
803 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
804 py_net_change_password
),
805 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
806 .ml_doc
= py_net_change_password_doc
809 .ml_name
= "set_password",
810 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
811 py_net_set_password
),
812 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
813 .ml_doc
= py_net_set_password_doc
817 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
, py_net_time
),
818 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
819 .ml_doc
= py_net_time_doc
822 .ml_name
= "create_user",
823 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
825 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
826 .ml_doc
= py_net_create_user_doc
829 .ml_name
= "delete_user",
830 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
832 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
833 .ml_doc
= py_net_delete_user_doc
836 .ml_name
= "replicate_init",
837 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
838 py_net_replicate_init
),
839 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
840 .ml_doc
= py_net_replicate_init_doc
843 .ml_name
= "replicate_chunk",
844 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
845 py_net_replicate_chunk
),
846 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
847 .ml_doc
= py_net_replicate_chunk_doc
850 .ml_name
= "replicate_decrypt",
851 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
852 py_net_replicate_decrypt
),
853 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
854 .ml_doc
= py_net_replicate_decrypt_doc
858 .ml_meth
= PY_DISCARD_FUNC_SIG(PyCFunction
,
860 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
861 .ml_doc
= py_net_finddc_doc
866 static void py_net_dealloc(py_net_Object
*self
)
868 talloc_free(self
->ev
);
872 static PyObject
*net_obj_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
874 PyObject
*py_creds
, *py_lp
= Py_None
;
875 const char *kwnames
[] = { "creds", "lp", "server", NULL
};
877 struct loadparm_context
*lp
;
878 const char *server_address
= NULL
;
880 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O|Oz",
881 discard_const_p(char *, kwnames
), &py_creds
, &py_lp
,
885 ret
= PyObject_New(py_net_Object
, type
);
890 /* FIXME: we really need to get a context from the caller or we may end
891 * up with 2 event contexts */
892 ret
->ev
= s4_event_context_init(NULL
);
893 ret
->mem_ctx
= talloc_new(ret
->ev
);
895 lp
= lpcfg_from_py_object(ret
->mem_ctx
, py_lp
);
901 ret
->libnet_ctx
= libnet_context_init(ret
->ev
, lp
);
902 if (ret
->libnet_ctx
== NULL
) {
903 PyErr_SetString(PyExc_RuntimeError
, "Unable to initialize net");
908 ret
->libnet_ctx
->server_address
= server_address
;
910 ret
->libnet_ctx
->cred
= cli_credentials_from_py_object(py_creds
);
911 if (ret
->libnet_ctx
->cred
== NULL
) {
912 PyErr_SetString(PyExc_TypeError
, "Expected credentials object");
917 return (PyObject
*)ret
;
921 PyTypeObject py_net_Type
= {
922 PyVarObject_HEAD_INIT(NULL
, 0)
923 .tp_name
= "net.Net",
924 .tp_basicsize
= sizeof(py_net_Object
),
925 .tp_dealloc
= (destructor
)py_net_dealloc
,
926 .tp_methods
= net_obj_methods
,
927 .tp_new
= net_obj_new
,
930 static struct PyModuleDef moduledef
= {
931 PyModuleDef_HEAD_INIT
,
936 MODULE_INIT_FUNC(net
)
940 if (PyType_Ready(&py_net_Type
) < 0)
943 m
= PyModule_Create(&moduledef
);
947 Py_INCREF(&py_net_Type
);
948 PyModule_AddObject(m
, "Net", (PyObject
*)&py_net_Type
);
949 PyModule_AddIntConstant(m
, "LIBNET_JOINDOMAIN_AUTOMATIC", LIBNET_JOINDOMAIN_AUTOMATIC
);
950 PyModule_AddIntConstant(m
, "LIBNET_JOINDOMAIN_SPECIFIED", LIBNET_JOINDOMAIN_SPECIFIED
);
951 PyModule_AddIntConstant(m
, "LIBNET_JOIN_AUTOMATIC", LIBNET_JOIN_AUTOMATIC
);
952 PyModule_AddIntConstant(m
, "LIBNET_JOIN_SPECIFIED", LIBNET_JOIN_SPECIFIED
);