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