net: Fix python 2.4 compatibility.
[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
55 /* There's no Py_ssize_t in 2.4, apparently */
56 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
57 typedef int Py_ssize_t;
58 #endif
59
60 static PyObject *py_tuple_from_argv(int argc, const char *argv[])
61 {
62         PyObject *l;
63         Py_ssize_t i;
64
65         l = PyTuple_New(argc);
66         if (l == NULL) {
67                 return NULL;
68         }
69
70         for (i = 0; i < argc; i++) {
71                 PyTuple_SetItem(l, i, PyString_FromString(argv[i]));
72         }
73
74         return l;
75 }
76
77 static int py_call_with_string_args(PyObject *self, const char *method, int argc, const char *argv[])
78 {
79         PyObject *ret, *args, *py_method;
80
81         args = py_tuple_from_argv(argc, argv);
82         if (args == NULL) {
83                 PyErr_Print();
84                 return 1;
85         }
86
87         py_method = PyObject_GetAttrString(self, method);
88         if (py_method == NULL) {
89                 PyErr_Print();
90                 return 1;
91         }       
92
93         ret = PyObject_CallObject(py_method, args);
94
95         Py_DECREF(args);
96
97         if (ret == NULL) {
98                 PyErr_Print();
99                 return 1;
100         }
101
102         if (ret == Py_None) {
103                 return 0;
104         } else if (PyInt_Check(ret)) {
105                 return PyInt_AsLong(ret);
106         } else {
107                 fprintf(stderr, "Function return value type unexpected.\n");
108                 return -1;
109         }
110 }
111
112 static PyObject *py_commands(void)
113 {
114         PyObject *netcmd_module, *py_cmds;
115         netcmd_module = PyImport_ImportModule("samba.netcmd");
116         if (netcmd_module == NULL) {
117                 PyErr_Print();
118                 return NULL;
119         }       
120
121         py_cmds = PyObject_GetAttrString(netcmd_module, "commands");
122         if (py_cmds == NULL) {
123                 PyErr_Print();
124                 return NULL;
125         }
126
127         if (!PyDict_Check(py_cmds)) {
128                 d_printf("Python net commands is not a dictionary\n");
129                 return NULL;
130         }
131
132         return py_cmds;
133 }
134
135 /*
136   run a function from a function table. If not found then
137   call the specified usage function 
138 */
139 int net_run_function(struct net_context *ctx,
140                         int argc, const char **argv,
141                         const struct net_functable *functable, 
142                         int (*usage_fn)(struct net_context *ctx, int argc, const char **argv))
143 {
144         int i;
145
146         if (argc == 0) {
147                 return usage_fn(ctx, argc, argv);
148
149         } else if (argc == 1 && strequal(argv[0], "help")) {
150                 return net_help(ctx, functable);
151         }
152
153         for (i=0; functable[i].name; i++) {
154                 if (strcasecmp_m(argv[0], functable[i].name) == 0)
155                         return functable[i].fn(ctx, argc-1, argv+1);
156         }
157
158         d_printf("No command: %s\n", argv[0]);
159         return usage_fn(ctx, argc, argv);
160 }
161
162 /*
163   run a usage function from a function table. If not found then fail
164 */
165 int net_run_usage(struct net_context *ctx,
166                         int argc, const char **argv,
167                         const struct net_functable *functable)
168 {
169         int i;
170         PyObject *py_cmds, *py_cmd;
171
172         for (i=0; functable[i].name; i++) {
173                 if (strcasecmp_m(argv[0], functable[i].name) == 0)
174                         if (functable[i].usage) {
175                                 return functable[i].usage(ctx, argc-1, argv+1);
176                         }
177         }
178
179         py_cmds = py_commands();
180         if (py_cmds == NULL) {
181                 return 1;
182         }
183
184         py_cmd = PyDict_GetItemString(py_cmds, argv[0]);
185         if (py_cmd != NULL) {
186                 return py_call_with_string_args(py_cmd, "usage", argc-1, 
187                                                 argv+1);
188         }
189
190         d_printf("No usage information for command: %s\n", argv[0]);
191
192         return 1;
193 }
194
195
196 /* main function table */
197 static const struct net_functable net_functable[] = {
198         {"password", "change password\n", net_password, net_password_usage},
199         {"time", "get remote server's time\n", net_time, net_time_usage},
200         {"join", "join a domain\n", net_join, net_join_usage},
201         {"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage},
202         {"export", "dump the sam of this domain\n", net_export, net_export_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         {NULL, NULL, NULL, NULL}
208 };
209
210 static int net_help_builtin(const struct net_functable *ftable)
211 {
212         int i = 0;
213         const char *name = ftable[i].name;
214         const char *desc = ftable[i].desc;
215
216         while (name && desc) {
217                 if (strlen(name) > 7) {
218                         d_printf("\t%s\t%s", name, desc);
219                 } else {
220                         d_printf("\t%s\t\t%s", name, desc);
221                 }
222                 name = ftable[++i].name;
223                 desc = ftable[i].desc;
224         }
225         return 0;
226 }
227
228 static int net_help_python(void)
229 {
230         PyObject *py_cmds;
231         PyObject *key, *value;
232         Py_ssize_t pos = 0;
233
234         py_cmds = py_commands();
235         if (py_cmds == NULL) {
236                 return 1;
237         }
238
239         while (PyDict_Next(py_cmds, &pos, &key, &value)) {
240                 char *name, *desc;
241                 PyObject *py_desc;
242                 if (!PyString_Check(key)) {
243                         d_printf("Command name not a string\n");
244                         return 1;
245                 }
246                 name = PyString_AsString(key);
247                 py_desc = PyObject_GetAttrString(value, "description");
248                 if (py_desc == NULL) {
249                         PyErr_Print();
250                         return 1;
251                 }
252                 if (!PyString_Check(py_desc)) {
253                         d_printf("Command description for %s not a string\n", 
254                                 name);
255                         return 1;
256                 }
257                 desc = PyString_AsString(py_desc);
258                 if (strlen(name) > 7) {
259                         d_printf("\t%s\t%s\n", name, desc);
260                 } else {
261                         d_printf("\t%s\t\t%s\n", name, desc);
262                 }
263         }
264         return 0;
265 }
266
267 int net_help(struct net_context *ctx, const struct net_functable *ftable)
268 {
269         d_printf("Available commands:\n");
270         net_help_builtin(ftable);
271         net_help_python();
272         return 0;
273 }
274
275 static int net_usage(struct net_context *ctx, int argc, const char **argv)
276 {
277         d_printf("Usage:\n");
278         d_printf("net <command> [options]\n");
279         d_printf("Type 'net help' for all available commands\n");
280         return 0;
281 }
282
283 /****************************************************************************
284   main program
285 ****************************************************************************/
286 static int binary_net(int argc, const char **argv)
287 {
288         int opt,i;
289         int rc;
290         int argc_new;
291         PyObject *py_cmds, *py_cmd;
292         const char **argv_new;
293         struct tevent_context *ev;
294         struct net_context *ctx = NULL;
295         poptContext pc;
296         struct poptOption long_options[] = {
297                 POPT_AUTOHELP
298                 POPT_COMMON_SAMBA
299                 POPT_COMMON_CONNECTION
300                 POPT_COMMON_CREDENTIALS
301                 POPT_COMMON_VERSION
302                 { NULL }
303         };
304
305         setlinebuf(stdout);
306
307         dcerpc_init(cmdline_lp_ctx);
308
309         ev = s4_event_context_init(NULL);
310         if (!ev) {
311                 d_printf("Failed to create an event context\n");
312                 exit(1);
313         }
314         py_load_samba_modules();
315         Py_Initialize();
316         PySys_SetArgv(argc, argv);
317         py_update_path("bin"); /* FIXME: Can't assume this is always the case */
318
319         py_cmds = py_commands();
320         if (py_cmds == NULL) {
321                 return 1;
322         }
323
324         if (argc > 1) {
325                 py_cmd = PyDict_GetItemString(py_cmds, argv[1]);
326                 if (py_cmd != NULL) {
327                         rc = py_call_with_string_args(py_cmd, "_run",
328                                 argc-1, argv+1);
329                         talloc_free(ev);
330                         return rc;
331                 }
332         }
333
334         pc = poptGetContext("net", argc, (const char **) argv, long_options, 
335                             POPT_CONTEXT_KEEP_FIRST);
336
337         while((opt = poptGetNextOpt(pc)) != -1) {
338                 switch (opt) {
339                 default:
340                         d_printf("Invalid option %s: %s\n", 
341                                  poptBadOption(pc, 0), poptStrerror(opt));
342                         net_usage(ctx, argc, argv);
343                         exit(1);
344                 }
345         }
346
347         argv_new = (const char **)poptGetArgs(pc);
348
349         argc_new = argc;
350         for (i=0; i<argc; i++) {
351                 if (argv_new[i] == NULL) {
352                         argc_new = i;
353                         break;
354                 }
355         }
356
357         if (argc_new < 2) {
358                 return net_usage(ctx, argc, argv);
359         }
360
361
362         ctx = talloc(ev, struct net_context);
363         if (!ctx) {
364                 d_printf("Failed to talloc a net_context\n");
365                 exit(1);
366         }
367
368         ZERO_STRUCTP(ctx);
369         ctx->lp_ctx = cmdline_lp_ctx;
370         ctx->credentials = cmdline_credentials;
371         ctx->event_ctx = ev;
372
373
374
375         rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable,
376                               net_usage);
377
378         if (rc != 0) {
379                 DEBUG(0,("return code = %d\n", rc));
380         }
381
382         talloc_free(ev);
383         return rc;
384 }
385
386  int main(int argc, const char **argv)
387 {
388         return binary_net(argc, argv);
389 }