2df4d4385310686e8d454685faf708acb4018371
[samba.git] / lib / cmdline / cmdline.c
1 /*
2  * Copyright (c) 2020      Andreas Schneider <asn@samba.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "includes.h"
19 #include "lib/param/param.h"
20 #include "dynconfig/dynconfig.h"
21 #include "auth/gensec/gensec.h"
22 #include "libcli/smb/smb_util.h"
23 #include "cmdline_private.h"
24
25 #include <samba/version.h>
26
27 static TALLOC_CTX *cmdline_mem_ctx;
28 static struct loadparm_context *cmdline_lp_ctx;
29 static struct cli_credentials *cmdline_creds;
30 static samba_cmdline_load_config cmdline_load_config_fn;
31
32 /* PRIVATE */
33 bool samba_cmdline_set_talloc_ctx(TALLOC_CTX *mem_ctx)
34 {
35         if (cmdline_mem_ctx != NULL) {
36                 return false;
37         }
38
39         cmdline_mem_ctx = mem_ctx;
40         return true;
41 }
42
43 TALLOC_CTX *samba_cmdline_get_talloc_ctx(void)
44 {
45         return cmdline_mem_ctx;
46 }
47
48 static void _samba_cmdline_talloc_log(const char *message)
49 {
50         DBG_ERR("%s", message);
51 }
52
53 bool samba_cmdline_init_common(TALLOC_CTX *mem_ctx)
54 {
55         bool ok;
56
57         ok = samba_cmdline_set_talloc_ctx(mem_ctx);
58         if (!ok) {
59                 return false;
60         }
61
62         fault_setup();
63
64         /*
65          * Log to stdout by default.
66          * This can be changed to stderr using the option: --debug-stdout
67          */
68         setup_logging(getprogname(), DEBUG_DEFAULT_STDERR);
69
70         talloc_set_log_fn(_samba_cmdline_talloc_log);
71         talloc_set_abort_fn(smb_panic);
72
73         return true;
74 }
75
76 bool samba_cmdline_set_load_config_fn(samba_cmdline_load_config fn)
77 {
78         cmdline_load_config_fn = fn;
79         return true;
80 }
81
82 /* PUBLIC */
83 bool samba_cmdline_set_lp_ctx(struct loadparm_context *lp_ctx)
84 {
85         if (lp_ctx == NULL) {
86                 return false;
87         }
88         cmdline_lp_ctx = lp_ctx;
89
90         return true;
91 }
92
93 struct loadparm_context *samba_cmdline_get_lp_ctx(void)
94 {
95         return cmdline_lp_ctx;
96 }
97
98 bool samba_cmdline_set_creds(struct cli_credentials *creds)
99 {
100         if (creds == NULL) {
101                 return false;
102         }
103
104         TALLOC_FREE(cmdline_creds);
105         cmdline_creds = creds;
106
107         return true;
108 }
109
110 struct cli_credentials *samba_cmdline_get_creds(void)
111 {
112         return cmdline_creds;
113 }
114
115 void samba_cmdline_burn(int argc, char *argv[])
116 {
117         bool found = false;
118         bool is_user = false;
119         char *p = NULL;
120         int i, ulen = 0;
121
122         for (i = 0; i < argc; i++) {
123                 p = argv[i];
124                 if (p == NULL) {
125                         return;
126                 }
127
128                 if (strncmp(p, "-U", 2) == 0) {
129                         ulen = 2;
130                         found = true;
131                         is_user = true;
132                 } else if (strncmp(p, "--user", 6) == 0) {
133                         ulen = 6;
134                         found = true;
135                         is_user = true;
136                 } else if (strncmp(p, "--password", 10) == 0) {
137                         ulen = 10;
138                         found = true;
139                 }
140
141                 if (found) {
142                         char *q = NULL;
143
144                         if (strlen(p) == ulen) {
145                                 continue;
146                         }
147
148                         if (is_user) {
149                                 q = strchr_m(p, '%');
150                                 if (q != NULL) {
151                                         p = q;
152                                 }
153                         } else {
154                                 p += ulen;
155                         }
156
157                         memset_s(p, strlen(p), '\0', strlen(p));
158                         found = false;
159                         is_user = false;
160                 }
161         }
162 }
163
164 static bool is_popt_table_end(const struct poptOption *o)
165 {
166         if (o->longName == NULL &&
167             o->shortName == 0 &&
168             o->argInfo == 0 &&
169             o->arg == NULL &&
170             o->val == 0 &&
171             o->descrip == NULL &&
172             o->argDescrip == NULL) {
173                 return true;
174         }
175
176         return false;
177 }
178
179 static void find_duplicates(const struct poptOption *needle,
180                             const struct poptOption *haystack,
181                             size_t *count)
182 {
183         for(;
184             !is_popt_table_end(haystack);
185             haystack++) {
186                 switch (haystack->argInfo) {
187                 case POPT_ARG_INCLUDE_TABLE:
188                         if (haystack->arg != NULL) {
189                                 find_duplicates(needle, haystack->arg, count);
190                         }
191
192                         break;
193                 default:
194                         if (needle->shortName != 0 &&
195                             needle->shortName == haystack->shortName) {
196                                 (*count)++;
197                                 break;
198                         }
199
200                         if (needle->longName != NULL &&
201                             haystack->longName != NULL &&
202                             strequal(needle->longName, haystack->longName)) {
203                                 (*count)++;
204                                 break;
205                         }
206                         break;
207                 }
208
209                 if (*count > 1) {
210                         return;
211                 }
212         }
213 }
214
215 static bool cmdline_sanity_checker(const struct poptOption *current_opts,
216                              const struct poptOption *full_opts)
217 {
218         const struct poptOption *o = current_opts;
219
220         for(;
221             !is_popt_table_end(o);
222             o++) {
223                 bool ok;
224
225                 switch (o->argInfo) {
226                 case POPT_ARG_INCLUDE_TABLE:
227                         if (o->arg != NULL) {
228                                 ok = cmdline_sanity_checker(o->arg, full_opts);
229                                 if (!ok) {
230                                         return false;
231                                 }
232                         }
233
234                         break;
235                 default:
236                         if (o->longName != NULL || o->shortName != 0) {
237                                 size_t count = 0;
238
239                                 find_duplicates(o, full_opts, &count);
240                                 if (count > 1) {
241                                         DBG_ERR("Duplicate option '--%s|-%c' "
242                                                 "detected!\n",
243                                                 o->longName,
244                                                 o->shortName != 0 ?
245                                                         o->shortName :
246                                                         '-');
247                                         return false;
248                                 }
249                         }
250
251                         break;
252                 }
253         }
254
255         return true;
256 }
257
258 bool samba_cmdline_sanity_check(const struct poptOption *opts)
259 {
260         return cmdline_sanity_checker(opts, opts);
261 }
262
263 poptContext samba_popt_get_context(const char * name,
264                                    int argc, const char ** argv,
265                                    const struct poptOption * options,
266                                    unsigned int flags)
267 {
268 #ifdef DEVELOPER
269         bool ok;
270
271         ok = samba_cmdline_sanity_check(options);
272         if (!ok) {
273                 return NULL;
274         }
275 #endif
276         return poptGetContext(name, argc, argv, options, flags);
277 }
278
279 /**********************************************************
280  * COMMON SAMBA POPT
281  **********************************************************/
282
283 static bool log_to_file;
284
285 static void popt_samba_callback(poptContext popt_ctx,
286                                 enum poptCallbackReason reason,
287                                 const struct poptOption *opt,
288                                 const char *arg, const void *data)
289 {
290         TALLOC_CTX *mem_ctx = samba_cmdline_get_talloc_ctx();
291         struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
292         const char *pname = NULL;
293         bool ok;
294
295         if (reason == POPT_CALLBACK_REASON_PRE) {
296                 if (lp_ctx == NULL) {
297                         fprintf(stderr,
298                                 "Command line parsing not initialized!\n");
299                         exit(1);
300                 }
301                 return;
302         }
303
304         if (reason == POPT_CALLBACK_REASON_POST) {
305                 ok = cmdline_load_config_fn();
306                 if (!ok) {
307                         fprintf(stderr,
308                                 "%s - Failed to load config file!\n",
309                                 getprogname());
310                         exit(1);
311                 }
312
313                 if (log_to_file) {
314                         const struct loadparm_substitution *lp_sub =
315                                 lpcfg_noop_substitution();
316                         char *logfile = NULL;
317
318                         logfile = lpcfg_logfile(lp_ctx, lp_sub, mem_ctx);
319                         if (logfile == NULL) {
320                                 fprintf(stderr,
321                                         "Failed to setup logging to file!");
322                                         exit(1);
323                         }
324                         debug_set_logfile(logfile);
325                         setup_logging(logfile, DEBUG_FILE);
326                         TALLOC_FREE(logfile);
327                 }
328
329                 return;
330         }
331
332         /* Find out basename of current program */
333         pname = strrchr_m(poptGetInvocationName(popt_ctx), '/');
334         if (pname == NULL) {
335                 pname = poptGetInvocationName(popt_ctx);
336         } else {
337                 pname++;
338         }
339
340         switch(opt->val) {
341         case OPT_LEAK_REPORT:
342                 talloc_enable_leak_report();
343                 break;
344         case OPT_LEAK_REPORT_FULL:
345                 talloc_enable_leak_report_full();
346                 break;
347         case OPT_OPTION:
348                 if (arg != NULL) {
349                         ok = lpcfg_set_option(lp_ctx, arg);
350                         if (!ok) {
351                                 fprintf(stderr, "Error setting option '%s'\n", arg);
352                                 exit(1);
353                         }
354                 }
355                 break;
356         case 'd':
357                 if (arg != NULL) {
358                         ok = lpcfg_set_cmdline(lp_ctx, "log level", arg);
359                         if (!ok) {
360                                 fprintf(stderr,
361                                         "Failed to set debug level to: %s\n",
362                                         arg);
363                                 exit(1);
364                         }
365                 }
366                 break;
367         case OPT_DEBUG_STDOUT:
368                 setup_logging(pname, DEBUG_STDOUT);
369                 break;
370         case OPT_CONFIGFILE:
371                 if (arg != NULL) {
372                         set_dyn_CONFIGFILE(arg);
373                 }
374                 break;
375         case 'l':
376                 if (arg != NULL) {
377                         char *new_logfile = talloc_asprintf(mem_ctx,
378                                                             "%s/log.%s",
379                                                             arg,
380                                                             pname);
381                         if (new_logfile == NULL) {
382                                 fprintf(stderr,
383                                         "Failed to allocate memory\n");
384                                 exit(1);
385                         }
386
387                         ok = lpcfg_set_cmdline(lp_ctx,
388                                                "log file",
389                                                new_logfile);
390                         if (!ok) {
391                                 fprintf(stderr,
392                                         "Failed to set log file: %s\n",
393                                         new_logfile);
394                                 TALLOC_FREE(new_logfile);
395                                 exit(1);
396                         }
397                         log_to_file = true;
398
399                         set_dyn_LOGFILEBASE(arg);
400
401                         TALLOC_FREE(new_logfile);
402                 }
403                 break;
404         }
405 }
406
407 static struct poptOption popt_common_samba[] = {
408         {
409                 .argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
410                 .arg        = (void *)popt_samba_callback,
411         },
412         {
413                 .longName   = "debuglevel",
414                 .shortName  = 'd',
415                 .argInfo    = POPT_ARG_STRING,
416                 .val        = 'd',
417                 .descrip    = "Set debug level",
418                 .argDescrip = "DEBUGLEVEL",
419         },
420         {
421                 .longName   = "debug-stdout",
422                 .argInfo    = POPT_ARG_NONE,
423                 .val        = OPT_DEBUG_STDOUT,
424                 .descrip    = "Send debug output to standard output",
425         },
426         {
427                 .longName   = "configfile",
428                 .shortName  = 's',
429                 .argInfo    = POPT_ARG_STRING,
430                 .val        = OPT_CONFIGFILE,
431                 .descrip    = "Use alternative configuration file",
432                 .argDescrip = "CONFIGFILE",
433         },
434         {
435                 .longName   = "option",
436                 .argInfo    = POPT_ARG_STRING,
437                 .val        = OPT_OPTION,
438                 .descrip    = "Set smb.conf option from command line",
439                 .argDescrip = "name=value",
440         },
441         {
442                 .longName   = "log-basename",
443                 .shortName  = 'l',
444                 .argInfo    = POPT_ARG_STRING,
445                 .val        = 'l',
446                 .descrip    = "Basename for log/debug files",
447                 .argDescrip = "LOGFILEBASE",
448         },
449         {
450                 .longName   = "leak-report",
451                 .argInfo    = POPT_ARG_NONE,
452                 .val        = OPT_LEAK_REPORT,
453                 .descrip    = "enable talloc leak reporting on exit",
454         },
455         {
456                 .longName   = "leak-report-full",
457                 .argInfo    = POPT_ARG_NONE,
458                 .val        = OPT_LEAK_REPORT_FULL,
459                 .descrip    = "enable full talloc leak reporting on exit",
460         },
461         POPT_TABLEEND
462 };
463
464 static struct poptOption popt_common_samba_ldb[] = {
465         {
466                 .argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
467                 .arg        = (void *)popt_samba_callback,
468         },
469         {
470                 .longName   = "debuglevel",
471                 .shortName  = 'd',
472                 .argInfo    = POPT_ARG_STRING,
473                 .val        = 'd',
474                 .descrip    = "Set debug level",
475                 .argDescrip = "DEBUGLEVEL",
476         },
477         {
478                 .longName   = "debug-stdout",
479                 .argInfo    = POPT_ARG_NONE,
480                 .val        = OPT_DEBUG_STDOUT,
481                 .descrip    = "Send debug output to standard output",
482         },
483         {
484                 .longName   = "configfile",
485                 .argInfo    = POPT_ARG_STRING,
486                 .val        = OPT_CONFIGFILE,
487                 .descrip    = "Use alternative configuration file",
488                 .argDescrip = "CONFIGFILE",
489         },
490         {
491                 .longName   = "option",
492                 .argInfo    = POPT_ARG_STRING,
493                 .val        = OPT_OPTION,
494                 .descrip    = "Set smb.conf option from command line",
495                 .argDescrip = "name=value",
496         },
497         {
498                 .longName   = "log-basename",
499                 .shortName  = 'l',
500                 .argInfo    = POPT_ARG_STRING,
501                 .val        = 'l',
502                 .descrip    = "Basename for log/debug files",
503                 .argDescrip = "LOGFILEBASE",
504         },
505         {
506                 .longName   = "leak-report",
507                 .argInfo    = POPT_ARG_NONE,
508                 .val        = OPT_LEAK_REPORT,
509                 .descrip    = "enable talloc leak reporting on exit",
510         },
511         {
512                 .longName   = "leak-report-full",
513                 .argInfo    = POPT_ARG_NONE,
514                 .val        = OPT_LEAK_REPORT_FULL,
515                 .descrip    = "enable full talloc leak reporting on exit",
516         },
517         POPT_TABLEEND
518 };
519
520 /**********************************************************
521  * CONNECTION POPT
522  **********************************************************/
523
524 static void popt_connection_callback(poptContext popt_ctx,
525                                      enum poptCallbackReason reason,
526                                      const struct poptOption *opt,
527                                      const char *arg,
528                                      const void *data)
529 {
530         struct loadparm_context *lp_ctx = cmdline_lp_ctx;
531
532         if (reason == POPT_CALLBACK_REASON_PRE) {
533                 if (lp_ctx == NULL) {
534                         fprintf(stderr,
535                                 "Command line parsing not initialized!\n");
536                         exit(1);
537                 }
538                 return;
539         }
540
541         switch(opt->val) {
542         case 'O':
543                 if (arg != NULL) {
544                         lpcfg_set_cmdline(lp_ctx, "socket options", arg);
545                 }
546                 break;
547         case 'R':
548                 if (arg != NULL) {
549                         lpcfg_set_cmdline(lp_ctx, "name resolve order", arg);
550                 }
551                 break;
552         case 'm':
553                 if (arg != NULL) {
554                         lpcfg_set_cmdline(lp_ctx, "client max protocol", arg);
555                 }
556                 break;
557         case OPT_NETBIOS_SCOPE:
558                 if (arg != NULL) {
559                         lpcfg_set_cmdline(lp_ctx, "netbios scope", arg);
560                 }
561                 break;
562         case 'n':
563                 if (arg != NULL) {
564                         lpcfg_set_cmdline(lp_ctx, "netbios name", arg);
565                 }
566                 break;
567         case 'W':
568                 if (arg != NULL) {
569                         lpcfg_set_cmdline(lp_ctx, "workgroup", arg);
570                 }
571                 break;
572         case 'r':
573                 if (arg != NULL) {
574                         lpcfg_set_cmdline(lp_ctx, "realm", arg);
575                 }
576                 break;
577         }
578 }
579
580 static struct poptOption popt_common_connection[] = {
581         {
582                 .argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE,
583                 .arg        = (void *)popt_connection_callback,
584         },
585         {
586                 .longName   = "name-resolve",
587                 .shortName  = 'R',
588                 .argInfo    = POPT_ARG_STRING,
589                 .val        = 'R',
590                 .descrip    = "Use these name resolution services only",
591                 .argDescrip = "NAME-RESOLVE-ORDER",
592         },
593         {
594                 .longName   = "socket-options",
595                 .shortName  = 'O',
596                 .argInfo    = POPT_ARG_STRING,
597                 .val        = 'O',
598                 .descrip    = "socket options to use",
599                 .argDescrip = "SOCKETOPTIONS",
600         },
601         {
602                 .longName   = "maxprotocol",
603                 .shortName  = 'm',
604                 .argInfo    = POPT_ARG_STRING,
605                 .val        = 'm',
606                 .descrip    = "Set max protocol level",
607                 .argDescrip = "MAXPROTOCOL",
608         },
609         {
610                 .longName   = "netbiosname",
611                 .shortName  = 'n',
612                 .argInfo    = POPT_ARG_STRING,
613                 .val        = 'n',
614                 .descrip    = "Primary netbios name",
615                 .argDescrip = "NETBIOSNAME",
616         },
617         {
618                 .longName   = "netbios-scope",
619                 .argInfo    = POPT_ARG_STRING,
620                 .val        = OPT_NETBIOS_SCOPE,
621                 .descrip    = "Use this Netbios scope",
622                 .argDescrip = "SCOPE",
623         },
624         {
625                 .longName   = "workgroup",
626                 .shortName  = 'W',
627                 .argInfo    = POPT_ARG_STRING,
628                 .val        = 'W',
629                 .descrip    = "Set the workgroup name",
630                 .argDescrip = "WORKGROUP",
631         },
632         {
633                 .longName   = "realm",
634                 .argInfo    = POPT_ARG_STRING,
635                 .val        = 'r',
636                 .descrip    = "Set the realm name",
637                 .argDescrip = "REALM",
638         },
639         POPT_TABLEEND
640 };
641
642 /**********************************************************
643  * CREDENTIALS POPT
644  **********************************************************/
645
646 static bool skip_password_callback;
647 static bool machine_account_pending;
648
649 static void popt_common_credentials_callback(poptContext popt_ctx,
650                                              enum poptCallbackReason reason,
651                                              const struct poptOption *opt,
652                                              const char *arg,
653                                              const void *data)
654 {
655         struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx();
656         struct cli_credentials *creds = samba_cmdline_get_creds();
657         bool ok;
658
659         if (reason == POPT_CALLBACK_REASON_PRE) {
660                 if (creds == NULL) {
661                         fprintf(stderr,
662                                 "Command line parsing not initialized!\n");
663                         exit(1);
664                 }
665                 return;
666         }
667
668         if (reason == POPT_CALLBACK_REASON_POST) {
669                 const char *username = NULL;
670                 enum credentials_obtained username_obtained =
671                         CRED_UNINITIALISED;
672                 enum credentials_obtained password_obtained =
673                         CRED_UNINITIALISED;
674
675                 /*
676                  * This calls cli_credentials_set_conf() to get the defaults
677                  * form smb.conf and set the winbind separator.
678                  */
679                 cli_credentials_guess(creds, lp_ctx);
680
681                 (void)cli_credentials_get_password_and_obtained(creds,
682                                                                 &password_obtained);
683                 if (!skip_password_callback &&
684                     password_obtained < CRED_CALLBACK) {
685                         ok = cli_credentials_set_cmdline_callbacks(creds);
686                         if (!ok) {
687                                 fprintf(stderr,
688                                         "Failed to set cmdline password "
689                                         "callback\n");
690                                 exit(1);
691                         }
692                 }
693
694                 if (machine_account_pending) {
695                         NTSTATUS status;
696
697                         status = cli_credentials_set_machine_account(creds,
698                                                                      lp_ctx);
699                         if (!NT_STATUS_IS_OK(status)) {
700                                 fprintf(stderr,
701                                         "Failed to set machine account: %s\n",
702                                         nt_errstr(status));
703                                 exit(1);
704                         }
705                 }
706
707                 /*
708                  * When we set the username during the handling of the options
709                  * passed to the binary we haven't loaded the config yet. This
710                  * means that we didn't take the 'winbind separator' into
711                  * account.
712                  *
713                  * The username might contain the domain name and thus it
714                  * hasn't been correctly parsed yet. If we have a username we
715                  * need to set it again to run the string parser for the
716                  * username correctly.
717                  */
718                 username =
719                         cli_credentials_get_username_and_obtained(
720                                         creds, &username_obtained);
721                 if (username_obtained == CRED_SPECIFIED &&
722                     username != NULL && username[0] != '\0') {
723                         cli_credentials_parse_string(creds,
724                                                      username,
725                                                      CRED_SPECIFIED);
726                 }
727
728                 return;
729         }
730
731         switch(opt->val) {
732         case 'U':
733                 if (arg != NULL) {
734                         cli_credentials_parse_string(creds,
735                                                      arg,
736                                                      CRED_SPECIFIED);
737                 }
738                 break;
739         case OPT_PASSWORD:
740                 if (arg != NULL) {
741                         ok = cli_credentials_set_password(creds,
742                                                           arg,
743                                                           CRED_SPECIFIED);
744                         if (!ok) {
745                                 fprintf(stderr,
746                                         "Failed to set password!\n");
747                                 exit(1);
748                         }
749
750                         skip_password_callback = true;
751                 }
752                 break;
753         case OPT_NT_HASH:
754                 cli_credentials_set_password_will_be_nt_hash(creds, true);
755                 break;
756         case 'A':
757                 if (arg != NULL) {
758                         ok = cli_credentials_parse_file(creds,
759                                                         arg,
760                                                         CRED_SPECIFIED);
761                         if (!ok) {
762                                 fprintf(stderr,
763                                         "Failed to set parse authentication file!\n");
764                                 exit(1);
765                         }
766                         skip_password_callback = true;
767                 }
768                 break;
769         case 'N':
770                 ok = cli_credentials_set_password(creds,
771                                                   NULL,
772                                                   CRED_SPECIFIED);
773                 if (!ok) {
774                         fprintf(stderr,
775                                 "Failed to set password!\n");
776                         exit(1);
777                 }
778                 skip_password_callback = true;
779                 break;
780         case 'P':
781                 /*
782                  * Later, after this is all over, get the machine account
783                  * details from the secrets.(l|t)db.
784                  */
785                 machine_account_pending = true;
786                 break;
787         case OPT_SIMPLE_BIND_DN:
788                 if (arg != NULL) {
789                         ok = cli_credentials_set_bind_dn(creds, arg);
790                         if (!ok) {
791                                 fprintf(stderr,
792                                         "Failed to set bind DN!\n");
793                                 exit(1);
794                         }
795                 }
796                 break;
797         case OPT_USE_KERBEROS:
798                 if (arg != NULL) {
799                         int32_t use_kerberos =
800                                 lpcfg_parse_enum_vals("client use kerberos", arg);
801
802                         if (use_kerberos == INT_MIN) {
803                                 fprintf(stderr, "Failed to parse --use-kerberos\n");
804                                 exit(1);
805                         }
806
807                         ok = cli_credentials_set_kerberos_state(creds,
808                                                                 use_kerberos,
809                                                                 CRED_SPECIFIED);
810                         if (!ok) {
811                                 fprintf(stderr,
812                                         "Failed to set Kerberos state to %s!\n", arg);
813                                 exit(1);
814                         }
815                 }
816                 break;
817         case OPT_USE_KERBEROS_CCACHE:
818                 if (arg != NULL) {
819                         const char *error_string = NULL;
820                         int rc;
821
822                         ok = cli_credentials_set_kerberos_state(creds,
823                                                                 CRED_USE_KERBEROS_REQUIRED,
824                                                                 CRED_SPECIFIED);
825                         if (!ok) {
826                                 fprintf(stderr,
827                                         "Failed to set Kerberos state to %s!\n", arg);
828                                 exit(1);
829                         }
830
831                         rc = cli_credentials_set_ccache(creds,
832                                                         lp_ctx,
833                                                         arg,
834                                                         CRED_SPECIFIED,
835                                                         &error_string);
836                         if (rc != 0) {
837                                 fprintf(stderr,
838                                         "Error reading krb5 credentials cache: '%s'"
839                                         " - %s\n",
840                                         arg,
841                                         error_string);
842                                 exit(1);
843                         }
844
845                         skip_password_callback = true;
846                 }
847                 break;
848         case OPT_USE_WINBIND_CCACHE:
849         {
850                 uint32_t gensec_features;
851
852                 gensec_features = cli_credentials_get_gensec_features(creds);
853                 gensec_features |= GENSEC_FEATURE_NTLM_CCACHE;
854
855                 ok = cli_credentials_set_gensec_features(creds,
856                                                          gensec_features,
857                                                          CRED_SPECIFIED);
858                 if (!ok) {
859                         fprintf(stderr,
860                                 "Failed to set gensec feature!\n");
861                         exit(1);
862                 }
863
864                 skip_password_callback = true;
865                 break;
866         }
867         case OPT_CLIENT_PROTECTION:
868                 if (arg != NULL) {
869                         uint32_t gensec_features;
870                         enum smb_signing_setting signing_state =
871                                 SMB_SIGNING_OFF;
872                         enum smb_encryption_setting encryption_state =
873                                 SMB_ENCRYPTION_OFF;
874
875                         gensec_features =
876                                 cli_credentials_get_gensec_features(
877                                                 creds);
878
879                         if (strequal(arg, "off")) {
880                                 gensec_features &=
881                                         ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL);
882
883                                 signing_state = SMB_SIGNING_OFF;
884                                 encryption_state = SMB_ENCRYPTION_OFF;
885                         } else if (strequal(arg, "sign")) {
886                                 gensec_features |= GENSEC_FEATURE_SIGN;
887
888                                 signing_state = SMB_SIGNING_REQUIRED;
889                                 encryption_state = SMB_ENCRYPTION_OFF;
890                         } else if (strequal(arg, "encrypt")) {
891                                 gensec_features |= GENSEC_FEATURE_SEAL;
892
893                                 signing_state = SMB_SIGNING_REQUIRED;
894                                 encryption_state = SMB_ENCRYPTION_REQUIRED;
895                         } else {
896                                 fprintf(stderr,
897                                         "Failed to parse --client-protection\n");
898                                 exit(1);
899                         }
900
901                         ok = cli_credentials_set_gensec_features(creds,
902                                                                  gensec_features,
903                                                                  CRED_SPECIFIED);
904                         if (!ok) {
905                                 fprintf(stderr,
906                                         "Failed to set gensec feature!\n");
907                                 exit(1);
908                         }
909
910                         ok = cli_credentials_set_smb_signing(creds,
911                                                              signing_state,
912                                                              CRED_SPECIFIED);
913                         if (!ok) {
914                                 fprintf(stderr,
915                                         "Failed to set smb signing!\n");
916                                 exit(1);
917                         }
918
919                         ok = cli_credentials_set_smb_encryption(creds,
920                                                                 encryption_state,
921                                                                 CRED_SPECIFIED);
922                         if (!ok) {
923                                 fprintf(stderr,
924                                         "Failed to set smb encryption!\n");
925                                 exit(1);
926                         }
927                 }
928                 break;
929         } /* switch */
930 }
931
932 static struct poptOption popt_common_credentials[] = {
933         {
934                 .argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
935                 .arg        = (void *)popt_common_credentials_callback,
936         },
937         {
938                 .longName   = "user",
939                 .shortName  = 'U',
940                 .argInfo    = POPT_ARG_STRING,
941                 .val        = 'U',
942                 .descrip    = "Set the network username",
943                 .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
944         },
945         {
946                 .longName   = "no-pass",
947                 .shortName  = 'N',
948                 .argInfo    = POPT_ARG_NONE,
949                 .val        = 'N',
950                 .descrip    = "Don't ask for a password",
951         },
952         {
953                 .longName   = "password",
954                 .argInfo    = POPT_ARG_STRING,
955                 .val        = OPT_PASSWORD,
956                 .descrip    = "Password",
957         },
958         {
959                 .longName   = "pw-nt-hash",
960                 .argInfo    = POPT_ARG_NONE,
961                 .val        = OPT_NT_HASH,
962                 .descrip    = "The supplied password is the NT hash",
963         },
964         {
965                 .longName   = "authentication-file",
966                 .shortName  = 'A',
967                 .argInfo    = POPT_ARG_STRING,
968                 .val        = 'A',
969                 .descrip    = "Get the credentials from a file",
970                 .argDescrip = "FILE",
971         },
972         {
973                 .longName   = "machine-pass",
974                 .shortName  = 'P',
975                 .argInfo    = POPT_ARG_NONE,
976                 .val        = 'P',
977                 .descrip    = "Use stored machine account password",
978         },
979         {
980                 .longName   = "simple-bind-dn",
981                 .argInfo    = POPT_ARG_STRING,
982                 .val        = OPT_SIMPLE_BIND_DN,
983                 .descrip    = "DN to use for a simple bind",
984                 .argDescrip = "DN",
985         },
986         {
987                 .longName   = "use-kerberos",
988                 .argInfo    = POPT_ARG_STRING,
989                 .val        = OPT_USE_KERBEROS,
990                 .descrip    = "Use Kerberos authentication",
991                 .argDescrip = "desired|required|off",
992         },
993         {
994                 .longName   = "use-krb5-ccache",
995                 .argInfo    = POPT_ARG_STRING,
996                 .val        = OPT_USE_KERBEROS_CCACHE,
997                 .descrip    = "Credentials cache location for Kerberos",
998                 .argDescrip = "CCACHE",
999         },
1000         {
1001                 .longName   = "use-winbind-ccache",
1002                 .argInfo    = POPT_ARG_NONE,
1003                 .val        = OPT_USE_WINBIND_CCACHE,
1004                 .descrip    = "Use the winbind ccache for authentication",
1005         },
1006         {
1007                 .longName   = "client-protection",
1008                 .argInfo    = POPT_ARG_STRING,
1009                 .val        = OPT_CLIENT_PROTECTION,
1010                 .descrip    = "Configure used protection for client connections",
1011                 .argDescrip = "sign|encrypt|off",
1012         },
1013         POPT_TABLEEND
1014 };
1015
1016 /**********************************************************
1017  * VERSION POPT
1018  **********************************************************/
1019
1020 static void popt_version_callback(poptContext ctx,
1021                                   enum poptCallbackReason reason,
1022                                   const struct poptOption *opt,
1023                                   const char *arg,
1024                                   const void *data)
1025 {
1026         switch(opt->val) {
1027         case 'V':
1028                 printf("Version %s\n", SAMBA_VERSION_STRING);
1029                 exit(0);
1030         }
1031 }
1032
1033 static struct poptOption popt_common_version[] = {
1034         {
1035                 .argInfo    = POPT_ARG_CALLBACK,
1036                 .arg        = (void *)popt_version_callback,
1037         },
1038         {
1039                 .longName   = "version",
1040                 .shortName  = 'V',
1041                 .argInfo    = POPT_ARG_NONE,
1042                 .val        = 'V',
1043                 .descrip    = "Print version",
1044         },
1045         POPT_TABLEEND
1046 };
1047
1048 /**********************************************************
1049  * LEGACY S3 POPT
1050  **********************************************************/
1051
1052 static void popt_legacy_s3_callback(poptContext ctx,
1053                                     enum poptCallbackReason reason,
1054                                     const struct poptOption *opt,
1055                                     const char *arg,
1056                                     const void *data)
1057 {
1058         struct cli_credentials *creds = samba_cmdline_get_creds();
1059         bool ok;
1060
1061         switch(opt->val) {
1062         case 'k':
1063                 fprintf(stderr,
1064                         "WARNING: The option -k|--kerberos is deprecated!\n");
1065
1066                 ok = cli_credentials_set_kerberos_state(creds,
1067                                                         CRED_USE_KERBEROS_REQUIRED,
1068                                                         CRED_SPECIFIED);
1069                 if (!ok) {
1070                         fprintf(stderr,
1071                                 "Failed to set Kerberos state to %s!\n", arg);
1072                         exit(1);
1073                 }
1074
1075                 skip_password_callback = true;
1076                 break;
1077         }
1078 }
1079
1080 /* We allow '-k yes' too. */
1081 static struct poptOption popt_legacy_s3[] = {
1082         {
1083                 .argInfo    = POPT_ARG_CALLBACK,
1084                 .arg        = (void *)popt_legacy_s3_callback,
1085         },
1086         {
1087                 .longName   = "kerberos",
1088                 .shortName  = 'k',
1089                 .argInfo    = POPT_ARG_STRING,
1090                 .val        = 'k',
1091                 .descrip    = "DEPRECATED: Migrate to --use-kerberos",
1092         },
1093         POPT_TABLEEND
1094 };
1095
1096 /**********************************************************
1097  * LEGACY S4 POPT
1098  **********************************************************/
1099
1100 static void popt_legacy_s4_callback(poptContext ctx,
1101                                     enum poptCallbackReason reason,
1102                                     const struct poptOption *opt,
1103                                     const char *arg,
1104                                     const void *data)
1105 {
1106         struct cli_credentials *creds = samba_cmdline_get_creds();
1107         bool ok;
1108
1109         switch(opt->val) {
1110         case 'k': {
1111                 enum credentials_use_kerberos use_kerberos =
1112                         CRED_USE_KERBEROS_REQUIRED;
1113
1114                 fprintf(stderr,
1115                         "WARNING: The option -k|--kerberos is deprecated!\n");
1116
1117                 if (arg != NULL) {
1118                         if (strcasecmp_m(arg, "yes") == 0) {
1119                                 use_kerberos = CRED_USE_KERBEROS_REQUIRED;
1120                         } else if (strcasecmp_m(arg, "no") == 0) {
1121                                 use_kerberos = CRED_USE_KERBEROS_DISABLED;
1122                         } else {
1123                                 fprintf(stderr,
1124                                         "Error parsing -k %s. Should be "
1125                                         "-k [yes|no]\n",
1126                                         arg);
1127                                 exit(1);
1128                         }
1129                 }
1130
1131                 ok = cli_credentials_set_kerberos_state(creds,
1132                                                         use_kerberos,
1133                                                         CRED_SPECIFIED);
1134                 if (!ok) {
1135                         fprintf(stderr,
1136                                 "Failed to set Kerberos state to %s!\n", arg);
1137                         exit(1);
1138                 }
1139
1140                 break;
1141         }
1142         }
1143 }
1144
1145 static struct poptOption popt_legacy_s4[] = {
1146         {
1147                 .argInfo    = POPT_ARG_CALLBACK,
1148                 .arg        = (void *)popt_legacy_s4_callback,
1149         },
1150         {
1151                 .longName   = "kerberos",
1152                 .shortName  = 'k',
1153                 .argInfo    = POPT_ARG_STRING,
1154                 .val        = 'k',
1155                 .descrip    = "DEPRECATED: Migrate to --use-kerberos",
1156         },
1157         POPT_TABLEEND
1158 };
1159
1160 struct poptOption *samba_cmdline_get_popt(enum smb_cmdline_popt_options opt)
1161 {
1162         switch (opt) {
1163         case SAMBA_CMDLINE_POPT_OPT_SAMBA:
1164                 return popt_common_samba;
1165                 break;
1166         case SAMBA_CMDLINE_POPT_OPT_CONNECTION:
1167                 return popt_common_connection;
1168                 break;
1169         case SAMBA_CMDLINE_POPT_OPT_CREDENTIALS:
1170                 return popt_common_credentials;
1171                 break;
1172         case SAMBA_CMDLINE_POPT_OPT_VERSION:
1173                 return popt_common_version;
1174                 break;
1175         case SAMBA_CMDLINE_POPT_OPT_SAMBA_LDB:
1176                 return popt_common_samba_ldb;
1177                 break;
1178         case SAMBA_CMDLINE_POPT_OPT_LEGACY_S3:
1179                 return popt_legacy_s3;
1180                 break;
1181         case SAMBA_CMDLINE_POPT_OPT_LEGACY_S4:
1182                 return popt_legacy_s4;
1183                 break;
1184         }
1185
1186         /* Never reached */
1187         return NULL;
1188 }