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