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

Generated by: LCOV version 1.14