s4:net utility - make outprinted description comments more consistent
[metze/samba/wip.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", "Changes/Sets the password on a user account [server connection needed]\n", net_password, net_password_usage},
200         {"join", "Joins a domain [server connection needed]\n", net_join, net_join_usage},
201         {"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage},
202         {"samsync", "synchronise into the local ldb the sam of an NT4 domain\n", net_samsync_ldb, net_samsync_ldb_usage},
203         {"drs", "Implements functionality offered by repadmin.exe utility in Windows\n", net_drs, net_drs_usage},
204         {NULL, NULL, NULL, NULL}
205 };
206
207 static int net_help_builtin(const struct net_functable *ftable)
208 {
209         int i = 0;
210         const char *name = ftable[i].name;
211         const char *desc = ftable[i].desc;
212
213         while (name && desc) {
214                 if (strlen(name) > 7) {
215                         d_printf("\t%s\t%s", name, desc);
216                 } else {
217                         d_printf("\t%s\t\t%s", name, desc);
218                 }
219                 name = ftable[++i].name;
220                 desc = ftable[i].desc;
221         }
222         return 0;
223 }
224
225 static int net_help_python(void)
226 {
227         PyObject *py_cmds;
228         PyObject *key, *value;
229         Py_ssize_t pos = 0;
230
231         py_cmds = py_commands();
232         if (py_cmds == NULL) {
233                 return 1;
234         }
235
236         while (PyDict_Next(py_cmds, &pos, &key, &value)) {
237                 char *name, *desc;
238                 PyObject *py_desc;
239                 if (!PyString_Check(key)) {
240                         d_printf("Command name not a string\n");
241                         return 1;
242                 }
243                 name = PyString_AsString(key);
244                 py_desc = PyObject_GetAttrString(value, "description");
245                 if (py_desc == NULL) {
246                         PyErr_Print();
247                         return 1;
248                 }
249                 if (!PyString_Check(py_desc)) {
250                         d_printf("Command description for %s not a string\n", 
251                                 name);
252                         return 1;
253                 }
254                 desc = PyString_AsString(py_desc);
255                 if (strlen(name) > 7) {
256                         d_printf("\t%s\t%s\n", name, desc);
257                 } else {
258                         d_printf("\t%s\t\t%s\n", name, desc);
259                 }
260         }
261         return 0;
262 }
263
264 int net_help(struct net_context *ctx, const struct net_functable *ftable)
265 {
266         d_printf("Available commands:\n");
267         net_help_builtin(ftable);
268         net_help_python();
269         return 0;
270 }
271
272 static int net_usage(struct net_context *ctx, int argc, const char **argv)
273 {
274         d_printf("Usage:\n");
275         d_printf("net <command> [options]\n");
276         net_help(ctx, net_functable);
277         return 0;
278 }
279
280 /****************************************************************************
281   main program
282 ****************************************************************************/
283 static int binary_net(int argc, const char **argv)
284 {
285         int opt,i;
286         int rc;
287         int argc_new;
288         PyObject *py_cmds, *py_cmd;
289         const char **argv_new;
290         struct tevent_context *ev;
291         struct net_context *ctx = NULL;
292         poptContext pc;
293         struct poptOption long_options[] = {
294                 POPT_AUTOHELP
295                 POPT_COMMON_SAMBA
296                 POPT_COMMON_CONNECTION
297                 POPT_COMMON_CREDENTIALS
298                 POPT_COMMON_VERSION
299                 { NULL }
300         };
301
302         setlinebuf(stdout);
303
304         dcerpc_init(cmdline_lp_ctx);
305
306         ev = s4_event_context_init(NULL);
307         if (!ev) {
308                 d_printf("Failed to create an event context\n");
309                 exit(1);
310         }
311         py_load_samba_modules();
312         Py_Initialize();
313         PySys_SetArgv(argc, discard_const_p(char *, argv));
314         py_update_path("bin"); /* FIXME: Can't assume this is always the case */
315
316         py_cmds = py_commands();
317         if (py_cmds == NULL) {
318                 return 1;
319         }
320
321         if (argc > 1) {
322                 py_cmd = PyDict_GetItemString(py_cmds, argv[1]);
323                 if (py_cmd != NULL) {
324                         rc = py_call_with_string_args(py_cmd, "_run",
325                                 argc-1, argv+1);
326                         talloc_free(ev);
327                         return rc;
328                 }
329         }
330
331         pc = poptGetContext("net", argc, (const char **) argv, long_options, 
332                             POPT_CONTEXT_KEEP_FIRST);
333
334         while((opt = poptGetNextOpt(pc)) != -1) {
335                 switch (opt) {
336                 default:
337                         d_printf("Invalid option %s: %s\n", 
338                                  poptBadOption(pc, 0), poptStrerror(opt));
339                         net_usage(ctx, argc, argv);
340                         exit(1);
341                 }
342         }
343
344         argv_new = (const char **)poptGetArgs(pc);
345
346         argc_new = argc;
347         for (i=0; i<argc; i++) {
348                 if (argv_new[i] == NULL) {
349                         argc_new = i;
350                         break;
351                 }
352         }
353
354         if (argc_new < 2) {
355                 return net_usage(ctx, argc, argv);
356         }
357
358
359         ctx = talloc(ev, struct net_context);
360         if (!ctx) {
361                 d_printf("Failed to talloc a net_context\n");
362                 exit(1);
363         }
364
365         ZERO_STRUCTP(ctx);
366         ctx->lp_ctx = cmdline_lp_ctx;
367         ctx->credentials = cmdline_credentials;
368         ctx->event_ctx = ev;
369
370
371
372         rc = net_run_function(ctx, argc_new-1, argv_new+1, net_functable,
373                               net_usage);
374
375         if (rc != 0) {
376                 DEBUG(0,("return code = %d\n", rc));
377         }
378
379         talloc_free(ev);
380         return rc;
381 }
382
383  int main(int argc, const char **argv)
384 {
385         return binary_net(argc, argv);
386 }