| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 | Samba utility functions
|
|---|
| 4 | Copyright (C) Jelmer Vernooij <[email protected]> 2008-2010
|
|---|
| 5 | Copyright (C) Kamen Mazdrashki <[email protected]> 2009
|
|---|
| 6 |
|
|---|
| 7 | This program is free software; you can redistribute it and/or modify
|
|---|
| 8 | it under the terms of the GNU General Public License as published by
|
|---|
| 9 | the Free Software Foundation; either version 3 of the License, or
|
|---|
| 10 | (at your option) any later version.
|
|---|
| 11 |
|
|---|
| 12 | This program is distributed in the hope that it will be useful,
|
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 15 | GNU General Public License for more details.
|
|---|
| 16 |
|
|---|
| 17 | You should have received a copy of the GNU General Public License
|
|---|
| 18 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|---|
| 19 | */
|
|---|
| 20 |
|
|---|
| 21 | #include <Python.h>
|
|---|
| 22 | #include "includes.h"
|
|---|
| 23 | #include <ldb.h>
|
|---|
| 24 | #include <pyldb.h>
|
|---|
| 25 | #include "libnet.h"
|
|---|
| 26 | #include "auth/credentials/pycredentials.h"
|
|---|
| 27 | #include "libcli/security/security.h"
|
|---|
| 28 | #include "lib/events/events.h"
|
|---|
| 29 | #include "param/pyparam.h"
|
|---|
| 30 | #include "auth/gensec/gensec.h"
|
|---|
| 31 | #include "librpc/rpc/pyrpc_util.h"
|
|---|
| 32 | #include "libcli/finddc.h"
|
|---|
| 33 | #include "libcli/resolve/resolve.h"
|
|---|
| 34 |
|
|---|
| 35 | void initnet(void);
|
|---|
| 36 |
|
|---|
| 37 | typedef struct {
|
|---|
| 38 | PyObject_HEAD
|
|---|
| 39 | TALLOC_CTX *mem_ctx;
|
|---|
| 40 | struct libnet_context *libnet_ctx;
|
|---|
| 41 | struct tevent_context *ev;
|
|---|
| 42 | } py_net_Object;
|
|---|
| 43 |
|
|---|
| 44 | static PyObject *py_net_join(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 45 | {
|
|---|
| 46 | struct libnet_Join r;
|
|---|
| 47 | NTSTATUS status;
|
|---|
| 48 | PyObject *result;
|
|---|
| 49 | TALLOC_CTX *mem_ctx;
|
|---|
| 50 | const char *kwnames[] = { "domain_name", "netbios_name", "join_type", "level", NULL };
|
|---|
| 51 |
|
|---|
| 52 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssii:Join", discard_const_p(char *, kwnames),
|
|---|
| 53 | &r.in.domain_name, &r.in.netbios_name,
|
|---|
| 54 | &r.in.join_type, &r.in.level))
|
|---|
| 55 | return NULL;
|
|---|
| 56 |
|
|---|
| 57 | mem_ctx = talloc_new(self->mem_ctx);
|
|---|
| 58 | if (mem_ctx == NULL) {
|
|---|
| 59 | PyErr_NoMemory();
|
|---|
| 60 | return NULL;
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | status = libnet_Join(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 64 | if (NT_STATUS_IS_ERR(status)) {
|
|---|
| 65 | PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
|
|---|
| 66 | talloc_free(mem_ctx);
|
|---|
| 67 | return NULL;
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | result = Py_BuildValue("sss", r.out.join_password,
|
|---|
| 71 | dom_sid_string(mem_ctx, r.out.domain_sid),
|
|---|
| 72 | r.out.domain_name);
|
|---|
| 73 |
|
|---|
| 74 | talloc_free(mem_ctx);
|
|---|
| 75 |
|
|---|
| 76 | return result;
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | static const char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \
|
|---|
| 80 | "Join the domain with the specified name.";
|
|---|
| 81 |
|
|---|
| 82 | static PyObject *py_net_set_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 83 | {
|
|---|
| 84 | union libnet_SetPassword r;
|
|---|
| 85 | NTSTATUS status;
|
|---|
| 86 | PyObject *py_creds;
|
|---|
| 87 | TALLOC_CTX *mem_ctx;
|
|---|
| 88 | struct tevent_context *ev;
|
|---|
| 89 | const char *kwnames[] = { "account_name", "domain_name", "newpassword", "credentials", NULL };
|
|---|
| 90 |
|
|---|
| 91 | r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
|
|---|
| 92 |
|
|---|
| 93 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssO:set_password", discard_const_p(char *, kwnames),
|
|---|
| 94 | &r.generic.in.account_name, &r.generic.in.domain_name,
|
|---|
| 95 | &r.generic.in.newpassword, &py_creds)) {
|
|---|
| 96 | return NULL;
|
|---|
| 97 | }
|
|---|
| 98 |
|
|---|
| 99 | /* FIXME: we really need to get a context from the caller or we may end
|
|---|
| 100 | * up with 2 event contexts */
|
|---|
| 101 | ev = s4_event_context_init(NULL);
|
|---|
| 102 |
|
|---|
| 103 | mem_ctx = talloc_new(ev);
|
|---|
| 104 | if (mem_ctx == NULL) {
|
|---|
| 105 | PyErr_NoMemory();
|
|---|
| 106 | return NULL;
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | status = libnet_SetPassword(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 110 | if (NT_STATUS_IS_ERR(status)) {
|
|---|
| 111 | PyErr_SetString(PyExc_RuntimeError,
|
|---|
| 112 | r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
|
|---|
| 113 | talloc_free(mem_ctx);
|
|---|
| 114 | return NULL;
|
|---|
| 115 | }
|
|---|
| 116 |
|
|---|
| 117 | talloc_free(mem_ctx);
|
|---|
| 118 |
|
|---|
| 119 | Py_RETURN_NONE;
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 | static const char py_net_set_password_doc[] = "set_password(account_name, domain_name, newpassword) -> True\n\n" \
|
|---|
| 123 | "Set password for a user. You must supply credential with enough rights to do this.\n\n" \
|
|---|
| 124 | "Sample usage is:\n" \
|
|---|
| 125 | "net.set_password(account_name=<account_name>,\n" \
|
|---|
| 126 | " domain_name=domain_name,\n" \
|
|---|
| 127 | " newpassword=new_pass)\n";
|
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 | static PyObject *py_net_export_keytab(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 131 | {
|
|---|
| 132 | struct libnet_export_keytab r;
|
|---|
| 133 | TALLOC_CTX *mem_ctx;
|
|---|
| 134 | const char *kwnames[] = { "keytab", NULL };
|
|---|
| 135 | NTSTATUS status;
|
|---|
| 136 |
|
|---|
| 137 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:export_keytab", discard_const_p(char *, kwnames),
|
|---|
| 138 | &r.in.keytab_name)) {
|
|---|
| 139 | return NULL;
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | mem_ctx = talloc_new(self->mem_ctx);
|
|---|
| 143 | if (mem_ctx == NULL) {
|
|---|
| 144 | PyErr_NoMemory();
|
|---|
| 145 | return NULL;
|
|---|
| 146 | }
|
|---|
| 147 |
|
|---|
| 148 | status = libnet_export_keytab(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 149 | if (NT_STATUS_IS_ERR(status)) {
|
|---|
| 150 | PyErr_SetString(PyExc_RuntimeError,
|
|---|
| 151 | r.out.error_string?r.out.error_string:nt_errstr(status));
|
|---|
| 152 | talloc_free(mem_ctx);
|
|---|
| 153 | return NULL;
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 | talloc_free(mem_ctx);
|
|---|
| 157 |
|
|---|
| 158 | Py_RETURN_NONE;
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | static const char py_net_export_keytab_doc[] = "export_keytab(keytab, name)\n\n"
|
|---|
| 162 | "Export the DC keytab to a keytab file.";
|
|---|
| 163 |
|
|---|
| 164 | static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 165 | {
|
|---|
| 166 | const char *kwnames[] = { "server_name", NULL };
|
|---|
| 167 | union libnet_RemoteTOD r;
|
|---|
| 168 | NTSTATUS status;
|
|---|
| 169 | TALLOC_CTX *mem_ctx;
|
|---|
| 170 | char timestr[64];
|
|---|
| 171 | PyObject *ret;
|
|---|
| 172 | struct tm *tm;
|
|---|
| 173 |
|
|---|
| 174 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
|
|---|
| 175 | discard_const_p(char *, kwnames), &r.generic.in.server_name))
|
|---|
| 176 | return NULL;
|
|---|
| 177 |
|
|---|
| 178 | r.generic.level = LIBNET_REMOTE_TOD_GENERIC;
|
|---|
| 179 |
|
|---|
| 180 | mem_ctx = talloc_new(NULL);
|
|---|
| 181 | if (mem_ctx == NULL) {
|
|---|
| 182 | PyErr_NoMemory();
|
|---|
| 183 | return NULL;
|
|---|
| 184 | }
|
|---|
| 185 |
|
|---|
| 186 | status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 187 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 188 | PyErr_SetString(PyExc_RuntimeError,
|
|---|
| 189 | r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
|
|---|
| 190 | talloc_free(mem_ctx);
|
|---|
| 191 | return NULL;
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | ZERO_STRUCT(timestr);
|
|---|
| 195 | tm = localtime(&r.generic.out.time);
|
|---|
| 196 | strftime(timestr, sizeof(timestr)-1, "%c %Z",tm);
|
|---|
| 197 |
|
|---|
| 198 | ret = PyString_FromString(timestr);
|
|---|
| 199 |
|
|---|
| 200 | talloc_free(mem_ctx);
|
|---|
| 201 |
|
|---|
| 202 | return ret;
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
|
|---|
| 206 | "Retrieve the remote time on a server";
|
|---|
| 207 |
|
|---|
| 208 | static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 209 | {
|
|---|
| 210 | const char *kwnames[] = { "username", NULL };
|
|---|
| 211 | NTSTATUS status;
|
|---|
| 212 | TALLOC_CTX *mem_ctx;
|
|---|
| 213 | struct libnet_CreateUser r;
|
|---|
| 214 |
|
|---|
| 215 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
|
|---|
| 216 | &r.in.user_name))
|
|---|
| 217 | return NULL;
|
|---|
| 218 |
|
|---|
| 219 | r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
|
|---|
| 220 |
|
|---|
| 221 | mem_ctx = talloc_new(NULL);
|
|---|
| 222 | if (mem_ctx == NULL) {
|
|---|
| 223 | PyErr_NoMemory();
|
|---|
| 224 | return NULL;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 228 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 229 | PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
|
|---|
| 230 | talloc_free(mem_ctx);
|
|---|
| 231 | return NULL;
|
|---|
| 232 | }
|
|---|
| 233 |
|
|---|
| 234 | talloc_free(mem_ctx);
|
|---|
| 235 |
|
|---|
| 236 | Py_RETURN_NONE;
|
|---|
| 237 | }
|
|---|
| 238 |
|
|---|
| 239 | static const char py_net_create_user_doc[] = "create_user(username)\n"
|
|---|
| 240 | "Create a new user.";
|
|---|
| 241 |
|
|---|
| 242 | static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 243 | {
|
|---|
| 244 | const char *kwnames[] = { "username", NULL };
|
|---|
| 245 | NTSTATUS status;
|
|---|
| 246 | TALLOC_CTX *mem_ctx;
|
|---|
| 247 | struct libnet_DeleteUser r;
|
|---|
| 248 |
|
|---|
| 249 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames),
|
|---|
| 250 | &r.in.user_name))
|
|---|
| 251 | return NULL;
|
|---|
| 252 |
|
|---|
| 253 | r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
|
|---|
| 254 |
|
|---|
| 255 | mem_ctx = talloc_new(NULL);
|
|---|
| 256 | if (mem_ctx == NULL) {
|
|---|
| 257 | PyErr_NoMemory();
|
|---|
| 258 | return NULL;
|
|---|
| 259 | }
|
|---|
| 260 |
|
|---|
| 261 | status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 262 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 263 | PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
|
|---|
| 264 | talloc_free(mem_ctx);
|
|---|
| 265 | return NULL;
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 | talloc_free(mem_ctx);
|
|---|
| 269 |
|
|---|
| 270 | Py_RETURN_NONE;
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 | static const char py_net_delete_user_doc[] = "delete_user(username)\n"
|
|---|
| 274 | "Delete a user.";
|
|---|
| 275 |
|
|---|
| 276 | static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
|
|---|
| 277 | {
|
|---|
| 278 | PyObject *mod_security, *dom_sid_Type;
|
|---|
| 279 |
|
|---|
| 280 | mod_security = PyImport_ImportModule("samba.dcerpc.security");
|
|---|
| 281 | if (mod_security == NULL)
|
|---|
| 282 | return NULL;
|
|---|
| 283 |
|
|---|
| 284 | dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
|
|---|
| 285 | if (dom_sid_Type == NULL)
|
|---|
| 286 | return NULL;
|
|---|
| 287 |
|
|---|
| 288 | return py_talloc_reference((PyTypeObject *)dom_sid_Type, sid);
|
|---|
| 289 | }
|
|---|
| 290 |
|
|---|
| 291 | static PyObject *py_net_vampire(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 292 | {
|
|---|
| 293 | const char *kwnames[] = { "domain", "target_dir", NULL };
|
|---|
| 294 | NTSTATUS status;
|
|---|
| 295 | TALLOC_CTX *mem_ctx;
|
|---|
| 296 | PyObject *ret;
|
|---|
| 297 | struct libnet_Vampire r;
|
|---|
| 298 |
|
|---|
| 299 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", discard_const_p(char *, kwnames),
|
|---|
| 300 | &r.in.domain_name, &r.in.targetdir)) {
|
|---|
| 301 | return NULL;
|
|---|
| 302 | }
|
|---|
| 303 |
|
|---|
| 304 | r.in.netbios_name = lpcfg_netbios_name(self->libnet_ctx->lp_ctx);
|
|---|
| 305 | r.out.error_string = NULL;
|
|---|
| 306 |
|
|---|
| 307 | mem_ctx = talloc_new(NULL);
|
|---|
| 308 | if (mem_ctx == NULL) {
|
|---|
| 309 | PyErr_NoMemory();
|
|---|
| 310 | return NULL;
|
|---|
| 311 | }
|
|---|
| 312 |
|
|---|
| 313 | status = libnet_Vampire(self->libnet_ctx, mem_ctx, &r);
|
|---|
| 314 |
|
|---|
| 315 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 316 | PyErr_SetString(PyExc_RuntimeError,
|
|---|
| 317 | r.out.error_string ? r.out.error_string : nt_errstr(status));
|
|---|
| 318 | talloc_free(mem_ctx);
|
|---|
| 319 | return NULL;
|
|---|
| 320 | }
|
|---|
| 321 |
|
|---|
| 322 | ret = Py_BuildValue("(sO)", r.out.domain_name, py_dom_sid_FromSid(r.out.domain_sid));
|
|---|
| 323 |
|
|---|
| 324 | talloc_free(mem_ctx);
|
|---|
| 325 |
|
|---|
| 326 | return ret;
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | struct replicate_state {
|
|---|
| 330 | void *vampire_state;
|
|---|
| 331 | dcerpc_InterfaceObject *drs_pipe;
|
|---|
| 332 | struct libnet_BecomeDC_StoreChunk chunk;
|
|---|
| 333 | DATA_BLOB gensec_skey;
|
|---|
| 334 | struct libnet_BecomeDC_Partition partition;
|
|---|
| 335 | struct libnet_BecomeDC_Forest forest;
|
|---|
| 336 | struct libnet_BecomeDC_DestDSA dest_dsa;
|
|---|
| 337 | };
|
|---|
| 338 |
|
|---|
| 339 | /*
|
|---|
| 340 | setup for replicate_chunk() calls
|
|---|
| 341 | */
|
|---|
| 342 | static PyObject *py_net_replicate_init(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 343 | {
|
|---|
| 344 | const char *kwnames[] = { "samdb", "lp", "drspipe", NULL };
|
|---|
| 345 | PyObject *py_ldb, *py_lp, *py_drspipe;
|
|---|
| 346 | struct ldb_context *samdb;
|
|---|
| 347 | struct loadparm_context *lp;
|
|---|
| 348 | struct replicate_state *s;
|
|---|
| 349 | NTSTATUS status;
|
|---|
| 350 |
|
|---|
| 351 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO",
|
|---|
| 352 | discard_const_p(char *, kwnames),
|
|---|
| 353 | &py_ldb, &py_lp, &py_drspipe)) {
|
|---|
| 354 | return NULL;
|
|---|
| 355 | }
|
|---|
| 356 |
|
|---|
| 357 | s = talloc_zero(NULL, struct replicate_state);
|
|---|
| 358 | if (!s) return NULL;
|
|---|
| 359 |
|
|---|
| 360 | lp = lpcfg_from_py_object(s, py_lp);
|
|---|
| 361 | if (lp == NULL) {
|
|---|
| 362 | PyErr_SetString(PyExc_TypeError, "Expected lp object");
|
|---|
| 363 | talloc_free(s);
|
|---|
| 364 | return NULL;
|
|---|
| 365 | }
|
|---|
| 366 |
|
|---|
| 367 | samdb = PyLdb_AsLdbContext(py_ldb);
|
|---|
| 368 | if (samdb == NULL) {
|
|---|
| 369 | PyErr_SetString(PyExc_TypeError, "Expected ldb object");
|
|---|
| 370 | talloc_free(s);
|
|---|
| 371 | return NULL;
|
|---|
| 372 | }
|
|---|
| 373 |
|
|---|
| 374 | s->drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);
|
|---|
| 375 |
|
|---|
| 376 | s->vampire_state = libnet_vampire_replicate_init(s, samdb, lp);
|
|---|
| 377 | if (s->vampire_state == NULL) {
|
|---|
| 378 | PyErr_SetString(PyExc_TypeError, "Failed to initialise vampire_state");
|
|---|
| 379 | talloc_free(s);
|
|---|
| 380 | return NULL;
|
|---|
| 381 | }
|
|---|
| 382 |
|
|---|
| 383 | status = gensec_session_key(s->drs_pipe->pipe->conn->security_state.generic_state,
|
|---|
| 384 | &s->gensec_skey);
|
|---|
| 385 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 386 | PyErr_Format(PyExc_RuntimeError, "Unable to get session key from drspipe: %s",
|
|---|
| 387 | nt_errstr(status));
|
|---|
| 388 | talloc_free(s);
|
|---|
| 389 | return NULL;
|
|---|
| 390 | }
|
|---|
| 391 |
|
|---|
| 392 | s->forest.dns_name = lpcfg_dnsdomain(lp);
|
|---|
| 393 |
|
|---|
| 394 | s->chunk.gensec_skey = &s->gensec_skey;
|
|---|
| 395 | s->chunk.partition = &s->partition;
|
|---|
| 396 | s->chunk.forest = &s->forest;
|
|---|
| 397 | s->chunk.dest_dsa = &s->dest_dsa;
|
|---|
| 398 |
|
|---|
| 399 | return PyCObject_FromTallocPtr(s);
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 |
|
|---|
| 403 | /*
|
|---|
| 404 | process one replication chunk
|
|---|
| 405 | */
|
|---|
| 406 | static PyObject *py_net_replicate_chunk(py_net_Object *self, PyObject *args, PyObject *kwargs)
|
|---|
| 407 | {
|
|---|
| 408 | const char *kwnames[] = { "state", "level", "ctr", "schema", NULL };
|
|---|
| 409 | PyObject *py_state, *py_ctr, *py_schema;
|
|---|
| 410 | struct replicate_state *s;
|
|---|
| 411 | unsigned level;
|
|---|
| 412 | NTSTATUS (*chunk_handler)(void *private_data, const struct libnet_BecomeDC_StoreChunk *c);
|
|---|
| 413 | NTSTATUS status;
|
|---|
| 414 |
|
|---|
| 415 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OIO|O",
|
|---|
| 416 | discard_const_p(char *, kwnames),
|
|---|
| 417 | &py_state, &level, &py_ctr, &py_schema)) {
|
|---|
| 418 | return NULL;
|
|---|
| 419 | }
|
|---|
| 420 |
|
|---|
| 421 | s = talloc_get_type(PyCObject_AsVoidPtr(py_state), struct replicate_state);
|
|---|
| 422 | if (!s) {
|
|---|
| 423 | PyErr_SetString(PyExc_TypeError, "Expected replication_state");
|
|---|
| 424 | return NULL;
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | switch (level) {
|
|---|
| 428 | case 1:
|
|---|
| 429 | if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr1")) {
|
|---|
| 430 | return NULL;
|
|---|
| 431 | }
|
|---|
| 432 | s->chunk.ctr1 = py_talloc_get_ptr(py_ctr);
|
|---|
| 433 | s->partition.nc = *s->chunk.ctr1->naming_context;
|
|---|
| 434 | s->partition.more_data = s->chunk.ctr1->more_data;
|
|---|
| 435 | s->partition.source_dsa_guid = s->chunk.ctr1->source_dsa_guid;
|
|---|
| 436 | s->partition.source_dsa_invocation_id = s->chunk.ctr1->source_dsa_invocation_id;
|
|---|
| 437 | s->partition.highwatermark = s->chunk.ctr1->new_highwatermark;
|
|---|
| 438 | break;
|
|---|
| 439 | case 6:
|
|---|
| 440 | if (!py_check_dcerpc_type(py_ctr, "samba.dcerpc.drsuapi", "DsGetNCChangesCtr6")) {
|
|---|
| 441 | return NULL;
|
|---|
| 442 | }
|
|---|
| 443 | s->chunk.ctr6 = py_talloc_get_ptr(py_ctr);
|
|---|
| 444 | s->partition.nc = *s->chunk.ctr6->naming_context;
|
|---|
| 445 | s->partition.more_data = s->chunk.ctr6->more_data;
|
|---|
| 446 | s->partition.source_dsa_guid = s->chunk.ctr6->source_dsa_guid;
|
|---|
| 447 | s->partition.source_dsa_invocation_id = s->chunk.ctr6->source_dsa_invocation_id;
|
|---|
| 448 | s->partition.highwatermark = s->chunk.ctr6->new_highwatermark;
|
|---|
| 449 | break;
|
|---|
| 450 | default:
|
|---|
| 451 | PyErr_Format(PyExc_TypeError, "Bad level %u in replicate_chunk", level);
|
|---|
| 452 | return NULL;
|
|---|
| 453 | }
|
|---|
| 454 |
|
|---|
| 455 | chunk_handler = libnet_vampire_cb_store_chunk;
|
|---|
| 456 | if (py_schema) {
|
|---|
| 457 | if (!PyBool_Check(py_schema)) {
|
|---|
| 458 | PyErr_SetString(PyExc_TypeError, "Expected boolean schema");
|
|---|
| 459 | return NULL;
|
|---|
| 460 | }
|
|---|
| 461 | if (py_schema == Py_True) {
|
|---|
| 462 | chunk_handler = libnet_vampire_cb_schema_chunk;
|
|---|
| 463 | }
|
|---|
| 464 | }
|
|---|
| 465 |
|
|---|
| 466 | s->chunk.ctr_level = level;
|
|---|
| 467 |
|
|---|
| 468 | status = chunk_handler(s->vampire_state, &s->chunk);
|
|---|
| 469 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 470 | PyErr_Format(PyExc_TypeError, "Failed to process chunk: %s", nt_errstr(status));
|
|---|
| 471 | return NULL;
|
|---|
| 472 | }
|
|---|
| 473 |
|
|---|
| 474 | Py_RETURN_NONE;
|
|---|
| 475 | }
|
|---|
| 476 |
|
|---|
| 477 |
|
|---|
| 478 | /*
|
|---|
| 479 | find a DC given a domain name and server type
|
|---|
| 480 | */
|
|---|
| 481 | static PyObject *py_net_finddc(py_net_Object *self, PyObject *args)
|
|---|
| 482 | {
|
|---|
| 483 | const char *domain_name;
|
|---|
| 484 | unsigned server_type;
|
|---|
| 485 | NTSTATUS status;
|
|---|
| 486 | struct finddcs *io;
|
|---|
| 487 | TALLOC_CTX *mem_ctx;
|
|---|
| 488 | PyObject *ret;
|
|---|
| 489 |
|
|---|
| 490 | if (!PyArg_ParseTuple(args, "sI", &domain_name, &server_type)) {
|
|---|
| 491 | return NULL;
|
|---|
| 492 | }
|
|---|
| 493 |
|
|---|
| 494 | mem_ctx = talloc_new(self->mem_ctx);
|
|---|
| 495 |
|
|---|
| 496 | io = talloc_zero(mem_ctx, struct finddcs);
|
|---|
| 497 | io->in.domain_name = domain_name;
|
|---|
| 498 | io->in.minimum_dc_flags = server_type;
|
|---|
| 499 |
|
|---|
| 500 | status = finddcs_cldap(io, io,
|
|---|
| 501 | lpcfg_resolve_context(self->libnet_ctx->lp_ctx), self->ev);
|
|---|
| 502 | if (NT_STATUS_IS_ERR(status)) {
|
|---|
| 503 | PyErr_SetString(PyExc_RuntimeError, nt_errstr(status));
|
|---|
| 504 | talloc_free(mem_ctx);
|
|---|
| 505 | return NULL;
|
|---|
| 506 | }
|
|---|
| 507 |
|
|---|
| 508 | ret = py_return_ndr_struct("samba.dcerpc.nbt", "NETLOGON_SAM_LOGON_RESPONSE_EX",
|
|---|
| 509 | io, &io->out.netlogon.data.nt5_ex);
|
|---|
| 510 | talloc_free(mem_ctx);
|
|---|
| 511 |
|
|---|
| 512 | return ret;
|
|---|
| 513 | }
|
|---|
| 514 |
|
|---|
| 515 |
|
|---|
| 516 | static const char py_net_vampire_doc[] = "vampire(domain, target_dir=None)\n"
|
|---|
| 517 | "Vampire a domain.";
|
|---|
| 518 |
|
|---|
| 519 | static const char py_net_replicate_init_doc[] = "replicate_init(samdb, lp, drspipe)\n"
|
|---|
| 520 | "Setup for replicate_chunk calls.";
|
|---|
| 521 |
|
|---|
| 522 | static const char py_net_replicate_chunk_doc[] = "replicate_chunk(state, level, ctr, schema)\n"
|
|---|
| 523 | "Process replication for one chunk";
|
|---|
| 524 |
|
|---|
| 525 | static const char py_net_finddc_doc[] = "finddc(domain, server_type)\n"
|
|---|
| 526 | "find a DC with the specified server_type bits. Return the DNS name";
|
|---|
| 527 |
|
|---|
| 528 | static PyMethodDef net_obj_methods[] = {
|
|---|
| 529 | {"join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
|
|---|
| 530 | {"set_password", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
|
|---|
| 531 | {"export_keytab", (PyCFunction)py_net_export_keytab, METH_VARARGS|METH_KEYWORDS, py_net_export_keytab_doc},
|
|---|
| 532 | {"time", (PyCFunction)py_net_time, METH_VARARGS|METH_KEYWORDS, py_net_time_doc},
|
|---|
| 533 | {"create_user", (PyCFunction)py_net_user_create, METH_VARARGS|METH_KEYWORDS, py_net_create_user_doc},
|
|---|
| 534 | {"delete_user", (PyCFunction)py_net_user_delete, METH_VARARGS|METH_KEYWORDS, py_net_delete_user_doc},
|
|---|
| 535 | {"vampire", (PyCFunction)py_net_vampire, METH_VARARGS|METH_KEYWORDS, py_net_vampire_doc},
|
|---|
| 536 | {"replicate_init", (PyCFunction)py_net_replicate_init, METH_VARARGS|METH_KEYWORDS, py_net_replicate_init_doc},
|
|---|
| 537 | {"replicate_chunk", (PyCFunction)py_net_replicate_chunk, METH_VARARGS|METH_KEYWORDS, py_net_replicate_chunk_doc},
|
|---|
| 538 | {"finddc", (PyCFunction)py_net_finddc, METH_VARARGS, py_net_finddc_doc},
|
|---|
| 539 | { NULL }
|
|---|
| 540 | };
|
|---|
| 541 |
|
|---|
| 542 | static void py_net_dealloc(py_net_Object *self)
|
|---|
| 543 | {
|
|---|
| 544 | talloc_free(self->mem_ctx);
|
|---|
| 545 | PyObject_Del(self);
|
|---|
| 546 | }
|
|---|
| 547 |
|
|---|
| 548 | static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|---|
| 549 | {
|
|---|
| 550 | PyObject *py_creds, *py_lp = Py_None;
|
|---|
| 551 | const char *kwnames[] = { "creds", "lp", "server", NULL };
|
|---|
| 552 | py_net_Object *ret;
|
|---|
| 553 | struct loadparm_context *lp;
|
|---|
| 554 | const char *server_address = NULL;
|
|---|
| 555 |
|
|---|
| 556 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oz",
|
|---|
| 557 | discard_const_p(char *, kwnames), &py_creds, &py_lp,
|
|---|
| 558 | &server_address))
|
|---|
| 559 | return NULL;
|
|---|
| 560 |
|
|---|
| 561 | ret = PyObject_New(py_net_Object, type);
|
|---|
| 562 | if (ret == NULL) {
|
|---|
| 563 | return NULL;
|
|---|
| 564 | }
|
|---|
| 565 |
|
|---|
| 566 | /* FIXME: we really need to get a context from the caller or we may end
|
|---|
| 567 | * up with 2 event contexts */
|
|---|
| 568 | ret->ev = s4_event_context_init(NULL);
|
|---|
| 569 | ret->mem_ctx = talloc_new(ret->ev);
|
|---|
| 570 |
|
|---|
| 571 | lp = lpcfg_from_py_object(ret->mem_ctx, py_lp);
|
|---|
| 572 | if (lp == NULL) {
|
|---|
| 573 | Py_DECREF(ret);
|
|---|
| 574 | return NULL;
|
|---|
| 575 | }
|
|---|
| 576 |
|
|---|
| 577 | ret->libnet_ctx = libnet_context_init(ret->ev, lp);
|
|---|
| 578 | if (ret->libnet_ctx == NULL) {
|
|---|
| 579 | PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
|
|---|
| 580 | Py_DECREF(ret);
|
|---|
| 581 | return NULL;
|
|---|
| 582 | }
|
|---|
| 583 |
|
|---|
| 584 | ret->libnet_ctx->server_address = server_address;
|
|---|
| 585 |
|
|---|
| 586 | ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
|
|---|
| 587 | if (ret->libnet_ctx->cred == NULL) {
|
|---|
| 588 | PyErr_SetString(PyExc_TypeError, "Expected credentials object");
|
|---|
| 589 | Py_DECREF(ret);
|
|---|
| 590 | return NULL;
|
|---|
| 591 | }
|
|---|
| 592 |
|
|---|
| 593 | return (PyObject *)ret;
|
|---|
| 594 | }
|
|---|
| 595 |
|
|---|
| 596 |
|
|---|
| 597 | PyTypeObject py_net_Type = {
|
|---|
| 598 | PyObject_HEAD_INIT(NULL) 0,
|
|---|
| 599 | .tp_name = "net.Net",
|
|---|
| 600 | .tp_basicsize = sizeof(py_net_Object),
|
|---|
| 601 | .tp_dealloc = (destructor)py_net_dealloc,
|
|---|
| 602 | .tp_methods = net_obj_methods,
|
|---|
| 603 | .tp_new = net_obj_new,
|
|---|
| 604 | };
|
|---|
| 605 |
|
|---|
| 606 | void initnet(void)
|
|---|
| 607 | {
|
|---|
| 608 | PyObject *m;
|
|---|
| 609 |
|
|---|
| 610 | if (PyType_Ready(&py_net_Type) < 0)
|
|---|
| 611 | return;
|
|---|
| 612 |
|
|---|
| 613 | m = Py_InitModule3("net", NULL, NULL);
|
|---|
| 614 | if (m == NULL)
|
|---|
| 615 | return;
|
|---|
| 616 |
|
|---|
| 617 | Py_INCREF(&py_net_Type);
|
|---|
| 618 | PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
|
|---|
| 619 | PyModule_AddObject(m, "LIBNET_JOINDOMAIN_AUTOMATIC", PyInt_FromLong(LIBNET_JOINDOMAIN_AUTOMATIC));
|
|---|
| 620 | PyModule_AddObject(m, "LIBNET_JOINDOMAIN_SPECIFIED", PyInt_FromLong(LIBNET_JOINDOMAIN_SPECIFIED));
|
|---|
| 621 | PyModule_AddObject(m, "LIBNET_JOIN_AUTOMATIC", PyInt_FromLong(LIBNET_JOIN_AUTOMATIC));
|
|---|
| 622 | PyModule_AddObject(m, "LIBNET_JOIN_SPECIFIED", PyInt_FromLong(LIBNET_JOIN_SPECIFIED));
|
|---|
| 623 | }
|
|---|