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