91070a5da9dd2ec711f5c2bc365317b4dcb44adc
[samba.git] / source3 / utils / 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) 2008 Kai Blin (kai@samba.org)
9
10    Originally written by Steve and Jim. Largely rewritten by tridge in
11    November 2001.
12
13    Reworked again by abartlet in December 2001
14
15    Another overhaul, moving functionality into plug-ins loaded on demand by Kai
16    in May 2008.
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 /*   Distributed SMB/CIFS Server Management Utility  */
34 /*                                                   */
35 /*   The intent was to make the syntax similar       */
36 /*   to the NET utility (first developed in DOS      */
37 /*   with additional interesting & useful functions  */
38 /*   added in later SMB server network operating     */
39 /*   systems).                                       */
40 /*                                                   */
41 /*****************************************************/
42
43 #include "includes.h"
44 #include "utils/net.h"
45
46 extern bool AllowDebugChange;
47
48 #ifdef WITH_FAKE_KASERVER
49 #include "utils/net_afs.h"
50 #endif
51
52 /***********************************************************************/
53 /* Beginning of internationalization section.  Translatable constants  */
54 /* should be kept in this area and referenced in the rest of the code. */
55 /*                                                                     */
56 /* No functions, outside of Samba or LSB (Linux Standards Base) should */
57 /* be used (if possible).                                              */
58 /***********************************************************************/
59
60 #define YES_STRING              "Yes"
61 #define NO_STRING               "No"
62
63 /***********************************************************************/
64 /* end of internationalization section                                 */
65 /***********************************************************************/
66
67 uint32 get_sec_channel_type(const char *param)
68 {
69         if (!(param && *param)) {
70                 return get_default_sec_channel();
71         } else {
72                 if (strequal(param, "PDC")) {
73                         return SEC_CHAN_BDC;
74                 } else if (strequal(param, "BDC")) {
75                         return SEC_CHAN_BDC;
76                 } else if (strequal(param, "MEMBER")) {
77                         return SEC_CHAN_WKSTA;
78 #if 0
79                 } else if (strequal(param, "DOMAIN")) {
80                         return SEC_CHAN_DOMAIN;
81 #endif
82                 } else {
83                         return get_default_sec_channel();
84                 }
85         }
86 }
87
88 /*
89   run a function from a function table. If not found then
90   call the specified usage function
91 */
92 int net_run_function(struct net_context *c, int argc, const char **argv,
93                      struct functable *table,
94                      int (*usage_fn)(struct net_context *c,
95                                      int argc, const char **argv))
96 {
97         int i;
98
99         if (argc < 1) {
100                 d_printf("\nUsage: \n");
101                 return usage_fn(c, argc, argv);
102         }
103         for (i=0; table[i].funcname; i++) {
104                 if (StrCaseCmp(argv[0], table[i].funcname) == 0)
105                         return table[i].fn(c, argc-1, argv+1);
106         }
107         d_fprintf(stderr, "No command: %s\n", argv[0]);
108         return usage_fn(c, argc, argv);
109 }
110
111 /*
112  * run a function from a function table.
113  */
114 int net_run_function2(struct net_context *c, int argc, const char **argv,
115                       const char *whoami, struct functable2 *table)
116 {
117         int i;
118
119         if (argc != 0) {
120                 for (i=0; table[i].funcname; i++) {
121                         if (StrCaseCmp(argv[0], table[i].funcname) == 0)
122                                 return table[i].fn(c, argc-1, argv+1);
123                 }
124         }
125
126         for (i=0; table[i].funcname != NULL; i++) {
127                 d_printf("%s %-15s %s\n", whoami, table[i].funcname,
128                          table[i].helptext);
129         }
130
131         return -1;
132 }
133
134 static int net_changetrustpw(struct net_context *c, int argc, const char **argv)
135 {
136         if (net_ads_check_our_domain(c) == 0)
137                 return net_ads_changetrustpw(c, argc, argv);
138
139         return net_rpc_changetrustpw(c, argc, argv);
140 }
141
142 static void set_line_buffering(FILE *f)
143 {
144         setvbuf(f, NULL, _IOLBF, 0);
145 }
146
147 static int net_changesecretpw(struct net_context *c, int argc,
148                               const char **argv)
149 {
150         char *trust_pw;
151         uint32 sec_channel_type = SEC_CHAN_WKSTA;
152
153         if(c->opt_force) {
154                 if (c->opt_stdin) {
155                         set_line_buffering(stdin);
156                         set_line_buffering(stdout);
157                         set_line_buffering(stderr);
158                 }
159
160                 trust_pw = get_pass("Enter machine password: ", c->opt_stdin);
161
162                 if (!secrets_store_machine_password(trust_pw, lp_workgroup(), sec_channel_type)) {
163                             d_fprintf(stderr, "Unable to write the machine account password in the secrets database");
164                             return 1;
165                 }
166                 else {
167                     d_printf("Modified trust account password in secrets database\n");
168                 }
169         }
170         else {
171                 d_printf("Machine account password change requires the -f flag.\n");
172                 d_printf("Do NOT use this function unless you know what it does!\n");
173                 d_printf("This function will change the ADS Domain member machine account password in the secrets.tdb file!\n");
174         }
175
176         return 0;
177 }
178
179 /*
180  Retrieve our local SID or the SID for the specified name
181  */
182 static int net_getlocalsid(struct net_context *c, int argc, const char **argv)
183 {
184         DOM_SID sid;
185         const char *name;
186         fstring sid_str;
187
188         if (argc >= 1) {
189                 name = argv[0];
190         }
191         else {
192                 name = global_myname();
193         }
194
195         if(!initialize_password_db(false, NULL)) {
196                 DEBUG(0, ("WARNING: Could not open passdb - local sid may not reflect passdb\n"
197                           "backend knowledge (such as the sid stored in LDAP)\n"));
198         }
199
200         /* first check to see if we can even access secrets, so we don't
201            panic when we can't. */
202
203         if (!secrets_init()) {
204                 d_fprintf(stderr, "Unable to open secrets.tdb.  Can't fetch domain SID for name: %s\n", name);
205                 return 1;
206         }
207
208         /* Generate one, if it doesn't exist */
209         get_global_sam_sid();
210
211         if (!secrets_fetch_domain_sid(name, &sid)) {
212                 DEBUG(0, ("Can't fetch domain SID for name: %s\n", name));
213                 return 1;
214         }
215         sid_to_fstring(sid_str, &sid);
216         d_printf("SID for domain %s is: %s\n", name, sid_str);
217         return 0;
218 }
219
220 static int net_setlocalsid(struct net_context *c, int argc, const char **argv)
221 {
222         DOM_SID sid;
223
224         if ( (argc != 1)
225              || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
226              || (!string_to_sid(&sid, argv[0]))
227              || (sid.num_auths != 4)) {
228                 d_printf("usage: net setlocalsid S-1-5-21-x-y-z\n");
229                 return 1;
230         }
231
232         if (!secrets_store_domain_sid(global_myname(), &sid)) {
233                 DEBUG(0,("Can't store domain SID as a pdc/bdc.\n"));
234                 return 1;
235         }
236
237         return 0;
238 }
239
240 static int net_setdomainsid(struct net_context *c, int argc, const char **argv)
241 {
242         DOM_SID sid;
243
244         if ( (argc != 1)
245              || (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
246              || (!string_to_sid(&sid, argv[0]))
247              || (sid.num_auths != 4)) {
248                 d_printf("usage: net setdomainsid S-1-5-21-x-y-z\n");
249                 return 1;
250         }
251
252         if (!secrets_store_domain_sid(lp_workgroup(), &sid)) {
253                 DEBUG(0,("Can't store domain SID.\n"));
254                 return 1;
255         }
256
257         return 0;
258 }
259
260 static int net_getdomainsid(struct net_context *c, int argc, const char **argv)
261 {
262         DOM_SID domain_sid;
263         fstring sid_str;
264
265         if (argc > 0) {
266                 d_printf("usage: net getdomainsid\n");
267                 return 1;
268         }
269
270         if(!initialize_password_db(false, NULL)) {
271                 DEBUG(0, ("WARNING: Could not open passdb - domain SID may "
272                           "not reflect passdb\n"
273                           "backend knowledge (such as the SID stored in "
274                           "LDAP)\n"));
275         }
276
277         /* first check to see if we can even access secrets, so we don't
278            panic when we can't. */
279
280         if (!secrets_init()) {
281                 d_fprintf(stderr, "Unable to open secrets.tdb.  Can't fetch domain"
282                                   "SID for name: %s\n", get_global_sam_name());
283                 return 1;
284         }
285
286         /* Generate one, if it doesn't exist */
287         get_global_sam_sid();
288
289         if (!secrets_fetch_domain_sid(global_myname(), &domain_sid)) {
290                 d_fprintf(stderr, "Could not fetch local SID\n");
291                 return 1;
292         }
293         sid_to_fstring(sid_str, &domain_sid);
294         d_printf("SID for local machine %s is: %s\n", global_myname(), sid_str);
295
296         if (!secrets_fetch_domain_sid(c->opt_workgroup, &domain_sid)) {
297                 d_fprintf(stderr, "Could not fetch domain SID\n");
298                 return 1;
299         }
300
301         sid_to_fstring(sid_str, &domain_sid);
302         d_printf("SID for domain %s is: %s\n", c->opt_workgroup, sid_str);
303
304         return 0;
305 }
306
307 static bool search_maxrid(struct pdb_search *search, const char *type,
308                           uint32 *max_rid)
309 {
310         struct samr_displayentry *entries;
311         uint32 i, num_entries;
312
313         if (search == NULL) {
314                 d_fprintf(stderr, "get_maxrid: Could not search %s\n", type);
315                 return false;
316         }
317
318         num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
319         for (i=0; i<num_entries; i++)
320                 *max_rid = MAX(*max_rid, entries[i].rid);
321         pdb_search_destroy(search);
322         return true;
323 }
324
325 static uint32 get_maxrid(void)
326 {
327         uint32 max_rid = 0;
328
329         if (!search_maxrid(pdb_search_users(0), "users", &max_rid))
330                 return 0;
331
332         if (!search_maxrid(pdb_search_groups(), "groups", &max_rid))
333                 return 0;
334
335         if (!search_maxrid(pdb_search_aliases(get_global_sam_sid()),
336                            "aliases", &max_rid))
337                 return 0;
338
339         return max_rid;
340 }
341
342 static int net_maxrid(struct net_context *c, int argc, const char **argv)
343 {
344         uint32 rid;
345
346         if (argc != 0) {
347                 DEBUG(0, ("usage: net maxrid\n"));
348                 return 1;
349         }
350
351         if ((rid = get_maxrid()) == 0) {
352                 DEBUG(0, ("can't get current maximum rid\n"));
353                 return 1;
354         }
355
356         d_printf("Currently used maximum rid: %d\n", rid);
357
358         return 0;
359 }
360
361 /* main function table */
362 static struct functable net_func[] = {
363         {"RPC", net_rpc},
364         {"RAP", net_rap},
365         {"ADS", net_ads},
366
367         /* eventually these should auto-choose the transport ... */
368         {"FILE", net_file},
369         {"SHARE", net_share},
370         {"SESSION", net_rap_session},
371         {"SERVER", net_rap_server},
372         {"DOMAIN", net_rap_domain},
373         {"PRINTQ", net_rap_printq},
374         {"USER", net_user},
375         {"GROUP", net_group},
376         {"GROUPMAP", net_groupmap},
377         {"SAM", net_sam},
378         {"VALIDATE", net_rap_validate},
379         {"GROUPMEMBER", net_rap_groupmember},
380         {"ADMIN", net_rap_admin},
381         {"SERVICE", net_rap_service},
382         {"PASSWORD", net_rap_password},
383         {"CHANGETRUSTPW", net_changetrustpw},
384         {"CHANGESECRETPW", net_changesecretpw},
385         {"TIME", net_time},
386         {"LOOKUP", net_lookup},
387         {"JOIN", net_join},
388         {"DOM", net_dom},
389         {"CACHE", net_cache},
390         {"GETLOCALSID", net_getlocalsid},
391         {"SETLOCALSID", net_setlocalsid},
392         {"SETDOMAINSID", net_setdomainsid},
393         {"GETDOMAINSID", net_getdomainsid},
394         {"MAXRID", net_maxrid},
395         {"IDMAP", net_idmap},
396         {"STATUS", net_status},
397         {"USERSHARE", net_usershare},
398         {"USERSIDLIST", net_usersidlist},
399         {"CONF", net_conf},
400         {"REGISTRY", net_registry},
401 #ifdef WITH_FAKE_KASERVER
402         {"AFS", net_afs},
403 #endif
404
405         {"HELP", net_help},
406         {NULL, NULL}
407 };
408
409
410 /****************************************************************************
411   main program
412 ****************************************************************************/
413  int main(int argc, const char **argv)
414 {
415         int opt,i;
416         char *p;
417         int rc = 0;
418         int argc_new = 0;
419         const char ** argv_new;
420         poptContext pc;
421         TALLOC_CTX *frame = talloc_stackframe();
422         struct net_context *c = talloc_zero(frame, struct net_context);
423
424         struct poptOption long_options[] = {
425                 {"help",        'h', POPT_ARG_NONE,   0, 'h'},
426                 {"workgroup",   'w', POPT_ARG_STRING, &c->opt_target_workgroup},
427                 {"user",        'U', POPT_ARG_STRING, &c->opt_user_name, 'U'},
428                 {"ipaddress",   'I', POPT_ARG_STRING, 0,'I'},
429                 {"port",        'p', POPT_ARG_INT,    &c->opt_port},
430                 {"myname",      'n', POPT_ARG_STRING, &c->opt_requester_name},
431                 {"server",      'S', POPT_ARG_STRING, &c->opt_host},
432                 {"encrypt",     'e', POPT_ARG_NONE,   NULL, 'e', "Encrypt SMB transport (UNIX extended servers only)" },
433                 {"container",   'c', POPT_ARG_STRING, &c->opt_container},
434                 {"comment",     'C', POPT_ARG_STRING, &c->opt_comment},
435                 {"maxusers",    'M', POPT_ARG_INT,    &c->opt_maxusers},
436                 {"flags",       'F', POPT_ARG_INT,    &c->opt_flags},
437                 {"long",        'l', POPT_ARG_NONE,   &c->opt_long_list_entries},
438                 {"reboot",      'r', POPT_ARG_NONE,   &c->opt_reboot},
439                 {"force",       'f', POPT_ARG_NONE,   &c->opt_force},
440                 {"stdin",       'i', POPT_ARG_NONE,   &c->opt_stdin},
441                 {"timeout",     't', POPT_ARG_INT,    &c->opt_timeout},
442                 {"machine-pass",'P', POPT_ARG_NONE,   &c->opt_machine_pass},
443                 {"myworkgroup", 'W', POPT_ARG_STRING, &c->opt_workgroup},
444                 {"verbose",     'v', POPT_ARG_NONE,   &c->opt_verbose},
445                 {"test",        'T', POPT_ARG_NONE,   &c->opt_testmode},
446                 /* Options for 'net groupmap set' */
447                 {"local",       'L', POPT_ARG_NONE,   &c->opt_localgroup},
448                 {"domain",      'D', POPT_ARG_NONE,   &c->opt_domaingroup},
449                 {"ntname",      'N', POPT_ARG_STRING, &c->opt_newntname},
450                 {"rid",         'R', POPT_ARG_INT,    &c->opt_rid},
451                 /* Options for 'net rpc share migrate' */
452                 {"acls",        0, POPT_ARG_NONE,     &c->opt_acls},
453                 {"attrs",       0, POPT_ARG_NONE,     &c->opt_attrs},
454                 {"timestamps",  0, POPT_ARG_NONE,     &c->opt_timestamps},
455                 {"exclude",     'X', POPT_ARG_STRING, &c->opt_exclude},
456                 {"destination", 0, POPT_ARG_STRING,   &c->opt_destination},
457                 {"tallocreport", 0, POPT_ARG_NONE,    &c->do_talloc_report},
458
459                 POPT_COMMON_SAMBA
460                 { 0, 0, 0, 0}
461         };
462
463
464         zero_addr(&c->opt_dest_ip);
465
466         load_case_tables();
467
468         /* set default debug level to 0 regardless of what smb.conf sets */
469         DEBUGLEVEL_CLASS[DBGC_ALL] = 0;
470         dbf = x_stderr;
471
472         pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
473                             POPT_CONTEXT_KEEP_FIRST);
474
475         while((opt = poptGetNextOpt(pc)) != -1) {
476                 switch (opt) {
477                 case 'h':
478                         net_help(c, argc, argv);
479                         exit(0);
480                         break;
481                 case 'e':
482                         c->smb_encrypt = true;
483                         break;
484                 case 'I':
485                         if (!interpret_string_addr(&c->opt_dest_ip,
486                                                 poptGetOptArg(pc), 0)) {
487                                 d_fprintf(stderr, "\nInvalid ip address specified\n");
488                         } else {
489                                 c->opt_have_ip = true;
490                         }
491                         break;
492                 case 'U':
493                         c->opt_user_specified = true;
494                         c->opt_user_name = SMB_STRDUP(c->opt_user_name);
495                         p = strchr(c->opt_user_name,'%');
496                         if (p) {
497                                 *p = 0;
498                                 c->opt_password = p+1;
499                         }
500                         break;
501                 default:
502                         d_fprintf(stderr, "\nInvalid option %s: %s\n",
503                                  poptBadOption(pc, 0), poptStrerror(opt));
504                         net_help(c, argc, argv);
505                         exit(1);
506                 }
507         }
508
509         /*
510          * Don't load debug level from smb.conf. It should be
511          * set by cmdline arg or remain default (0)
512          */
513         AllowDebugChange = false;
514         lp_load(get_dyn_CONFIGFILE(), true, false, false, true);
515
516         argv_new = (const char **)poptGetArgs(pc);
517
518         argc_new = argc;
519         for (i=0; i<argc; i++) {
520                 if (argv_new[i] == NULL) {
521                         argc_new = i;
522                         break;
523                 }
524         }
525
526         if (c->do_talloc_report) {
527                 talloc_enable_leak_report();
528         }
529
530         if (c->opt_requester_name) {
531                 set_global_myname(c->opt_requester_name);
532         }
533
534         if (!c->opt_user_name && getenv("LOGNAME")) {
535                 c->opt_user_name = getenv("LOGNAME");
536         }
537
538         if (!c->opt_workgroup) {
539                 c->opt_workgroup = smb_xstrdup(lp_workgroup());
540         }
541
542         if (!c->opt_target_workgroup) {
543                 c->opt_target_workgroup = smb_xstrdup(lp_workgroup());
544         }
545
546         if (!init_names())
547                 exit(1);
548
549         load_interfaces();
550
551         /* this makes sure that when we do things like call scripts,
552            that it won't assert becouse we are not root */
553         sec_init();
554
555         if (c->opt_machine_pass) {
556                 /* it is very useful to be able to make ads queries as the
557                    machine account for testing purposes and for domain leave */
558
559                 net_use_krb_machine_account(c);
560         }
561
562         if (!c->opt_password) {
563                 c->opt_password = getenv("PASSWD");
564         }
565
566         rc = net_run_function(c, argc_new-1, argv_new+1, net_func, net_help);
567
568         DEBUG(2,("return code = %d\n", rc));
569
570         libnetapi_free(c->netapi_ctx);
571
572         poptFreeContext(pc);
573
574         TALLOC_FREE(frame);
575         return rc;
576 }