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,--use-kerberos
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 
popt_get_cmdline_auth_info(void)42 struct user_auth_info *popt_get_cmdline_auth_info(void)
43 {
44 	return cmdline_auth_info;
45 }
popt_free_cmdline_auth_info(void)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 
popt_common_credentials_set_ignore_missing_conf(void)54 void popt_common_credentials_set_ignore_missing_conf(void)
55 {
56 	popt_common_credentials_ignore_missing_conf = true;
57 }
58 
popt_common_credentials_set_delay_post(void)59 void popt_common_credentials_set_delay_post(void)
60 {
61 	popt_common_credentials_delay_post = true;
62 }
63 
popt_common_credentials_post(void)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 
popt_common_credentials_callback(poptContext con,enum poptCallbackReason reason,const struct poptOption * opt,const char * arg,const void * data)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 	if (reason == POPT_CALLBACK_REASON_PRE) {
94 		struct user_auth_info *auth_info =
95 				user_auth_info_init(NULL);
96 		if (auth_info == NULL) {
97 			fprintf(stderr, "user_auth_info_init() failed\n");
98 			exit(1);
99 		}
100 		cmdline_auth_info = auth_info;
101 		return;
102 	}
103 
104 	if (reason == POPT_CALLBACK_REASON_POST) {
105 		bool ok;
106 
107 		ok = lp_load_client(get_dyn_CONFIGFILE());
108 		if (!ok) {
109 			const char *pname = poptGetInvocationName(con);
110 
111 			fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
112 				pname, get_dyn_CONFIGFILE());
113 			if (!popt_common_credentials_ignore_missing_conf) {
114 				exit(1);
115 			}
116 		}
117 
118 		load_interfaces();
119 
120 		set_cmdline_auth_info_guess(cmdline_auth_info);
121 
122 		if (popt_common_credentials_delay_post) {
123 			return;
124 		}
125 
126 		popt_common_credentials_post();
127 		return;
128 	}
129 
130 	switch(opt->val) {
131 	case 'U':
132 		set_cmdline_auth_info_username(cmdline_auth_info, arg);
133 		break;
134 
135 	case 'A':
136 		set_cmdline_auth_info_from_file(cmdline_auth_info, arg);
137 		break;
138 
139 	case 'k':
140 #ifndef HAVE_KRB5
141 		d_printf("No kerberos support compiled in\n");
142 		exit(1);
143 #else
144 		set_cmdline_auth_info_use_krb5_ticket(cmdline_auth_info);
145 #endif
146 		break;
147 
148 	case 'S':
149 		if (!set_cmdline_auth_info_signing_state(cmdline_auth_info,
150 				arg)) {
151 			fprintf(stderr, "Unknown signing option %s\n", arg );
152 			exit(1);
153 		}
154 		break;
155 	case 'P':
156 		set_cmdline_auth_info_use_machine_account(cmdline_auth_info);
157 		break;
158 	case 'N':
159 		set_cmdline_auth_info_password(cmdline_auth_info, "");
160 		break;
161 	case 'e':
162 		set_cmdline_auth_info_smb_encrypt(cmdline_auth_info);
163 		break;
164 	case 'C':
165 		set_cmdline_auth_info_use_ccache(cmdline_auth_info, true);
166 		break;
167 	case 'H':
168 		set_cmdline_auth_info_use_pw_nt_hash(cmdline_auth_info, true);
169 		break;
170 	}
171 }
172 
173 /**
174  * @brief Burn the commandline password.
175  *
176  * This function removes the password from the command line so we
177  * don't leak the password e.g. in 'ps aux'.
178  *
179  * It should be called after processing the options and you should pass down
180  * argv from main().
181  *
182  * @param[in]  argc     The number of arguments.
183  *
184  * @param[in]  argv[]   The argument array we will find the array.
185  */
popt_burn_cmdline_password(int argc,char * argv[])186 void popt_burn_cmdline_password(int argc, char *argv[])
187 {
188 	bool found = false;
189 	char *p = NULL;
190 	int i, ulen = 0;
191 
192 	for (i = 0; i < argc; i++) {
193 		p = argv[i];
194 		if (p == NULL) {
195 			return;
196 		}
197 
198 		if (strncmp(p, "-U", 2) == 0) {
199 			ulen = 2;
200 			found = true;
201 		} else if (strncmp(p, "--user", 6) == 0) {
202 			ulen = 6;
203 			found = true;
204 		}
205 
206 		if (found) {
207 			if (strlen(p) == ulen) {
208 				continue;
209 			}
210 
211 			p = strchr_m(p, '%');
212 			if (p != NULL) {
213 				memset_s(p, strlen(p), '\0', strlen(p));
214 			}
215 			found = false;
216 		}
217 	}
218 }
219 
220 struct poptOption popt_common_credentials[] = {
221 	{
222 		.argInfo    = POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,
223 		.arg        = (void *)popt_common_credentials_callback,
224 	},
225 	{
226 		.longName   = "user",
227 		.shortName  = 'U',
228 		.argInfo    = POPT_ARG_STRING,
229 		.val        = 'U',
230 		.descrip    = "Set the network username",
231 		.argDescrip = "USERNAME",
232 	},
233 	{
234 		.longName   = "no-pass",
235 		.shortName  = 'N',
236 		.argInfo    = POPT_ARG_NONE,
237 		.val        = 'N',
238 		.descrip    = "Don't ask for a password",
239 	},
240 	{
241 		.longName   = "kerberos",
242 		.shortName  = 'k',
243 		.argInfo    = POPT_ARG_NONE,
244 		.val        = 'k',
245 		.descrip    = "Use kerberos (active directory) authentication",
246 	},
247 	{
248 		.longName   = "authentication-file",
249 		.shortName  = 'A',
250 		.argInfo    = POPT_ARG_STRING,
251 		.val        = 'A',
252 		.descrip    = "Get the credentials from a file",
253 		.argDescrip = "FILE",
254 	},
255 	{
256 		.longName   = "signing",
257 		.shortName  = 'S',
258 		.argInfo    = POPT_ARG_STRING,
259 		.val        = 'S',
260 		.descrip    = "Set the client signing state",
261 		.argDescrip = "on|off|required",
262 	},
263 	{
264 		.longName   = "machine-pass",
265 		.shortName  = 'P',
266 		.argInfo    = POPT_ARG_NONE,
267 		.val        = 'P',
268 		.descrip    = "Use stored machine account password",
269 	},
270 	{
271 		.longName   = "encrypt",
272 		.shortName  = 'e',
273 		.argInfo    = POPT_ARG_NONE,
274 		.val        = 'e',
275 		.descrip    = "Encrypt SMB transport",
276 	},
277 	{
278 		.longName   = "use-ccache",
279 		.shortName  = 'C',
280 		.argInfo    = POPT_ARG_NONE,
281 		.val        = 'C',
282 		.descrip    = "Use the winbind ccache for authentication",
283 	},
284 	{
285 		.longName   = "pw-nt-hash",
286 		.shortName  = '\0',
287 		.argInfo    = POPT_ARG_NONE,
288 		.val        = 'H',
289 		.descrip    = "The supplied password is the NT hash",
290 	},
291 	POPT_TABLEEND
292 };
293