xref: /freebsd/contrib/openpam/bin/pamtest/pamtest.c (revision 3e65b9c6e6b7b2081d54e1dc40983c3c00eaf738)
1 /*-
2  * Copyright (c) 2011 Dag-Erling Smørgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $Id: pamtest.c 472 2011-11-03 09:46:52Z des $
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 
34 #include <err.h>
35 #include <pwd.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include <security/pam_appl.h>
43 #include <security/openpam.h>	/* for openpam_ttyconv() */
44 
45 /* OpenPAM internals */
46 extern const char *pam_item_name[PAM_NUM_ITEMS];
47 extern int openpam_debug;
48 
49 static pam_handle_t *pamh;
50 static struct pam_conv pamc;
51 
52 static int silent;
53 static int verbose;
54 
55 static void pt_verbose(const char *, ...)
56 	OPENPAM_FORMAT ((__printf__, 1, 2));
57 static void pt_error(int, const char *, ...)
58 	OPENPAM_FORMAT ((__printf__, 2, 3));
59 
60 /*
61  * Print an information message if -v was specified at least once
62  */
63 static void
64 pt_verbose(const char *fmt, ...)
65 {
66 	va_list ap;
67 
68 	if (verbose) {
69 		va_start(ap, fmt);
70 		vfprintf(stderr, fmt, ap);
71 		va_end(ap);
72 		fprintf(stderr, "\n");
73 	}
74 }
75 
76 /*
77  * Print an error message
78  */
79 static void
80 pt_error(int e, const char *fmt, ...)
81 {
82 	va_list ap;
83 
84 	if (e == PAM_SUCCESS && !verbose)
85 		return;
86 	va_start(ap, fmt);
87 	vfprintf(stderr, fmt, ap);
88 	va_end(ap);
89 	fprintf(stderr, ": %s\n", pam_strerror(NULL, e));
90 }
91 
92 /*
93  * Wrapper for pam_start(3)
94  */
95 static int
96 pt_start(const char *service, const char *user)
97 {
98 	int pame;
99 
100 	pamc.conv = &openpam_ttyconv;
101 	pt_verbose("pam_start(%s, %s)", service, user);
102 	if ((pame = pam_start(service, user, &pamc, &pamh)) != PAM_SUCCESS)
103 		pt_error(pame, "pam_start(%s)", service);
104 	return (pame);
105 }
106 
107 /*
108  * Wrapper for pam_authenticate(3)
109  */
110 static int
111 pt_authenticate(int flags)
112 {
113 	int pame;
114 
115 	flags |= silent;
116 	if ((pame = pam_authenticate(pamh, flags)) != PAM_SUCCESS)
117 		pt_error(pame, "pam_authenticate()");
118 	return (pame);
119 }
120 
121 /*
122  * Wrapper for pam_acct_mgmt(3)
123  */
124 static int
125 pt_acct_mgmt(int flags)
126 {
127 	int pame;
128 
129 	flags |= silent;
130 	if ((pame = pam_acct_mgmt(pamh, flags)) != PAM_SUCCESS)
131 		pt_error(pame, "pam_acct_mgmt()");
132 	return (pame);
133 }
134 
135 /*
136  * Wrapper for pam_chauthtok(3)
137  */
138 static int
139 pt_chauthtok(int flags)
140 {
141 	int pame;
142 
143 	flags |= silent;
144 	if ((pame = pam_chauthtok(pamh, flags)) != PAM_SUCCESS)
145 		pt_error(pame, "pam_chauthtok()");
146 	return (pame);
147 }
148 
149 /*
150  * Wrapper for pam_setcred(3)
151  */
152 static int
153 pt_setcred(int flags)
154 {
155 	int pame;
156 
157 	flags |= silent;
158 	if ((pame = pam_setcred(pamh, flags)) != PAM_SUCCESS)
159 		pt_error(pame, "pam_setcred()");
160 	return (pame);
161 }
162 
163 /*
164  * Wrapper for pam_open_session(3)
165  */
166 static int
167 pt_open_session(int flags)
168 {
169 	int pame;
170 
171 	flags |= silent;
172 	if ((pame = pam_open_session(pamh, flags)) != PAM_SUCCESS)
173 		pt_error(pame, "pam_open_session()");
174 	return (pame);
175 }
176 
177 /*
178  * Wrapper for pam_close_session(3)
179  */
180 static int
181 pt_close_session(int flags)
182 {
183 	int pame;
184 
185 	flags |= silent;
186 	if ((pame = pam_close_session(pamh, flags)) != PAM_SUCCESS)
187 		pt_error(pame, "pam_close_session()");
188 	return (pame);
189 }
190 
191 /*
192  * Wrapper for pam_set_item(3)
193  */
194 static int
195 pt_set_item(int item, const char *p)
196 {
197 	int pame;
198 
199 	switch (item) {
200 	case PAM_SERVICE:
201 	case PAM_USER:
202 	case PAM_AUTHTOK:
203 	case PAM_OLDAUTHTOK:
204 	case PAM_TTY:
205 	case PAM_RHOST:
206 	case PAM_RUSER:
207 	case PAM_USER_PROMPT:
208 	case PAM_AUTHTOK_PROMPT:
209 	case PAM_OLDAUTHTOK_PROMPT:
210 	case PAM_HOST:
211 		pt_verbose("setting %s to %s", pam_item_name[item], p);
212 		break;
213 	default:
214 		pt_verbose("setting %s", pam_item_name[item]);
215 		break;
216 	}
217 	if ((pame = pam_set_item(pamh, item, p)) != PAM_SUCCESS)
218 		pt_error(pame, "pam_set_item(%s)", pam_item_name[item]);
219 	return (pame);
220 }
221 
222 /*
223  * Wrapper for pam_end(3)
224  */
225 static int
226 pt_end(int pame)
227 {
228 
229 	if (pamh != NULL && (pame = pam_end(pamh, pame)) != PAM_SUCCESS)
230 		/* can't happen */
231 		pt_error(pame, "pam_end()");
232 	return (pame);
233 }
234 
235 /*
236  * Retrieve and list the PAM environment variables
237  */
238 static int
239 pt_listenv(void)
240 {
241 	char **pam_envlist, **pam_env;
242 
243 	if ((pam_envlist = pam_getenvlist(pamh)) == NULL ||
244 	    *pam_envlist == NULL) {
245 		pt_verbose("no environment variables.");
246 	} else {
247 		pt_verbose("environment variables:");
248 		for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
249 			printf(" %s\n", *pam_env);
250 			free(*pam_env);
251 		}
252 	}
253 	free(pam_envlist);
254 	return (PAM_SUCCESS);
255 }
256 
257 /*
258  * Print usage string and exit
259  */
260 static void
261 usage(void)
262 {
263 
264 	fprintf(stderr, "usage: pamtest [-dksv] %s\n",
265 	    "[-H rhost] [-h host] [-t tty] [-U ruser] [-u user] service");
266 	exit(1);
267 }
268 
269 /*
270  * Handle an option that takes a string argument and can be used only once
271  */
272 static void
273 opt_str_once(int opt, const char **p, const char *arg)
274 {
275 
276 	if (*p != NULL) {
277 		fprintf(stderr, "The -%c option can only be used once\n", opt);
278 		usage();
279 	}
280 	*p = arg;
281 }
282 
283 /*
284  * Entry point
285  */
286 int
287 main(int argc, char *argv[])
288 {
289 	char hostname[1024];
290 	const char *rhost = NULL;
291 	const char *host = NULL;
292 	const char *ruser = NULL;
293 	const char *user = NULL;
294 	const char *service = NULL;
295 	const char *tty = NULL;
296 	int keepatit = 0;
297 	int pame;
298 	int opt;
299 
300 	while ((opt = getopt(argc, argv, "dH:h:kst:U:u:v")) != -1)
301 		switch (opt) {
302 		case 'd':
303 			openpam_debug++;
304 			break;
305 		case 'H':
306 			opt_str_once(opt, &rhost, optarg);
307 			break;
308 		case 'h':
309 			opt_str_once(opt, &host, optarg);
310 			break;
311 		case 'k':
312 			keepatit = 1;
313 			break;
314 		case 's':
315 			silent = PAM_SILENT;
316 			break;
317 		case 't':
318 			opt_str_once(opt, &tty, optarg);
319 			break;
320 		case 'U':
321 			opt_str_once(opt, &ruser, optarg);
322 			break;
323 		case 'u':
324 			opt_str_once(opt, &user, optarg);
325 			break;
326 		case 'v':
327 			verbose++;
328 			break;
329 		default:
330 			usage();
331 		}
332 
333 	argc -= optind;
334 	argv += optind;
335 
336 	if (argc < 1)
337 		usage();
338 
339 	service = *argv;
340 	--argc;
341 	++argv;
342 
343 	/* defaults */
344 	if (rhost == NULL) {
345 		if (gethostname(hostname, sizeof(hostname)) == -1)
346 			err(1, "gethostname()");
347 		rhost = hostname;
348 	}
349 	if (tty == NULL)
350 		tty = ttyname(STDERR_FILENO);
351 	if (user == NULL)
352 		user = getlogin();
353 	if (ruser == NULL)
354 		ruser = user;
355 
356 	/* initialize PAM */
357 	if ((pame = pt_start(service, user)) != PAM_SUCCESS)
358 		goto end;
359 
360 	/*
361 	 * pam_start(3) sets this to the machine's hostname, but we allow
362 	 * the user to override it.
363 	 */
364 	if (host != NULL)
365 		if ((pame = pt_set_item(PAM_HOST, host)) != PAM_SUCCESS)
366 		    goto end;
367 
368 	/*
369 	 * The remote host / user / tty are usually set by the
370 	 * application.
371 	 */
372 	if ((pame = pt_set_item(PAM_RHOST, rhost)) != PAM_SUCCESS ||
373 	    (pame = pt_set_item(PAM_RUSER, ruser)) != PAM_SUCCESS ||
374 	    (pame = pt_set_item(PAM_TTY, tty)) != PAM_SUCCESS)
375 		goto end;
376 
377 	while (argc > 0) {
378 		if (strcmp(*argv, "listenv") == 0 ||
379 		    strcmp(*argv, "env") == 0) {
380 			pame = pt_listenv();
381 		} else if (strcmp(*argv, "authenticate") == 0 ||
382 		    strcmp(*argv, "auth") == 0) {
383 			pame = pt_authenticate(0);
384 		} else if (strcmp(*argv, "acct_mgmt") == 0 ||
385 		    strcmp(*argv, "account") == 0) {
386 			pame = pt_acct_mgmt(0);
387 		} else if (strcmp(*argv, "chauthtok") == 0 ||
388 		    strcmp(*argv, "change") == 0) {
389 			pame = pt_chauthtok(PAM_CHANGE_EXPIRED_AUTHTOK);
390 		} else if (strcmp(*argv, "forcechauthtok") == 0 ||
391 		    strcmp(*argv, "forcechange") == 0) {
392 			pame = pt_chauthtok(0);
393 		} else if (strcmp(*argv, "setcred") == 0 ||
394 		    strcmp(*argv, "establish_cred") == 0) {
395 			pame = pt_setcred(PAM_ESTABLISH_CRED);
396 		} else if (strcmp(*argv, "open_session") == 0 ||
397 		    strcmp(*argv, "open") == 0) {
398 			pame = pt_open_session(0);
399 		} else if (strcmp(*argv, "close_session") == 0 ||
400 		    strcmp(*argv, "close") == 0) {
401 			pame = pt_close_session(0);
402 		} else if (strcmp(*argv, "unsetcred") == 0 ||
403 		    strcmp(*argv, "delete_cred") == 0) {
404 			pame = pt_setcred(PAM_DELETE_CRED);
405 		} else {
406 			warnx("unknown primitive: %s", *argv);
407 			pame = PAM_SYSTEM_ERR;
408 		}
409 		if (pame != PAM_SUCCESS && !keepatit) {
410 			warnx("test aborted");
411 			break;
412 		}
413 		--argc;
414 		++argv;
415 	}
416 
417 end:
418 	(void)pt_end(pame);
419 	exit(pame == PAM_SUCCESS ? 0 : 1);
420 }
421