torture3: Fix CID 1435119 Error handling issues (CHECKED_RETURN)
[samba.git] / source3 / lib / popt_common.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Common popt routines
4
5    Copyright (C) Tim Potter 2001,2002
6    Copyright (C) Jelmer Vernooij 2002,2003
7    Copyright (C) James Peach 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "popt_common.h"
25 #include "lib/param/param.h"
26
27 /* Handle command line options:
28  *              -d,--debuglevel 
29  *              -s,--configfile 
30  *              -O,--socket-options 
31  *              -V,--version
32  *              -l,--log-base
33  *              -n,--netbios-name
34  *              -W,--workgroup
35  *              -i,--scope
36  */
37
38 enum {OPT_OPTION=1};
39
40 extern bool override_logfile;
41
42 static void set_logfile(poptContext con, const char * arg)
43 {
44
45         char *lfile = NULL;
46         const char *pname;
47
48         /* Find out basename of current program */
49         pname = strrchr_m(poptGetInvocationName(con),'/');
50
51         if (!pname)
52                 pname = poptGetInvocationName(con);
53         else
54                 pname++;
55
56         if (asprintf(&lfile, "%s/log.%s", arg, pname) < 0) {
57                 return;
58         }
59         lp_set_logfile(lfile);
60         SAFE_FREE(lfile);
61 }
62
63 static bool PrintSambaVersionString;
64
65 static void popt_s3_talloc_log_fn(const char *message)
66 {
67         DEBUG(0,("%s", message));
68 }
69
70 static void popt_common_callback(poptContext con,
71                            enum poptCallbackReason reason,
72                            const struct poptOption *opt,
73                            const char *arg, const void *data)
74 {
75
76         if (reason == POPT_CALLBACK_REASON_PRE) {
77                 set_logfile(con, get_dyn_LOGFILEBASE());
78                 talloc_set_log_fn(popt_s3_talloc_log_fn);
79                 talloc_set_abort_fn(smb_panic);
80                 return;
81         }
82
83         if (reason == POPT_CALLBACK_REASON_POST) {
84
85                 if (PrintSambaVersionString) {
86                         printf( "Version %s\n", samba_version_string());
87                         exit(0);
88                 }
89
90                 if (is_default_dyn_CONFIGFILE()) {
91                         if(getenv("SMB_CONF_PATH")) {
92                                 set_dyn_CONFIGFILE(getenv("SMB_CONF_PATH"));
93                         }
94                 }
95
96                 /* Further 'every Samba program must do this' hooks here. */
97                 return;
98         }
99
100         switch(opt->val) {
101         case OPT_OPTION:
102         {
103                 struct loadparm_context *lp_ctx;
104
105                 lp_ctx = loadparm_init_s3(talloc_tos(), loadparm_s3_helpers());
106                 if (lp_ctx == NULL) {
107                         fprintf(stderr, "loadparm_init_s3() failed!\n");
108                         exit(1);
109                 }
110
111                 if (!lpcfg_set_option(lp_ctx, arg)) {
112                         fprintf(stderr, "Error setting option '%s'\n", arg);
113                         exit(1);
114                 }
115                 TALLOC_FREE(lp_ctx);
116                 break;
117         }
118         case 'd':
119                 if (arg) {
120                         lp_set_cmdline("log level", arg);
121                 }
122                 break;
123
124         case 'V':
125                 PrintSambaVersionString = True;
126                 break;
127
128         case 'O':
129                 if (arg) {
130                         lp_set_cmdline("socket options", arg);
131                 }
132                 break;
133
134         case 's':
135                 if (arg) {
136                         set_dyn_CONFIGFILE(arg);
137                 }
138                 break;
139
140         case 'n':
141                 if (arg) {
142                         lp_set_cmdline("netbios name", arg);
143                 }
144                 break;
145
146         case 'l':
147                 if (arg) {
148                         set_logfile(con, arg);
149                         override_logfile = True;
150                         set_dyn_LOGFILEBASE(arg);
151                 }
152                 break;
153
154         case 'i':
155                 if (arg) {
156                         lp_set_cmdline("netbios scope", arg);
157                 }
158                 break;
159
160         case 'W':
161                 if (arg) {
162                         lp_set_cmdline("workgroup", arg);
163                 }
164                 break;
165         }
166 }
167
168 struct poptOption popt_common_connection[] = {
169         { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
170         { "socket-options", 'O', POPT_ARG_STRING, NULL, 'O', "socket options to use",
171           "SOCKETOPTIONS" },
172         { "netbiosname", 'n', POPT_ARG_STRING, NULL, 'n', "Primary netbios name", "NETBIOSNAME" },
173         { "workgroup", 'W', POPT_ARG_STRING, NULL, 'W', "Set the workgroup name", "WORKGROUP" },
174         { "scope", 'i', POPT_ARG_STRING, NULL, 'i', "Use this Netbios scope", "SCOPE" },
175
176         POPT_TABLEEND
177 };
178
179 struct poptOption popt_common_samba[] = {
180         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
181         { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
182         { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
183         { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" },
184         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
185         { "option",         0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" },
186         POPT_TABLEEND
187 };
188
189 struct poptOption popt_common_configfile[] = {
190         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST, (void *)popt_common_callback },
191         { "configfile", 0, POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
192         POPT_TABLEEND
193 };
194
195 struct poptOption popt_common_version[] = {
196         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback },
197         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
198         POPT_TABLEEND
199 };
200
201 struct poptOption popt_common_debuglevel[] = {
202         { NULL, 0, POPT_ARG_CALLBACK, (void *)popt_common_callback },
203         { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" },
204         POPT_TABLEEND
205 };
206
207 struct poptOption popt_common_option[] = {
208         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_POST, (void *)popt_common_callback },
209         { "option",         0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" },
210         POPT_TABLEEND
211 };
212
213 /* Handle command line options:
214  *              -U,--user
215  *              -A,--authentication-file
216  *              -k,--use-kerberos
217  *              -N,--no-pass
218  *              -S,--signing
219  *              -P --machine-pass
220  *              -e --encrypt
221  *              -C --use-ccache
222  */
223
224 static struct user_auth_info *cmdline_auth_info;
225
226 struct user_auth_info *popt_get_cmdline_auth_info(void)
227 {
228         return cmdline_auth_info;
229 }
230 void popt_free_cmdline_auth_info(void)
231 {
232         TALLOC_FREE(cmdline_auth_info);
233 }
234
235 static bool popt_common_credentials_ignore_missing_conf;
236 static bool popt_common_credentials_delay_post;
237
238 void popt_common_credentials_set_ignore_missing_conf(void)
239 {
240         popt_common_credentials_delay_post = true;
241 }
242
243 void popt_common_credentials_set_delay_post(void)
244 {
245         popt_common_credentials_delay_post = true;
246 }
247
248 void popt_common_credentials_post(void)
249 {
250         if (get_cmdline_auth_info_use_machine_account(cmdline_auth_info) &&
251             !set_cmdline_auth_info_machine_account_creds(cmdline_auth_info))
252         {
253                 fprintf(stderr,
254                         "Failed to use machine account credentials\n");
255                 exit(1);
256         }
257
258         set_cmdline_auth_info_getpass(cmdline_auth_info);
259
260         /*
261          * When we set the username during the handling of the options passed to
262          * the binary we haven't loaded the config yet. This means that we
263          * didnn't take the 'winbind separator' into account.
264          *
265          * The username might contain the domain name and thus it hasn't been
266          * correctly parsed yet. If we have a username we need to set it again
267          * to run the string parser for the username correctly.
268          */
269         reset_cmdline_auth_info_username(cmdline_auth_info);
270 }
271
272 static void popt_common_credentials_callback(poptContext con,
273                                         enum poptCallbackReason reason,
274                                         const struct poptOption *opt,
275                                         const char *arg, const void *data)
276 {
277         if (reason == POPT_CALLBACK_REASON_PRE) {
278                 struct user_auth_info *auth_info =
279                                 user_auth_info_init(NULL);
280                 if (auth_info == NULL) {
281                         fprintf(stderr, "user_auth_info_init() failed\n");
282                         exit(1);
283                 }
284                 cmdline_auth_info = auth_info;
285                 return;
286         }
287
288         if (reason == POPT_CALLBACK_REASON_POST) {
289                 bool ok;
290
291                 if (override_logfile) {
292                         setup_logging(lp_logfile(talloc_tos()), DEBUG_FILE );
293                 }
294
295                 ok = lp_load_client(get_dyn_CONFIGFILE());
296                 if (!ok) {
297                         const char *pname = poptGetInvocationName(con);
298
299                         fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
300                                 pname, get_dyn_CONFIGFILE());
301                         if (!popt_common_credentials_ignore_missing_conf) {
302                                 exit(1);
303                         }
304                 }
305
306                 load_interfaces();
307
308                 set_cmdline_auth_info_guess(cmdline_auth_info);
309
310                 if (popt_common_credentials_delay_post) {
311                         return;
312                 }
313
314                 popt_common_credentials_post();
315                 return;
316         }
317
318         switch(opt->val) {
319         case 'U':
320                 set_cmdline_auth_info_username(cmdline_auth_info, arg);
321                 break;
322
323         case 'A':
324                 set_cmdline_auth_info_from_file(cmdline_auth_info, arg);
325                 break;
326
327         case 'k':
328 #ifndef HAVE_KRB5
329                 d_printf("No kerberos support compiled in\n");
330                 exit(1);
331 #else
332                 set_cmdline_auth_info_use_krb5_ticket(cmdline_auth_info);
333 #endif
334                 break;
335
336         case 'S':
337                 if (!set_cmdline_auth_info_signing_state(cmdline_auth_info,
338                                 arg)) {
339                         fprintf(stderr, "Unknown signing option %s\n", arg );
340                         exit(1);
341                 }
342                 break;
343         case 'P':
344                 set_cmdline_auth_info_use_machine_account(cmdline_auth_info);
345                 break;
346         case 'N':
347                 set_cmdline_auth_info_password(cmdline_auth_info, "");
348                 break;
349         case 'e':
350                 set_cmdline_auth_info_smb_encrypt(cmdline_auth_info);
351                 break;
352         case 'C':
353                 set_cmdline_auth_info_use_ccache(cmdline_auth_info, true);
354                 break;
355         case 'H':
356                 set_cmdline_auth_info_use_pw_nt_hash(cmdline_auth_info, true);
357                 break;
358         }
359 }
360
361 /**
362  * @brief Burn the commandline password.
363  *
364  * This function removes the password from the command line so we
365  * don't leak the password e.g. in 'ps aux'.
366  *
367  * It should be called after processing the options and you should pass down
368  * argv from main().
369  *
370  * @param[in]  argc     The number of arguments.
371  *
372  * @param[in]  argv[]   The argument array we will find the array.
373  */
374 void popt_burn_cmdline_password(int argc, char *argv[])
375 {
376         bool found = false;
377         char *p = NULL;
378         int i, ulen = 0;
379
380         for (i = 0; i < argc; i++) {
381                 p = argv[i];
382                 if (strncmp(p, "-U", 2) == 0) {
383                         ulen = 2;
384                         found = true;
385                 } else if (strncmp(p, "--user", 6) == 0) {
386                         ulen = 6;
387                         found = true;
388                 }
389
390                 if (found) {
391                         if (p == NULL) {
392                                 return;
393                         }
394
395                         if (strlen(p) == ulen) {
396                                 continue;
397                         }
398
399                         p = strchr_m(p, '%');
400                         if (p != NULL) {
401                                 memset(p, '\0', strlen(p));
402                         }
403                         found = false;
404                 }
405         }
406 }
407
408 struct poptOption popt_common_credentials[] = {
409         { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
410           (void *)popt_common_credentials_callback, 0, NULL },
411         { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "USERNAME" },
412         { "no-pass", 'N', POPT_ARG_NONE, NULL, 'N', "Don't ask for a password" },
413         { "kerberos", 'k', POPT_ARG_NONE, NULL, 'k', "Use kerberos (active directory) authentication" },
414         { "authentication-file", 'A', POPT_ARG_STRING, NULL, 'A', "Get the credentials from a file", "FILE" },
415         { "signing", 'S', POPT_ARG_STRING, NULL, 'S', "Set the client signing state", "on|off|required" },
416         {"machine-pass", 'P', POPT_ARG_NONE, NULL, 'P', "Use stored machine account password" },
417         {"encrypt", 'e', POPT_ARG_NONE, NULL, 'e', "Encrypt SMB transport" },
418         {"use-ccache", 'C', POPT_ARG_NONE, NULL, 'C',
419          "Use the winbind ccache for authentication" },
420         {"pw-nt-hash", '\0', POPT_ARG_NONE, NULL, 'H',
421          "The supplied password is the NT hash" },
422         POPT_TABLEEND
423 };