TODO tests s3:popt_common: implement -k [yes|no] as alternative to just -k
[metze/samba/wip.git] / source3 / lib / popt_common_cmdline.c
1 /*
2    Unix SMB/CIFS implementation.
3    Common popt routines only used by cmdline utils
4
5    Copyright (C) Tim Potter 2001,2002
6    Copyright (C) Jelmer Vernooij 2002,2003
7    Copyright (C) James Peach 2006
8    Copyright (C) Christof Schmitt 2018
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /* Handle command line options:
25  *              -U,--user
26  *              -A,--authentication-file
27  *              -k,--kerberos[=yes|no]
28  *              -N,--no-pass
29  *              -S,--signing
30  *              -P --machine-pass
31  *              -e --encrypt
32  *              -C --use-ccache
33  */
34
35 #include "popt_common_cmdline.h"
36 #include "includes.h"
37 #include "auth_info.h"
38 #include "cmdline_contexts.h"
39
40 static struct user_auth_info *cmdline_auth_info;
41
42 struct user_auth_info *popt_get_cmdline_auth_info(void)
43 {
44         return cmdline_auth_info;
45 }
46 void popt_free_cmdline_auth_info(void)
47 {
48         TALLOC_FREE(cmdline_auth_info);
49 }
50
51 static bool popt_common_credentials_ignore_missing_conf;
52 static bool popt_common_credentials_delay_post;
53
54 void popt_common_credentials_set_ignore_missing_conf(void)
55 {
56         popt_common_credentials_ignore_missing_conf = true;
57 }
58
59 void popt_common_credentials_set_delay_post(void)
60 {
61         popt_common_credentials_delay_post = true;
62 }
63
64 void popt_common_credentials_post(void)
65 {
66         if (get_cmdline_auth_info_use_machine_account(cmdline_auth_info) &&
67             !set_cmdline_auth_info_machine_account_creds(cmdline_auth_info))
68         {
69                 fprintf(stderr,
70                         "Failed to use machine account credentials\n");
71                 exit(1);
72         }
73
74         set_cmdline_auth_info_getpass(cmdline_auth_info);
75
76         /*
77          * When we set the username during the handling of the options passed to
78          * the binary we haven't loaded the config yet. This means that we
79          * didn't take the 'winbind separator' into account.
80          *
81          * The username might contain the domain name and thus it hasn't been
82          * correctly parsed yet. If we have a username we need to set it again
83          * to run the string parser for the username correctly.
84          */
85         reset_cmdline_auth_info_username(cmdline_auth_info);
86 }
87
88 static void popt_common_credentials_callback(poptContext con,
89                                         enum poptCallbackReason reason,
90                                         const struct poptOption *opt,
91                                         const char *arg, const void *data)
92 {
93         bool use_kerberos = false;
94
95         if (reason == POPT_CALLBACK_REASON_PRE) {
96                 struct user_auth_info *auth_info =
97                                 user_auth_info_init(NULL);
98                 if (auth_info == NULL) {
99                         fprintf(stderr, "user_auth_info_init() failed\n");
100                         exit(1);
101                 }
102                 cmdline_auth_info = auth_info;
103                 return;
104         }
105
106         if (reason == POPT_CALLBACK_REASON_POST) {
107                 bool ok;
108
109                 ok = lp_load_client(get_dyn_CONFIGFILE());
110                 if (!ok) {
111                         const char *pname = poptGetInvocationName(con);
112
113                         fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
114                                 pname, get_dyn_CONFIGFILE());
115                         if (!popt_common_credentials_ignore_missing_conf) {
116                                 exit(1);
117                         }
118                 }
119
120                 load_interfaces();
121
122                 set_cmdline_auth_info_guess(cmdline_auth_info);
123
124                 if (popt_common_credentials_delay_post) {
125                         return;
126                 }
127
128                 popt_common_credentials_post();
129                 return;
130         }
131
132         switch(opt->val) {
133         case 'U':
134                 set_cmdline_auth_info_username(cmdline_auth_info, arg);
135                 break;
136
137         case 'A':
138                 set_cmdline_auth_info_from_file(cmdline_auth_info, arg);
139                 break;
140
141         case 'k':
142                 /* Force us to only use kerberos */
143                 if (arg) {
144                         if (!set_boolean(arg, &use_kerberos)) {
145                                 fprintf(stderr, "Error parsing -k %s. Should be "
146                                         "-k [yes|no]\n", arg);
147                                 exit(1);
148                                 break;
149                         }
150                 }
151
152                 if (use_kerberos) {
153 #ifndef HAVE_KRB5
154                         d_printf("No kerberos support compiled in\n");
155                         exit(1);
156 #endif
157                         set_cmdline_auth_info_use_krb5_ticket(cmdline_auth_info);
158                 } else {
159                         set_cmdline_auth_info_use_kerberos(cmdline_auth_info, false);
160                 }
161                 break;
162
163         case 'S':
164                 if (!set_cmdline_auth_info_signing_state(cmdline_auth_info,
165                                 arg)) {
166                         fprintf(stderr, "Unknown signing option %s\n", arg );
167                         exit(1);
168                 }
169                 break;
170         case 'P':
171                 set_cmdline_auth_info_use_machine_account(cmdline_auth_info);
172                 break;
173         case 'N':
174                 set_cmdline_auth_info_password(cmdline_auth_info, "");
175                 break;
176         case 'e':
177                 set_cmdline_auth_info_smb_encrypt(cmdline_auth_info);
178                 break;
179         case 'C':
180                 set_cmdline_auth_info_use_ccache(cmdline_auth_info, true);
181                 break;
182         case 'H':
183                 set_cmdline_auth_info_use_pw_nt_hash(cmdline_auth_info, true);
184                 break;
185         }
186 }
187
188 /**
189  * @brief Burn the commandline password.
190  *
191  * This function removes the password from the command line so we
192  * don't leak the password e.g. in 'ps aux'.
193  *
194  * It should be called after processing the options and you should pass down
195  * argv from main().
196  *
197  * @param[in]  argc     The number of arguments.
198  *
199  * @param[in]  argv[]   The argument array we will find the array.
200  */
201 void popt_burn_cmdline_password(int argc, char *argv[])
202 {
203         bool found = false;
204         char *p = NULL;
205         int i, ulen = 0;
206
207         for (i = 0; i < argc; i++) {
208                 p = argv[i];
209                 if (p == NULL) {
210                         return;
211                 }
212
213                 if (strncmp(p, "-U", 2) == 0) {
214                         ulen = 2;
215                         found = true;
216                 } else if (strncmp(p, "--user", 6) == 0) {
217                         ulen = 6;
218                         found = true;
219                 }
220
221                 if (found) {
222                         if (strlen(p) == ulen) {
223                                 continue;
224                         }
225
226                         p = strchr_m(p, '%');
227                         if (p != NULL) {
228                                 memset_s(p, strlen(p), '\0', strlen(p));
229                         }
230                         found = false;
231                 }
232         }
233 }
234
235 struct poptOption popt_common_credentials[] = {
236         {
237                 .argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
238                 .arg        = (void *)popt_common_credentials_callback,
239         },
240         {
241                 .longName   = "user",
242                 .shortName  = 'U',
243                 .argInfo    = POPT_ARG_STRING,
244                 .val        = 'U',
245                 .descrip    = "Set the network username",
246                 .argDescrip = "USERNAME",
247         },
248         {
249                 .longName   = "no-pass",
250                 .shortName  = 'N',
251                 .argInfo    = POPT_ARG_NONE,
252                 .val        = 'N',
253                 .descrip    = "Don't ask for a password",
254         },
255         {
256                 .longName   = "kerberos",
257                 .shortName  = 'k',
258                 .argInfo    = POPT_ARG_NONE,
259                 .val        = 'k',
260                 .descrip    = "Use kerberos (active directory) authentication, -k [yes|no]",
261         },
262         {
263                 .longName   = "authentication-file",
264                 .shortName  = 'A',
265                 .argInfo    = POPT_ARG_STRING,
266                 .val        = 'A',
267                 .descrip    = "Get the credentials from a file",
268                 .argDescrip = "FILE",
269         },
270         {
271                 .longName   = "signing",
272                 .shortName  = 'S',
273                 .argInfo    = POPT_ARG_STRING,
274                 .val        = 'S',
275                 .descrip    = "Set the client signing state",
276                 .argDescrip = "on|off|required",
277         },
278         {
279                 .longName   = "machine-pass",
280                 .shortName  = 'P',
281                 .argInfo    = POPT_ARG_NONE,
282                 .val        = 'P',
283                 .descrip    = "Use stored machine account password",
284         },
285         {
286                 .longName   = "encrypt",
287                 .shortName  = 'e',
288                 .argInfo    = POPT_ARG_NONE,
289                 .val        = 'e',
290                 .descrip    = "Encrypt SMB transport",
291         },
292         {
293                 .longName   = "use-ccache",
294                 .shortName  = 'C',
295                 .argInfo    = POPT_ARG_NONE,
296                 .val        = 'C',
297                 .descrip    = "Use the winbind ccache for authentication",
298         },
299         {
300                 .longName   = "pw-nt-hash",
301                 .shortName  = '\0',
302                 .argInfo    = POPT_ARG_NONE,
303                 .val        = 'H',
304                 .descrip    = "The supplied password is the NT hash",
305         },
306         POPT_TABLEEND
307 };