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

Generated by: LCOV version 1.14