LCOV - code coverage report
Current view: top level - source4/libnet - py_net.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 236 427 55.3 %
Date: 2024-06-13 04:01:37 Functions: 12 14 85.7 %

          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             : }

Generated by: LCOV version 1.13