Migrate 'net export keytab' to python.
[amitay/samba.git] / source4 / utils / net / net.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    Distributed SMB/CIFS Server Management Utility 
4    Copyright (C) 2001 Steve French  (sfrench@us.ibm.com)
5    Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
6    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
7    Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
8    Copyright (C) 2004 Stefan Metzmacher (metze@samba.org)
9    Copyright (C) 2009 Jelmer Vernooij (jelmer@samba.org)
10
11    Largely rewritten by metze in August 2004
12
13    Originally written by Steve and Jim. Largely rewritten by tridge in
14    November 2001.
15
16    Reworked again by abartlet in December 2001
17
18    This program is free software; you can redistribute it and/or modify
19    it under the terms of the GNU General Public License as published by
20    the Free Software Foundation; either version 3 of the License, or
21    (at your option) any later version.
22    
23    This program is distributed in the hope that it will be useful,
24    but WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26    GNU General Public License for more details.
27    
28    You should have received a copy of the GNU General Public License
29    along with this program.  If not, see <http://www.gnu.org/licenses/>.
30 */
31  
32 /*****************************************************/
33 /*                                                   */
34 /*   Distributed SMB/CIFS Server Management Utility  */
35 /*                                                   */
36 /*   The intent was to make the syntax similar       */
37 /*   to the NET utility (first developed in DOS      */
38 /*   with additional interesting & useful functions  */
39 /*   added in later SMB server network operating     */
40 /*   systems).                                       */
41 /*                                                   */
42 /*****************************************************/
43
44 #include <Python.h>
45 #include "includes.h"
46 #include "utils/net/net.h"
47 #include "lib/cmdline/popt_common.h"
48 #include "lib/ldb/include/ldb.h"
49 #include "librpc/rpc/dcerpc.h"
50 #include "param/param.h"
51 #include "lib/events/events.h"
52 #include "auth/credentials/credentials.h"
53 #include "scripting/python/modules.h"
54 #include "utils/net/drs/net_drs.h"
55
56 /* There's no Py_ssize_t in 2.4, apparently */
57 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
58 typedef int Py_ssize_t;
59 #endif
60
61 static PyObject *py_tuple_from_argv(int argc, const char *argv[])
62 {
63         PyObject *l;
64         Py_ssize_t i;
65
66         l = PyTuple_New(argc);
67         if (l == NULL) {
68                 return NULL;
69         }
70
71         for (i = 0; i < argc; i++) {
72                 PyTuple_SetItem(l, i, PyString_FromString(argv[i]));
73         }
74
75         return l;
76 }
77
78 static int py_call_with_string_args(PyObject *self, const char *method, int argc, const char *argv[])
79 {
80         PyObject *ret, *args, *py_method;
81
82         args = py_tuple_from_argv(argc, argv);
83         if (args == NULL) {
84                 PyErr_Print();
85                 return 1;
86         }
87
88         py_method = PyObject_GetAttrString(self, method);
89         if (py_method == NULL) {
90                 PyErr_Print();
91                 return 1;
92         }       
93
94         ret = PyObject_CallObject(py_method, args);
95
96         Py_DECREF(args);
97
98         if (ret == NULL) {
99                 PyErr_Print();
100                 return 1;
101         }
102
103         if (ret == Py_None) {
104                 return 0;
105         } else if (PyInt_Check(ret)) {
106                 return PyInt_AsLong(ret);
107         } else {
108                 fprintf(stderr, "Function return value type unexpected.\n");
109                 return -1;
110         }
111 }
112
113 static PyObject *py_commands(void)
114 {
115         PyObject *netcmd_module, *py_cmds;
116         netcmd_module = PyImport_ImportModule("samba.netcmd");
117         if (netcmd_module == NULL) {
118                 PyErr_Print();
119                 return NULL;
120         }       
121
122         py_cmds = PyObject_GetAttrString(netcmd_module, "commands");
123         if (py_cmds == NULL) {
124                 PyErr_Print();
125                 return NULL;
126         }
127
128         if (!PyDict_Check(py_cmds)) {
129                 d_printf("Python net commands is not a dictionary\n");
130                 return NULL;
131         }
132
133         return py_cmds;
134 }
135
136 /*
137   run a function from a function table. If not found then
138   call the specified usage function 
139 */
140 int net_run_function(struct net_context *ctx,
141                         int argc, const char **argv,
142                         const struct net_functable *functable, 
143                         int (*usage_fn)(struct net_context *ctx, int argc, const char **argv))
144 {
145         int i;
146
147         if (argc == 0) {
148                 return usage_fn(ctx, argc, argv);
149
150         } else if (argc == 1 && strequal(argv[0], "help")) {
151                 return net_help(ctx, functable);
152         }
153
154         for (i=0; functable[i].name; i++) {
155                 if (strcasecmp_m(argv[0], functable[i].name) == 0)
156                         return functable[i].fn(ctx, argc-1, argv+1);
157         }
158
159         d_printf("No command: %s\n", argv[0]);
160         return usage_fn(ctx, argc, argv);
161 }
162
163 /*
164   run a usage function from a function table. If not found then fail
165 */
166 int net_run_usage(struct net_context *ctx,
167                         int argc, const char **argv,
168                         const struct net_functable *functable)
169 {
170         int i;
171         PyObject *py_cmds, *py_cmd;
172
173         for (i=0; functable[i].name; i++) {
174                 if (strcasecmp_m(argv[0], functable[i].name) == 0)
175                         if (functable[i].usage) {
176                                 return functable[i].usage(ctx, argc-1, argv+1);
177                         }
178         }
179
180         py_cmds = py_commands();
181         if (py_cmds == NULL) {
182                 return 1;
183         }
184
185         py_cmd = PyDict_GetItemString(py_cmds, argv[0]);
186         if (py_cmd != NULL) {
187                 return py_call_with_string_args(py_cmd, "usage", argc-1, 
188                                                 argv+1);
189         }
190
191         d_printf("No usage information for command: %s\n", argv[0]);
192
193         return 1;
194 }
195
196
197 /* main function table */
198 static const struct net_functable net_functable[] = {
199         {"password", "change password\n", net_password, net_password_usage},
200         {"time", "get remote server's time\n", net_time, net_time_usage},
201         {"join", "join a domain\n", net_join, net_join_usage},
202         {"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage},
203         {"vampire", "join and syncronise an AD domain onto the local server\n", net_vampire, net_vampire_usage},
204         {"samsync", "synchronise into the local ldb the sam of an NT4 domain\n", net_samsync_ldb, net_samsync_ldb_usage},
205         {"user", "manage user accounts\n", net_user, net_user_usage},
206         {"machinepw", "Get a machine password out of our SAM\n", net_machinepw, net_machinepw_usage},
207         {"drs", "Implements functionality offered by repadmin.exe utility in Windows\n", net_drs, net_drs_usage},
208         {NULL, NULL, NULL, NULL}
209 };
210
211 static int net_help_builtin(const struct net_functable *ftable)
212 {
213         int i = 0;
214         const char *name = ftable[i].name;
215         const char *desc = ftable[i].desc;
216
217         while (name && desc) {
218                 if (strlen(name) > 7) {
219                         d_printf("\t%s\t%s", name, desc);
220                 } else {
221                         d_printf("\t%s\t\t%s", name, desc);
222                 }
223                 name = ftable[++i].name;
224                 desc = ftable[i].desc;
225         }
226         return 0;
227 }
228
229 static int net_help_python(void)
230 {
231         PyObject *py_cmds;
232         PyObject *key, *value;
233         Py_ssize_t pos = 0;
234
235         py_cmds = py_commands();
236         if (py_cmds == NULL) {
237                 return 1;
238         }
239
240         while (PyDict_Next(py_cmds, &pos, &key, &value)) {
241                 char *name, *desc;
242                 PyObject *py_desc;
243                 if (!PyString_Check(key)) {
244                         d_printf("Command name not a string\n");
245                         return 1;
246                 }
247                 name = PyString_AsString(key);
248                 py_desc = PyObject_GetAttrString(value, "description");
249                 if (py_desc == NULL) {
250                         PyErr_Print();
251                         return 1;
252                 }
253                 if (!PyString_Check(py_desc)) {
254                         d_printf("Command description for %s not a string\n", 
255                                 name);
256                         return 1;
257                 }
258                 desc = PyString_AsString(py_desc);
259                 if (strlen(name) > 7) {
260                         d_printf("\t%s\t%s\n", name, desc);
261                 } else {
262                         d_printf("\t%s\t\t%s\n", name, desc);
263                 }
264         }
265         return 0;
266 }
267
268 int net_help(struct net_context *ctx, const struct net_functable *ftable)
269 {
270         d_printf("Available commands:\n");
271         net_help_builtin(ftable);
272         net_help_python();
273         return 0;
274 }
275
276 static int net_usage(struct net_context *ctx, int argc, const char **argv)
277 {
278         d_printf("Usage:\n");
279         d_printf("net <command> [options]\n");
280         d_printf("Type 'net help' for all available commands\n");
281         return 0;
282 }
283
284 /****************************************************************************
285   main program
286 ****************************************************************************/
287 static int binary_net(int argc, const char **argv)
288 {
289         int opt,i;
290         int rc;
291         int argc_new;
292         PyObject *py_cmds, *py_cmd;
293         const char **argv_new;
294         struct tevent_context *ev;
295         struct net_context *ctx = NULL;
296         poptContext pc;
297         struct poptOption long_options[] = {
298                 POPT_AUTOHELP
299                 POPT_COMMON_SAMBA
300                 POPT_COMMON_CONNECTION
301                 POPT_COMMON_CREDENTIALS
302                 POPT_COMMON_VERSION
303                 { NULL }
304         };
305
306         setlinebuf(stdout);
307
308         dcerpc_init(cmdline_lp_ctx);
309
310         ev = s4_event_context_init(NULL);
311         if (!ev) {
312                 d_printf("Failed to create an event context\n");
313                 exit(1);
314         }
315         py_load_samba_modules();
316         Py_Initialize();
317         PySys_SetArgv(argc, discard_const_p(char *, argv));
318         py_update_path("bin"); /* FIXME: Can't assume this is always the case */
319
320         py_cmds = py_commands();
321         if (py_cmds == NULL) {
322                 return 1;
323         }
324
325         if (argc > 1) {
326                 py_cmd = PyDict_GetItemString(py_cmds, argv[1]);
327                 if (py_cmd != NULL) {
328                         rc = py_call_with_string_args(py_cmd, "_run",
329                                 argc-1, argv+1);
330                         talloc_free(ev);
331                         return rc;
332                 }
333         }
334
335         pc = poptGetContext("net", argc, (const char **) argv, long_options, 
336                             POPT_CONTEXT_KEEP_FIRST);
337
338         while((opt = poptGetNextOpt(pc)) != -1) {
339                 switch (opt) {
340                 default:
341                         d_printf("Invalid option %s: %s\n", 
342                                  poptBadOption(pc, 0), poptStrerror(opt));
343                         net_usage(ctx, argc, argv);
344                         exit(1);
345                 }
346         }
347
348         argv_new = (const char **)poptGetArgs(pc);
349
350         argc_new = argc;
351         for (i=0; i<argc; i++) {
352                 if (argv_new[i] == NULL) {
353                         argc_new = i;
354                         break;
355                 }
356         }
357
358         if (argc_new < 2) {
359                 return net_usage(ctx, argc, argv);
360         }
361
362
363         ctx = talloc(ev, struct net_context);
364         if (!ctx) {
365                 d_printf("Failed to talloc a net_context\n");
366                 exit(1);
367         }
368
369         ZERO_STRUCTP(ctx);
370         ctx->lp_ctx = cmdline_lp_ctx;
371         ctx->credentials = cmdline_credentials;
372         ctx->event_ctx = ev;
373
374
375
376         rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable,
377                               net_usage);
378
379         if (rc != 0) {
380                 DEBUG(0,("return code = %d\n", rc));
381         }
382
383         talloc_free(ev);
384         return rc;
385 }
386
387  int main(int argc, const char **argv)
388 {
389         return binary_net(argc, argv);
390 }