2009-12-24 06:43:21 +03:00
/*
2008-04-08 07:16:07 +04:00
Unix SMB / CIFS implementation .
Samba utility functions
2011-08-10 17:15:18 +04:00
2010-04-09 00:59:16 +04:00
Copyright ( C ) Jelmer Vernooij < jelmer @ samba . org > 2008 - 2010
2009-12-24 06:43:21 +03:00
Copyright ( C ) Kamen Mazdrashki < kamen . mazdrashki @ postpath . com > 2009
2008-04-08 07:16:07 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2009-12-24 06:43:21 +03:00
2008-04-08 07:16:07 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2009-12-24 06:43:21 +03:00
2008-04-08 07:16:07 +04:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2023-11-09 13:35:56 +03:00
# include "lib/replace/system/python.h"
2017-01-23 22:34:08 +03:00
# include "python/py3compat.h"
2009-10-23 09:23:01 +04:00
# include "includes.h"
2019-05-02 21:45:14 +03:00
# include "python/modules.h"
2010-12-12 23:40:03 +03:00
# include <pyldb.h>
2013-09-19 01:27:26 +04:00
# include <pytalloc.h>
2008-04-08 07:16:07 +04:00
# include "libnet.h"
2024-05-27 10:44:38 +03:00
# include "libnet_join_proto.h"
2009-07-28 12:00:13 +04:00
# include "auth/credentials/pycredentials.h"
2008-04-08 07:16:07 +04:00
# include "libcli/security/security.h"
2008-04-14 20:43:37 +04:00
# include "lib/events/events.h"
2010-03-02 00:23:45 +03:00
# include "param/pyparam.h"
2010-08-24 09:41:40 +04:00
# include "auth/gensec/gensec.h"
2010-08-27 04:17:26 +04:00
# include "librpc/rpc/pyrpc_util.h"
2010-09-14 12:21:38 +04:00
# include "libcli/resolve/resolve.h"
2011-09-19 12:48:31 +04:00
# include "libcli/finddc.h"
# include "dsdb/samdb/samdb.h"
2012-04-10 13:09:20 +04:00
# include "py_net.h"
2013-09-19 01:27:26 +04:00
# include "librpc/rpc/pyrpc_util.h"
2017-05-17 08:05:13 +03:00
# include "libcli/drsuapi/drsuapi.h"
2008-04-08 07:16:07 +04:00
2016-11-01 02:38:48 +03:00
static void PyErr_SetDsExtendedError ( enum drsuapi_DsExtendedError ext_err , const char * error_description )
{
2019-01-23 18:15:07 +03:00
PyObject * mod = NULL ;
PyObject * error = NULL ;
mod = PyImport_ImportModule ( " samba " ) ;
if ( mod ) {
error = PyObject_GetAttrString ( mod , " DsExtendedError " ) ;
}
2016-11-01 02:38:48 +03:00
if ( error_description = = NULL ) {
switch ( ext_err ) {
/* Copied out of ndr_drsuapi.c:ndr_print_drsuapi_DsExtendedError() */
case DRSUAPI_EXOP_ERR_NONE :
error_description = " DRSUAPI_EXOP_ERR_NONE " ;
break ;
case DRSUAPI_EXOP_ERR_SUCCESS :
error_description = " DRSUAPI_EXOP_ERR_SUCCESS " ;
break ;
case DRSUAPI_EXOP_ERR_UNKNOWN_OP :
error_description = " DRSUAPI_EXOP_ERR_UNKNOWN_OP " ;
break ;
case DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER :
error_description = " DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER " ;
break ;
case DRSUAPI_EXOP_ERR_UPDATE_ERR :
error_description = " DRSUAPI_EXOP_ERR_UPDATE_ERR " ;
break ;
case DRSUAPI_EXOP_ERR_EXCEPTION :
error_description = " DRSUAPI_EXOP_ERR_EXCEPTION " ;
break ;
case DRSUAPI_EXOP_ERR_UNKNOWN_CALLER :
error_description = " DRSUAPI_EXOP_ERR_UNKNOWN_CALLER " ;
break ;
case DRSUAPI_EXOP_ERR_RID_ALLOC :
error_description = " DRSUAPI_EXOP_ERR_RID_ALLOC " ;
break ;
case DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED :
error_description = " DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED " ;
break ;
case DRSUAPI_EXOP_ERR_FMSO_PENDING_OP :
error_description = " DRSUAPI_EXOP_ERR_FMSO_PENDING_OP " ;
break ;
case DRSUAPI_EXOP_ERR_MISMATCH :
error_description = " DRSUAPI_EXOP_ERR_MISMATCH " ;
break ;
case DRSUAPI_EXOP_ERR_COULDNT_CONTACT :
error_description = " DRSUAPI_EXOP_ERR_COULDNT_CONTACT " ;
break ;
case DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES :
error_description = " DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES " ;
break ;
case DRSUAPI_EXOP_ERR_DIR_ERROR :
error_description = " DRSUAPI_EXOP_ERR_DIR_ERROR " ;
break ;
case DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS :
error_description = " DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS " ;
break ;
case DRSUAPI_EXOP_ERR_ACCESS_DENIED :
error_description = " DRSUAPI_EXOP_ERR_ACCESS_DENIED " ;
break ;
case DRSUAPI_EXOP_ERR_PARAM_ERROR :
error_description = " DRSUAPI_EXOP_ERR_PARAM_ERROR " ;
break ;
}
}
2019-01-23 18:15:07 +03:00
if ( error ) {
2019-01-28 19:57:17 +03:00
PyObject * value =
2016-11-01 02:38:48 +03:00
Py_BuildValue ( discard_const_p ( char , " (i,s) " ) ,
ext_err ,
2019-01-28 19:57:17 +03:00
error_description ) ;
PyErr_SetObject ( error , value ) ;
if ( value ) {
Py_DECREF ( value ) ;
}
Py_DECREF ( error ) ;
2019-01-23 18:15:07 +03:00
}
2016-11-01 02:38:48 +03:00
}
2011-05-16 16:55:29 +04:00
static PyObject * py_net_join_member ( py_net_Object * self , PyObject * args , PyObject * kwargs )
2008-04-08 07:16:07 +04:00
{
2011-05-16 16:55:29 +04:00
struct libnet_Join_member r ;
2011-08-08 16:31:40 +04:00
int _level = 0 ;
2008-04-08 07:16:07 +04:00
NTSTATUS status ;
PyObject * result ;
TALLOC_CTX * mem_ctx ;
2011-11-28 22:49:54 +04:00
const char * kwnames [ ] = { " domain_name " , " netbios_name " , " level " , " machinepass " , NULL } ;
2008-04-08 07:16:07 +04:00
2011-11-16 18:30:48 +04:00
ZERO_STRUCT ( r ) ;
2011-11-28 22:49:54 +04:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " ssi|z:Join " , discard_const_p ( char * , kwnames ) ,
2008-04-08 07:16:07 +04:00
& r . in . domain_name , & r . in . netbios_name ,
2011-11-28 22:49:54 +04:00
& _level ,
& r . in . account_pass ) ) {
2008-04-08 07:16:07 +04:00
return NULL ;
2011-08-08 16:31:40 +04:00
}
r . in . level = _level ;
2008-04-08 07:16:07 +04:00
2010-03-02 00:23:45 +03:00
mem_ctx = talloc_new ( self - > mem_ctx ) ;
2010-12-12 20:54:56 +03:00
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
2008-04-08 07:16:07 +04:00
2011-05-16 16:55:29 +04:00
status = libnet_Join_member ( self - > libnet_ctx , mem_ctx , & r ) ;
2008-04-08 07:16:07 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . out . error_string
? r . out . error_string
: nt_errstr ( status ) ) ;
2008-04-08 07:16:07 +04:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
2009-12-24 06:43:21 +03:00
result = Py_BuildValue ( " sss " , r . out . join_password ,
2008-04-08 07:16:07 +04:00
dom_sid_string ( mem_ctx , r . out . domain_sid ) ,
r . out . domain_name ) ;
talloc_free ( mem_ctx ) ;
return result ;
}
2011-05-16 16:55:29 +04:00
static const char py_net_join_member_doc [ ] = " join_member(domain_name, netbios_name, level) -> (join_password, domain_sid, domain_name) \n \n " \
2010-03-01 22:43:19 +03:00
" Join the domain with the specified name. " ;
2011-07-27 12:38:29 +04:00
static PyObject * py_net_change_password ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
union libnet_ChangePassword r ;
NTSTATUS status ;
2018-05-16 18:46:41 +03:00
TALLOC_CTX * mem_ctx = NULL ;
struct tevent_context * ev = NULL ;
2017-03-20 23:58:18 +03:00
const char * kwnames [ ] = { " newpassword " , " oldpassword " , " domain " , " username " , NULL } ;
2018-05-16 18:46:41 +03:00
const char * newpass = NULL ;
const char * oldpass = NULL ;
2011-07-27 12:38:29 +04:00
ZERO_STRUCT ( r ) ;
2018-12-11 18:58:44 +03:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , PYARG_STR_UNI
" | " PYARG_STR_UNI " ss:change_password " ,
2017-03-20 23:58:18 +03:00
discard_const_p ( char * , kwnames ) ,
2018-05-16 18:46:41 +03:00
" utf8 " ,
& newpass ,
" utf8 " ,
& oldpass ,
2017-03-20 23:58:18 +03:00
& r . generic . in . domain_name ,
& r . generic . in . account_name ) ) {
2011-07-27 12:38:29 +04:00
return NULL ;
}
2018-05-16 18:46:41 +03:00
r . generic . in . newpassword = newpass ;
r . generic . in . oldpassword = oldpass ;
2011-07-27 12:38:29 +04:00
r . generic . level = LIBNET_CHANGE_PASSWORD_GENERIC ;
2017-03-20 23:58:18 +03:00
if ( r . generic . in . account_name = = NULL ) {
r . generic . in . account_name
= cli_credentials_get_username ( self - > libnet_ctx - > cred ) ;
}
if ( r . generic . in . domain_name = = NULL ) {
r . generic . in . domain_name
= cli_credentials_get_domain ( self - > libnet_ctx - > cred ) ;
}
if ( r . generic . in . oldpassword = = NULL ) {
r . generic . in . oldpassword
= cli_credentials_get_password ( self - > libnet_ctx - > cred ) ;
}
2011-07-27 12:38:29 +04:00
/* FIXME: we really need to get a context from the caller or we may end
* up with 2 event contexts */
ev = s4_event_context_init ( NULL ) ;
mem_ctx = talloc_new ( ev ) ;
if ( mem_ctx = = NULL ) {
2018-05-16 21:37:28 +03:00
PyMem_Free ( discard_const_p ( char , newpass ) ) ;
PyMem_Free ( discard_const_p ( char , oldpass ) ) ;
2011-07-27 12:38:29 +04:00
PyErr_NoMemory ( ) ;
return NULL ;
}
status = libnet_ChangePassword ( self - > libnet_ctx , mem_ctx , & r ) ;
2018-05-16 21:37:28 +03:00
PyMem_Free ( discard_const_p ( char , newpass ) ) ;
PyMem_Free ( discard_const_p ( char , oldpass ) ) ;
2011-07-27 12:38:29 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . generic . out . error_string
? r . generic . out . error_string
: nt_errstr ( status ) ) ;
2018-05-16 21:37:28 +03:00
talloc_free ( mem_ctx ) ;
2011-07-27 12:38:29 +04:00
return NULL ;
}
talloc_free ( mem_ctx ) ;
Py_RETURN_NONE ;
}
static const char py_net_change_password_doc [ ] = " change_password(newpassword) -> True \n \n " \
" Change password for a user. You must supply credential with enough rights to do this. \n \n " \
" Sample usage is: \n " \
2014-10-13 03:07:41 +04:00
" net.change_password(newpassword=<new_password>) \n " ;
2011-07-27 12:38:29 +04:00
2010-03-02 00:23:45 +03:00
static PyObject * py_net_set_password ( py_net_Object * self , PyObject * args , PyObject * kwargs )
2009-12-24 06:43:21 +03:00
{
union libnet_SetPassword r ;
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
struct tevent_context * ev ;
2022-11-29 17:45:56 +03:00
const char * kwnames [ ] = { " account_name " , " domain_name " , " newpassword " , " force_samr_18 " , NULL } ;
PyObject * py_force_samr_18 = Py_False ;
2009-12-24 06:43:21 +03:00
2011-07-27 12:38:29 +04:00
ZERO_STRUCT ( r ) ;
2009-12-24 06:43:21 +03:00
r . generic . level = LIBNET_SET_PASSWORD_GENERIC ;
2022-11-29 17:45:56 +03:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " sss|O:set_password " ,
2011-07-27 12:37:14 +04:00
discard_const_p ( char * , kwnames ) ,
& r . generic . in . account_name ,
& r . generic . in . domain_name ,
2022-11-29 17:45:56 +03:00
& r . generic . in . newpassword ,
& py_force_samr_18 ) ) {
2009-12-24 06:43:21 +03:00
return NULL ;
}
2022-11-29 17:45:56 +03:00
if ( py_force_samr_18 ) {
if ( ! PyBool_Check ( py_force_samr_18 ) ) {
PyErr_SetString ( PyExc_TypeError , " Expected boolean force_samr_18 " ) ;
return NULL ;
}
if ( py_force_samr_18 = = Py_True ) {
r . generic . samr_level = LIBNET_SET_PASSWORD_SAMR_HANDLE_18 ;
}
}
2009-12-25 16:48:45 +03:00
/* FIXME: we really need to get a context from the caller or we may end
* up with 2 event contexts */
2009-12-24 06:43:21 +03:00
ev = s4_event_context_init ( NULL ) ;
2010-12-12 20:54:56 +03:00
2009-12-24 06:43:21 +03:00
mem_ctx = talloc_new ( ev ) ;
2010-12-12 20:54:56 +03:00
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
2009-12-24 06:43:21 +03:00
2010-03-02 00:23:45 +03:00
status = libnet_SetPassword ( self - > libnet_ctx , mem_ctx , & r ) ;
2009-12-24 06:43:21 +03:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . generic . out . error_string
? r . generic . out . error_string
: nt_errstr ( status ) ) ;
2009-12-24 06:43:21 +03:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
2010-03-01 22:43:19 +03:00
talloc_free ( mem_ctx ) ;
2009-12-24 06:43:21 +03:00
Py_RETURN_NONE ;
}
2010-03-01 22:43:19 +03:00
static const char py_net_set_password_doc [ ] = " set_password(account_name, domain_name, newpassword) -> True \n \n " \
2009-12-24 06:43:21 +03:00
" Set password for a user. You must supply credential with enough rights to do this. \n \n " \
" Sample usage is: \n " \
2014-10-13 03:07:41 +04:00
" net.set_password(account_name=account_name, domain_name=domain_name, newpassword=new_pass) \n " ;
2009-12-24 06:43:21 +03:00
2010-03-02 00:33:01 +03:00
static PyObject * py_net_time ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " server_name " , NULL } ;
union libnet_RemoteTOD r ;
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
char timestr [ 64 ] ;
PyObject * ret ;
struct tm * tm ;
2023-03-31 08:06:44 +03:00
size_t len ;
2010-03-02 00:33:01 +03:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " s " ,
discard_const_p ( char * , kwnames ) , & r . generic . in . server_name ) )
return NULL ;
r . generic . level = LIBNET_REMOTE_TOD_GENERIC ;
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
status = libnet_RemoteTOD ( self - > libnet_ctx , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . generic . out . error_string
? r . generic . out . error_string
: nt_errstr ( status ) ) ;
2010-03-02 00:33:01 +03:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
ZERO_STRUCT ( timestr ) ;
tm = localtime ( & r . generic . out . time ) ;
2023-03-31 08:06:44 +03:00
len = strftime ( timestr , sizeof ( timestr ) , " %c %Z " , tm ) ;
if ( len = = 0 ) {
PyErr_NoMemory ( ) ;
ret = NULL ;
} else {
ret = PyUnicode_FromStringAndSize ( timestr , ( Py_ssize_t ) len ) ;
}
2010-03-02 00:33:01 +03:00
2023-03-31 08:06:44 +03:00
talloc_free ( mem_ctx ) ;
2010-03-02 00:33:01 +03:00
return ret ;
}
static const char py_net_time_doc [ ] = " time(server_name) -> timestr \n "
" Retrieve the remote time on a server " ;
2010-03-02 01:03:41 +03:00
static PyObject * py_net_user_create ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " username " , NULL } ;
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
struct libnet_CreateUser r ;
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " s " , discard_const_p ( char * , kwnames ) ,
& r . in . user_name ) )
return NULL ;
r . in . domain_name = cli_credentials_get_domain ( self - > libnet_ctx - > cred ) ;
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
status = libnet_CreateUser ( self - > libnet_ctx , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . out . error_string
? r . out . error_string
: nt_errstr ( status ) ) ;
2010-03-02 01:03:41 +03:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
talloc_free ( mem_ctx ) ;
Py_RETURN_NONE ;
}
static const char py_net_create_user_doc [ ] = " create_user(username) \n "
" Create a new user. " ;
static PyObject * py_net_user_delete ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " username " , NULL } ;
NTSTATUS status ;
TALLOC_CTX * mem_ctx ;
struct libnet_DeleteUser r ;
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " s " , discard_const_p ( char * , kwnames ) ,
& r . in . user_name ) )
return NULL ;
r . in . domain_name = cli_credentials_get_domain ( self - > libnet_ctx - > cred ) ;
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
status = libnet_DeleteUser ( self - > libnet_ctx , mem_ctx , & r ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS_and_string ( status ,
r . out . error_string
? r . out . error_string
: nt_errstr ( status ) ) ;
2010-03-02 01:03:41 +03:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
talloc_free ( mem_ctx ) ;
Py_RETURN_NONE ;
}
static const char py_net_delete_user_doc [ ] = " delete_user(username) \n "
" Delete a user. " ;
2010-08-24 09:41:40 +04:00
struct replicate_state {
void * vampire_state ;
dcerpc_InterfaceObject * drs_pipe ;
struct libnet_BecomeDC_StoreChunk chunk ;
DATA_BLOB gensec_skey ;
struct libnet_BecomeDC_Partition partition ;
struct libnet_BecomeDC_Forest forest ;
struct libnet_BecomeDC_DestDSA dest_dsa ;
} ;
2010-08-23 05:30:22 +04:00
2010-08-24 09:41:40 +04:00
/*
setup for replicate_chunk ( ) calls
*/
static PyObject * py_net_replicate_init ( py_net_Object * self , PyObject * args , PyObject * kwargs )
2010-08-23 05:30:22 +04:00
{
2013-09-19 01:27:26 +04:00
const char * kwnames [ ] = { " samdb " , " lp " , " drspipe " , " invocation_id " , NULL } ;
PyObject * py_ldb , * py_lp , * py_drspipe , * py_invocation_id ;
2010-08-24 09:41:40 +04:00
struct ldb_context * samdb ;
struct loadparm_context * lp ;
struct replicate_state * s ;
2010-08-23 05:30:22 +04:00
NTSTATUS status ;
2013-09-19 01:27:26 +04:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " OOOO " ,
2010-08-23 05:30:22 +04:00
discard_const_p ( char * , kwnames ) ,
2013-09-19 01:27:26 +04:00
& py_ldb , & py_lp , & py_drspipe ,
& py_invocation_id ) ) {
2010-08-23 05:30:22 +04:00
return NULL ;
}
2010-08-24 09:41:40 +04:00
s = talloc_zero ( NULL , struct replicate_state ) ;
if ( ! s ) return NULL ;
2010-08-23 05:30:22 +04:00
2010-08-24 09:41:40 +04:00
lp = lpcfg_from_py_object ( s , py_lp ) ;
if ( lp = = NULL ) {
PyErr_SetString ( PyExc_TypeError , " Expected lp object " ) ;
talloc_free ( s ) ;
2010-08-23 05:30:22 +04:00
return NULL ;
}
2011-08-07 19:08:56 +04:00
samdb = pyldb_Ldb_AsLdbContext ( py_ldb ) ;
2010-08-24 09:41:40 +04:00
if ( samdb = = NULL ) {
PyErr_SetString ( PyExc_TypeError , " Expected ldb object " ) ;
talloc_free ( s ) ;
2010-08-23 05:30:22 +04:00
return NULL ;
}
2013-09-19 01:27:26 +04:00
if ( ! py_check_dcerpc_type ( py_invocation_id , " samba.dcerpc.misc " , " GUID " ) ) {
talloc_free ( s ) ;
return NULL ;
}
s - > dest_dsa . invocation_id = * pytalloc_get_type ( py_invocation_id , struct GUID ) ;
2010-08-23 05:30:22 +04:00
2010-08-24 09:41:40 +04:00
s - > drs_pipe = ( dcerpc_InterfaceObject * ) ( py_drspipe ) ;
2010-08-23 05:30:22 +04:00
2010-08-24 09:41:40 +04:00
s - > vampire_state = libnet_vampire_replicate_init ( s , samdb , lp ) ;
if ( s - > vampire_state = = NULL ) {
PyErr_SetString ( PyExc_TypeError , " Failed to initialise vampire_state " ) ;
talloc_free ( s ) ;
return NULL ;
}
status = gensec_session_key ( s - > drs_pipe - > pipe - > conn - > security_state . generic_state ,
2011-08-01 09:39:01 +04:00
s ,
2010-08-24 09:41:40 +04:00
& s - > gensec_skey ) ;
2010-08-23 05:30:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-11-01 02:38:48 +03:00
char * error_string = talloc_asprintf ( s ,
" Unable to get session key from drspipe: %s " ,
nt_errstr ( status ) ) ;
PyErr_SetNTSTATUS_and_string ( status , error_string ) ;
2010-08-24 09:41:40 +04:00
talloc_free ( s ) ;
2010-08-23 05:30:22 +04:00
return NULL ;
}
2011-08-24 07:51:01 +04:00
s - > forest . dns_name = samdb_dn_to_dns_domain ( s , ldb_get_root_basedn ( samdb ) ) ;
2011-11-15 12:45:46 +04:00
s - > forest . root_dn_str = ldb_dn_get_linearized ( ldb_get_root_basedn ( samdb ) ) ;
s - > forest . config_dn_str = ldb_dn_get_linearized ( ldb_get_config_basedn ( samdb ) ) ;
s - > forest . schema_dn_str = ldb_dn_get_linearized ( ldb_get_schema_basedn ( samdb ) ) ;
2010-09-15 12:50:09 +04:00
2010-08-24 09:41:40 +04:00
s - > chunk . gensec_skey = & s - > gensec_skey ;
s - > chunk . partition = & s - > partition ;
s - > chunk . forest = & s - > forest ;
s - > chunk . dest_dsa = & s - > dest_dsa ;
2017-02-22 12:14:10 +03:00
return pytalloc_GenericObject_steal ( s ) ;
2010-08-24 09:41:40 +04:00
}
/*
process one replication chunk
*/
static PyObject * py_net_replicate_chunk ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
2011-08-08 12:29:05 +04:00
const char * kwnames [ ] = { " state " , " level " , " ctr " ,
" schema " , " req_level " , " req " ,
NULL } ;
2011-11-23 01:06:15 +04:00
PyObject * py_state , * py_ctr , * py_schema = Py_None , * py_req = Py_None ;
2010-08-24 09:41:40 +04:00
struct replicate_state * s ;
unsigned level ;
2011-08-08 12:29:05 +04:00
unsigned req_level = 0 ;
2016-10-31 06:19:37 +03:00
WERROR ( * chunk_handler ) ( void * private_data , const struct libnet_BecomeDC_StoreChunk * c ) ;
WERROR werr ;
2016-10-31 06:25:51 +03:00
enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE ;
enum drsuapi_DsExtendedOperation exop = DRSUAPI_EXOP_NONE ;
2010-08-24 09:41:40 +04:00
2011-08-08 12:29:05 +04:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " OIO|OIO " ,
2010-08-24 09:41:40 +04:00
discard_const_p ( char * , kwnames ) ,
2011-08-08 12:29:05 +04:00
& py_state , & level , & py_ctr ,
& py_schema , & req_level , & py_req ) ) {
2010-08-24 09:41:40 +04:00
return NULL ;
}
2017-02-22 12:14:10 +03:00
s = pytalloc_get_type ( py_state , struct replicate_state ) ;
2010-08-24 09:41:40 +04:00
if ( ! s ) {
return NULL ;
}
switch ( level ) {
case 1 :
2010-08-27 04:17:26 +04:00
if ( ! py_check_dcerpc_type ( py_ctr , " samba.dcerpc.drsuapi " , " DsGetNCChangesCtr1 " ) ) {
2010-08-24 09:41:40 +04:00
return NULL ;
}
2011-08-10 17:15:18 +04:00
s - > chunk . ctr1 = pytalloc_get_ptr ( py_ctr ) ;
2016-10-31 06:25:51 +03:00
if ( s - > chunk . ctr1 - > naming_context ! = NULL ) {
s - > partition . nc = * s - > chunk . ctr1 - > naming_context ;
}
extended_ret = s - > chunk . ctr1 - > extended_ret ;
2010-08-24 09:41:40 +04:00
s - > partition . more_data = s - > chunk . ctr1 - > more_data ;
s - > partition . source_dsa_guid = s - > chunk . ctr1 - > source_dsa_guid ;
s - > partition . source_dsa_invocation_id = s - > chunk . ctr1 - > source_dsa_invocation_id ;
s - > partition . highwatermark = s - > chunk . ctr1 - > new_highwatermark ;
break ;
case 6 :
2010-08-27 04:17:26 +04:00
if ( ! py_check_dcerpc_type ( py_ctr , " samba.dcerpc.drsuapi " , " DsGetNCChangesCtr6 " ) ) {
2010-08-24 09:41:40 +04:00
return NULL ;
}
2011-08-10 17:15:18 +04:00
s - > chunk . ctr6 = pytalloc_get_ptr ( py_ctr ) ;
2016-10-31 06:25:51 +03:00
if ( s - > chunk . ctr6 - > naming_context ! = NULL ) {
s - > partition . nc = * s - > chunk . ctr6 - > naming_context ;
}
extended_ret = s - > chunk . ctr6 - > extended_ret ;
2010-08-24 09:41:40 +04:00
s - > partition . more_data = s - > chunk . ctr6 - > more_data ;
s - > partition . source_dsa_guid = s - > chunk . ctr6 - > source_dsa_guid ;
s - > partition . source_dsa_invocation_id = s - > chunk . ctr6 - > source_dsa_invocation_id ;
s - > partition . highwatermark = s - > chunk . ctr6 - > new_highwatermark ;
break ;
default :
PyErr_Format ( PyExc_TypeError , " Bad level %u in replicate_chunk " , level ) ;
return NULL ;
}
2011-08-08 12:29:05 +04:00
s - > chunk . req5 = NULL ;
s - > chunk . req8 = NULL ;
s - > chunk . req10 = NULL ;
2018-04-20 15:37:15 +03:00
if ( py_req ! = Py_None ) {
2011-08-08 12:29:05 +04:00
switch ( req_level ) {
case 0 :
break ;
case 5 :
if ( ! py_check_dcerpc_type ( py_req , " samba.dcerpc.drsuapi " , " DsGetNCChangesRequest5 " ) ) {
return NULL ;
}
s - > chunk . req5 = pytalloc_get_ptr ( py_req ) ;
2016-10-31 06:25:51 +03:00
exop = s - > chunk . req5 - > extended_op ;
2011-08-08 12:29:05 +04:00
break ;
case 8 :
if ( ! py_check_dcerpc_type ( py_req , " samba.dcerpc.drsuapi " , " DsGetNCChangesRequest8 " ) ) {
return NULL ;
}
s - > chunk . req8 = pytalloc_get_ptr ( py_req ) ;
2016-10-31 06:25:51 +03:00
exop = s - > chunk . req8 - > extended_op ;
2011-08-08 12:29:05 +04:00
break ;
case 10 :
if ( ! py_check_dcerpc_type ( py_req , " samba.dcerpc.drsuapi " , " DsGetNCChangesRequest10 " ) ) {
return NULL ;
}
s - > chunk . req10 = pytalloc_get_ptr ( py_req ) ;
2016-10-31 06:25:51 +03:00
exop = s - > chunk . req10 - > extended_op ;
2011-08-08 12:29:05 +04:00
break ;
default :
PyErr_Format ( PyExc_TypeError , " Bad req_level %u in replicate_chunk " , req_level ) ;
return NULL ;
}
}
2016-10-31 06:25:51 +03:00
if ( exop ! = DRSUAPI_EXOP_NONE & & extended_ret ! = DRSUAPI_EXOP_ERR_SUCCESS ) {
2016-11-01 02:38:48 +03:00
PyErr_SetDsExtendedError ( extended_ret , NULL ) ;
2016-10-31 06:25:51 +03:00
return NULL ;
}
2011-08-08 12:29:05 +04:00
s - > chunk . req_level = req_level ;
2010-08-24 09:41:40 +04:00
chunk_handler = libnet_vampire_cb_store_chunk ;
if ( py_schema ) {
if ( ! PyBool_Check ( py_schema ) ) {
PyErr_SetString ( PyExc_TypeError , " Expected boolean schema " ) ;
return NULL ;
}
if ( py_schema = = Py_True ) {
chunk_handler = libnet_vampire_cb_schema_chunk ;
}
}
s - > chunk . ctr_level = level ;
2016-10-31 06:19:37 +03:00
werr = chunk_handler ( s - > vampire_state , & s - > chunk ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2016-11-01 02:38:48 +03:00
char * error_string
= talloc_asprintf ( NULL ,
" Failed to process 'chunk' of DRS replicated objects: %s " ,
win_errstr ( werr ) ) ;
PyErr_SetWERROR_and_string ( werr , error_string ) ;
TALLOC_FREE ( error_string ) ;
2010-08-24 09:41:40 +04:00
return NULL ;
}
2010-08-23 05:30:22 +04:00
2010-08-28 16:18:00 +04:00
Py_RETURN_NONE ;
2010-08-23 05:30:22 +04:00
}
2010-09-14 12:21:38 +04:00
2017-05-17 08:05:13 +03:00
/*
just do the decryption of a DRS replicated attribute
*/
static PyObject * py_net_replicate_decrypt ( py_net_Object * self , PyObject * args , PyObject * kwargs )
{
const char * kwnames [ ] = { " drspipe " , " attribute " , " rid " , NULL } ;
PyObject * py_drspipe , * py_attribute ;
NTSTATUS status ;
dcerpc_InterfaceObject * drs_pipe ;
TALLOC_CTX * frame ;
TALLOC_CTX * context ;
DATA_BLOB gensec_skey ;
unsigned int rid ;
struct drsuapi_DsReplicaAttribute * attribute ;
WERROR werr ;
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " OOI " ,
discard_const_p ( char * , kwnames ) ,
& py_drspipe ,
& py_attribute , & rid ) ) {
return NULL ;
}
frame = talloc_stackframe ( ) ;
if ( ! py_check_dcerpc_type ( py_drspipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ) {
return NULL ;
}
drs_pipe = ( dcerpc_InterfaceObject * ) ( py_drspipe ) ;
status = gensec_session_key ( drs_pipe - > pipe - > conn - > security_state . generic_state ,
frame ,
& gensec_skey ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
char * error_string
= talloc_asprintf ( frame ,
" Unable to get session key from drspipe: %s " ,
nt_errstr ( status ) ) ;
PyErr_SetNTSTATUS_and_string ( status , error_string ) ;
talloc_free ( frame ) ;
return NULL ;
}
if ( ! py_check_dcerpc_type ( py_attribute , " samba.dcerpc.drsuapi " ,
" DsReplicaAttribute " ) ) {
return NULL ;
}
attribute = pytalloc_get_ptr ( py_attribute ) ;
context = pytalloc_get_mem_ctx ( py_attribute ) ;
werr = drsuapi_decrypt_attribute ( context , & gensec_skey ,
rid , 0 , attribute ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
char * error_string = talloc_asprintf ( frame ,
" Unable to get decrypt attribute: %s " ,
win_errstr ( werr ) ) ;
PyErr_SetWERROR_and_string ( werr , error_string ) ;
talloc_free ( frame ) ;
return NULL ;
}
talloc_free ( frame ) ;
Py_RETURN_NONE ;
}
2010-09-14 12:21:38 +04:00
/*
find a DC given a domain name and server type
*/
2011-11-23 01:26:06 +04:00
static PyObject * py_net_finddc ( py_net_Object * self , PyObject * args , PyObject * kwargs )
2010-09-14 12:21:38 +04:00
{
2011-11-23 01:26:06 +04:00
const char * domain = NULL , * address = NULL ;
2010-09-14 12:21:38 +04:00
unsigned server_type ;
NTSTATUS status ;
2010-09-15 12:51:09 +04:00
struct finddcs * io ;
2010-09-14 12:21:38 +04:00
TALLOC_CTX * mem_ctx ;
PyObject * ret ;
2011-11-23 01:26:06 +04:00
const char * const kwnames [ ] = { " flags " , " domain " , " address " , NULL } ;
2010-09-14 12:21:38 +04:00
2015-01-28 00:46:06 +03:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " I|zz " ,
2011-11-23 01:26:06 +04:00
discard_const_p ( char * , kwnames ) ,
& server_type , & domain , & address ) ) {
2010-09-14 12:21:38 +04:00
return NULL ;
}
mem_ctx = talloc_new ( self - > mem_ctx ) ;
2018-01-09 12:23:35 +03:00
if ( mem_ctx = = NULL ) {
PyErr_NoMemory ( ) ;
return NULL ;
}
2010-09-14 12:21:38 +04:00
2010-09-15 12:51:09 +04:00
io = talloc_zero ( mem_ctx , struct finddcs ) ;
2018-01-09 12:23:35 +03:00
if ( io = = NULL ) {
TALLOC_FREE ( mem_ctx ) ;
PyErr_NoMemory ( ) ;
return NULL ;
}
2011-11-23 01:26:06 +04:00
if ( domain ! = NULL ) {
io - > in . domain_name = domain ;
}
if ( address ! = NULL ) {
io - > in . server_address = address ;
}
2010-09-15 12:51:09 +04:00
io - > in . minimum_dc_flags = server_type ;
2010-09-14 12:21:38 +04:00
2010-09-15 12:51:09 +04:00
status = finddcs_cldap ( io , io ,
2010-09-14 12:21:38 +04:00
lpcfg_resolve_context ( self - > libnet_ctx - > lp_ctx ) , self - > ev ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
2016-11-01 02:38:48 +03:00
PyErr_SetNTSTATUS ( status ) ;
2010-09-14 12:21:38 +04:00
talloc_free ( mem_ctx ) ;
return NULL ;
}
2010-09-15 12:51:09 +04:00
ret = py_return_ndr_struct ( " samba.dcerpc.nbt " , " NETLOGON_SAM_LOGON_RESPONSE_EX " ,
io , & io - > out . netlogon . data . nt5_ex ) ;
2010-09-14 12:21:38 +04:00
talloc_free ( mem_ctx ) ;
2010-09-15 12:51:09 +04:00
2010-09-14 12:21:38 +04:00
return ret ;
}
2010-08-24 09:41:40 +04:00
static const char py_net_replicate_init_doc [ ] = " replicate_init(samdb, lp, drspipe) \n "
" Setup for replicate_chunk calls. " ;
static const char py_net_replicate_chunk_doc [ ] = " replicate_chunk(state, level, ctr, schema) \n "
" Process replication for one chunk " ;
2010-08-23 05:30:22 +04:00
2017-05-17 08:05:13 +03:00
static const char py_net_replicate_decrypt_doc [ ] = " replicate_decrypt(drs, attribute, rid) \n "
" Decrypt (in place) a DsReplicaAttribute replicated with drs.GetNCChanges() " ;
2011-11-23 01:26:06 +04:00
static const char py_net_finddc_doc [ ] = " finddc(flags=server_type, domain=None, address=None) \n "
" 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 " ;
2010-09-14 12:21:38 +04:00
2010-03-02 00:23:45 +03:00
static PyMethodDef net_obj_methods [ ] = {
2019-05-02 21:45:14 +03:00
{
. ml_name = " join_member " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_join_member ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_join_member_doc
} ,
{
. ml_name = " change_password " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_change_password ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_change_password_doc
} ,
{
. ml_name = " set_password " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_set_password ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_set_password_doc
} ,
{
. ml_name = " time " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , py_net_time ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_time_doc
} ,
{
. ml_name = " create_user " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_user_create ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_create_user_doc
} ,
{
. ml_name = " delete_user " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_user_delete ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_delete_user_doc
} ,
{
. ml_name = " replicate_init " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_replicate_init ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_replicate_init_doc
} ,
{
. ml_name = " replicate_chunk " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_replicate_chunk ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_replicate_chunk_doc
} ,
{
. ml_name = " replicate_decrypt " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_replicate_decrypt ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_replicate_decrypt_doc
} ,
{
. ml_name = " finddc " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction ,
py_net_finddc ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = py_net_finddc_doc
} ,
{ . ml_name = NULL }
2010-03-02 00:23:45 +03:00
} ;
static void py_net_dealloc ( py_net_Object * self )
{
2020-11-03 00:42:29 +03:00
talloc_free ( self - > ev ) ;
2010-12-29 17:58:12 +03:00
PyObject_Del ( self ) ;
2010-03-02 00:23:45 +03:00
}
static PyObject * net_obj_new ( PyTypeObject * type , PyObject * args , PyObject * kwargs )
{
PyObject * py_creds , * py_lp = Py_None ;
2010-09-24 06:52:19 +04:00
const char * kwnames [ ] = { " creds " , " lp " , " server " , NULL } ;
2010-03-02 00:23:45 +03:00
py_net_Object * ret ;
struct loadparm_context * lp ;
2010-09-24 06:52:19 +04:00
const char * server_address = NULL ;
2010-03-02 00:23:45 +03:00
2010-09-24 06:52:19 +04:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " O|Oz " ,
discard_const_p ( char * , kwnames ) , & py_creds , & py_lp ,
& server_address ) )
2010-03-02 00:23:45 +03:00
return NULL ;
ret = PyObject_New ( py_net_Object , type ) ;
if ( ret = = NULL ) {
return NULL ;
}
/* FIXME: we really need to get a context from the caller or we may end
* up with 2 event contexts */
ret - > ev = s4_event_context_init ( NULL ) ;
ret - > mem_ctx = talloc_new ( ret - > ev ) ;
2010-07-16 08:32:42 +04:00
lp = lpcfg_from_py_object ( ret - > mem_ctx , py_lp ) ;
2010-03-02 00:23:45 +03:00
if ( lp = = NULL ) {
Py_DECREF ( ret ) ;
return NULL ;
}
ret - > libnet_ctx = libnet_context_init ( ret - > ev , lp ) ;
if ( ret - > libnet_ctx = = NULL ) {
PyErr_SetString ( PyExc_RuntimeError , " Unable to initialize net " ) ;
Py_DECREF ( ret ) ;
return NULL ;
}
2010-09-24 06:52:19 +04:00
ret - > libnet_ctx - > server_address = server_address ;
2010-03-02 00:23:45 +03:00
ret - > libnet_ctx - > cred = cli_credentials_from_py_object ( py_creds ) ;
if ( ret - > libnet_ctx - > cred = = NULL ) {
PyErr_SetString ( PyExc_TypeError , " Expected credentials object " ) ;
Py_DECREF ( ret ) ;
return NULL ;
}
return ( PyObject * ) ret ;
}
PyTypeObject py_net_Type = {
2017-01-23 22:34:08 +03:00
PyVarObject_HEAD_INIT ( NULL , 0 )
2010-03-02 00:23:45 +03:00
. tp_name = " net.Net " ,
. tp_basicsize = sizeof ( py_net_Object ) ,
. tp_dealloc = ( destructor ) py_net_dealloc ,
. tp_methods = net_obj_methods ,
. tp_new = net_obj_new ,
2008-04-08 07:16:07 +04:00
} ;
2017-01-23 22:34:08 +03:00
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT ,
. m_name = " net " ,
. m_size = - 1 ,
} ;
MODULE_INIT_FUNC ( net )
2008-04-08 07:16:07 +04:00
{
2010-03-02 00:23:45 +03:00
PyObject * m ;
2010-04-09 00:59:16 +04:00
if ( PyType_Ready ( & py_net_Type ) < 0 )
2017-01-23 22:34:08 +03:00
return NULL ;
2010-04-09 00:59:16 +04:00
2017-01-23 22:34:08 +03:00
m = PyModule_Create ( & moduledef ) ;
2010-03-02 00:23:45 +03:00
if ( m = = NULL )
2017-01-23 22:34:08 +03:00
return NULL ;
2010-03-02 00:23:45 +03:00
Py_INCREF ( & py_net_Type ) ;
PyModule_AddObject ( m , " Net " , ( PyObject * ) & py_net_Type ) ;
2017-01-23 22:34:08 +03:00
PyModule_AddIntConstant ( m , " LIBNET_JOINDOMAIN_AUTOMATIC " , LIBNET_JOINDOMAIN_AUTOMATIC ) ;
PyModule_AddIntConstant ( m , " LIBNET_JOINDOMAIN_SPECIFIED " , LIBNET_JOINDOMAIN_SPECIFIED ) ;
PyModule_AddIntConstant ( m , " LIBNET_JOIN_AUTOMATIC " , LIBNET_JOIN_AUTOMATIC ) ;
PyModule_AddIntConstant ( m , " LIBNET_JOIN_SPECIFIED " , LIBNET_JOIN_SPECIFIED ) ;
return m ;
2008-04-08 07:16:07 +04:00
}