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