| 1 | /*
 | 
|---|
| 2 |    Unix SMB/CIFS implementation.
 | 
|---|
| 3 |    Samba utility functions
 | 
|---|
| 4 |    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2010
 | 
|---|
| 5 |    Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 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 | }
 | 
|---|