]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/openpam/bin/pamtest/pamtest.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / openpam / bin / pamtest / pamtest.c
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  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
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 685 2013-07-11 16:33:34Z des $
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <err.h>
37 #include <limits.h>
38 #include <pwd.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #include <security/pam_appl.h>
46 #include <security/openpam.h>   /* for openpam_ttyconv() */
47
48 /* OpenPAM internals */
49 extern const char *pam_item_name[PAM_NUM_ITEMS];
50 extern int openpam_debug;
51
52 static pam_handle_t *pamh;
53 static struct pam_conv pamc;
54
55 static int silent;
56 static int verbose;
57
58 static void pt_verbose(const char *, ...)
59         OPENPAM_FORMAT ((__printf__, 1, 2));
60 static void pt_error(int, const char *, ...)
61         OPENPAM_FORMAT ((__printf__, 2, 3));
62
63 /*
64  * Print an information message if -v was specified at least once
65  */
66 static void
67 pt_verbose(const char *fmt, ...)
68 {
69         va_list ap;
70
71         if (verbose) {
72                 va_start(ap, fmt);
73                 vfprintf(stderr, fmt, ap);
74                 va_end(ap);
75                 fprintf(stderr, "\n");
76         }
77 }
78
79 /*
80  * Print an error message
81  */
82 static void
83 pt_error(int e, const char *fmt, ...)
84 {
85         va_list ap;
86
87         if (e == PAM_SUCCESS && !verbose)
88                 return;
89         va_start(ap, fmt);
90         vfprintf(stderr, fmt, ap);
91         va_end(ap);
92         fprintf(stderr, ": %s\n", pam_strerror(NULL, e));
93 }
94
95 /*
96  * Wrapper for pam_start(3)
97  */
98 static int
99 pt_start(const char *service, const char *user)
100 {
101         int pame;
102
103         pamc.conv = &openpam_ttyconv;
104         pt_verbose("pam_start(%s, %s)", service, user);
105         if ((pame = pam_start(service, user, &pamc, &pamh)) != PAM_SUCCESS)
106                 pt_error(pame, "pam_start(%s)", service);
107         return (pame);
108 }
109
110 /*
111  * Wrapper for pam_authenticate(3)
112  */
113 static int
114 pt_authenticate(int flags)
115 {
116         int pame;
117
118         flags |= silent;
119         pt_verbose("pam_authenticate()");
120         if ((pame = pam_authenticate(pamh, flags)) != PAM_SUCCESS)
121                 pt_error(pame, "pam_authenticate()");
122         return (pame);
123 }
124
125 /*
126  * Wrapper for pam_acct_mgmt(3)
127  */
128 static int
129 pt_acct_mgmt(int flags)
130 {
131         int pame;
132
133         flags |= silent;
134         pt_verbose("pam_acct_mgmt()");
135         if ((pame = pam_acct_mgmt(pamh, flags)) != PAM_SUCCESS)
136                 pt_error(pame, "pam_acct_mgmt()");
137         return (pame);
138 }
139
140 /*
141  * Wrapper for pam_chauthtok(3)
142  */
143 static int
144 pt_chauthtok(int flags)
145 {
146         int pame;
147
148         flags |= silent;
149         pt_verbose("pam_chauthtok()");
150         if ((pame = pam_chauthtok(pamh, flags)) != PAM_SUCCESS)
151                 pt_error(pame, "pam_chauthtok()");
152         return (pame);
153 }
154
155 /*
156  * Wrapper for pam_setcred(3)
157  */
158 static int
159 pt_setcred(int flags)
160 {
161         int pame;
162
163         flags |= silent;
164         pt_verbose("pam_setcred()");
165         if ((pame = pam_setcred(pamh, flags)) != PAM_SUCCESS)
166                 pt_error(pame, "pam_setcred()");
167         return (pame);
168 }
169
170 /*
171  * Wrapper for pam_open_session(3)
172  */
173 static int
174 pt_open_session(int flags)
175 {
176         int pame;
177
178         flags |= silent;
179         pt_verbose("pam_open_session()");
180         if ((pame = pam_open_session(pamh, flags)) != PAM_SUCCESS)
181                 pt_error(pame, "pam_open_session()");
182         return (pame);
183 }
184
185 /*
186  * Wrapper for pam_close_session(3)
187  */
188 static int
189 pt_close_session(int flags)
190 {
191         int pame;
192
193         flags |= silent;
194         pt_verbose("pam_close_session()");
195         if ((pame = pam_close_session(pamh, flags)) != PAM_SUCCESS)
196                 pt_error(pame, "pam_close_session()");
197         return (pame);
198 }
199
200 /*
201  * Wrapper for pam_set_item(3)
202  */
203 static int
204 pt_set_item(int item, const char *p)
205 {
206         int pame;
207
208         switch (item) {
209         case PAM_SERVICE:
210         case PAM_USER:
211         case PAM_AUTHTOK:
212         case PAM_OLDAUTHTOK:
213         case PAM_TTY:
214         case PAM_RHOST:
215         case PAM_RUSER:
216         case PAM_USER_PROMPT:
217         case PAM_AUTHTOK_PROMPT:
218         case PAM_OLDAUTHTOK_PROMPT:
219         case PAM_HOST:
220                 pt_verbose("setting %s to %s", pam_item_name[item], p);
221                 break;
222         default:
223                 pt_verbose("setting %s", pam_item_name[item]);
224                 break;
225         }
226         if ((pame = pam_set_item(pamh, item, p)) != PAM_SUCCESS)
227                 pt_error(pame, "pam_set_item(%s)", pam_item_name[item]);
228         return (pame);
229 }
230
231 /*
232  * Wrapper for pam_end(3)
233  */
234 static int
235 pt_end(int pame)
236 {
237
238         if (pamh != NULL && (pame = pam_end(pamh, pame)) != PAM_SUCCESS)
239                 /* can't happen */
240                 pt_error(pame, "pam_end()");
241         return (pame);
242 }
243
244 /*
245  * Retrieve and list the PAM environment variables
246  */
247 static int
248 pt_listenv(void)
249 {
250         char **pam_envlist, **pam_env;
251
252         if ((pam_envlist = pam_getenvlist(pamh)) == NULL ||
253             *pam_envlist == NULL) {
254                 pt_verbose("no environment variables.");
255         } else {
256                 pt_verbose("environment variables:");
257                 for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
258                         printf(" %s\n", *pam_env);
259                         free(*pam_env);
260                 }
261         }
262         free(pam_envlist);
263         return (PAM_SUCCESS);
264 }
265
266 /*
267  * Print usage string and exit
268  */
269 static void
270 usage(void)
271 {
272
273         fprintf(stderr, "usage: pamtest %s service command ...\n",
274             "[-dkMPsv] [-H rhost] [-h host] [-t tty] [-U ruser] [-u user]");
275         exit(1);
276 }
277
278 /*
279  * Handle an option that takes an int argument and can be used only once
280  */
281 static void
282 opt_num_once(int opt, long *num, const char *arg)
283 {
284         char *end;
285         long l;
286
287         l = strtol(arg, &end, 0);
288         if (end == optarg || *end != '\0') {
289                 fprintf(stderr,
290                     "The -%c option expects a numeric argument\n", opt);
291                 usage();
292         }
293         *num = l;
294 }
295
296 /*
297  * Handle an option that takes a string argument and can be used only once
298  */
299 static void
300 opt_str_once(int opt, const char **p, const char *arg)
301 {
302
303         if (*p != NULL) {
304                 fprintf(stderr, "The -%c option can only be used once\n", opt);
305                 usage();
306         }
307         *p = arg;
308 }
309
310 /*
311  * Entry point
312  */
313 int
314 main(int argc, char *argv[])
315 {
316         char hostname[1024];
317         const char *rhost = NULL;
318         const char *host = NULL;
319         const char *ruser = NULL;
320         const char *user = NULL;
321         const char *service = NULL;
322         const char *tty = NULL;
323         long timeout = 0;
324         int keepatit = 0;
325         int pame;
326         int opt;
327
328         while ((opt = getopt(argc, argv, "dH:h:kMPsT:t:U:u:v")) != -1)
329                 switch (opt) {
330                 case 'd':
331                         openpam_debug++;
332                         break;
333                 case 'H':
334                         opt_str_once(opt, &rhost, optarg);
335                         break;
336                 case 'h':
337                         opt_str_once(opt, &host, optarg);
338                         break;
339                 case 'k':
340                         keepatit = 1;
341                         break;
342                 case 'M':
343                         openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
344                         openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
345                         break;
346                 case 'P':
347                         openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
348                         openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
349                         break;
350                 case 's':
351                         silent = PAM_SILENT;
352                         break;
353                 case 'T':
354                         opt_num_once(opt, &timeout, optarg);
355                         if (timeout < 0 || timeout > INT_MAX) {
356                                 fprintf(stderr,
357                                     "Invalid conversation timeout\n");
358                                 usage();
359                         }
360                         openpam_ttyconv_timeout = (int)timeout;
361                         break;
362                 case 't':
363                         opt_str_once(opt, &tty, optarg);
364                         break;
365                 case 'U':
366                         opt_str_once(opt, &ruser, optarg);
367                         break;
368                 case 'u':
369                         opt_str_once(opt, &user, optarg);
370                         break;
371                 case 'v':
372                         verbose++;
373                         break;
374                 default:
375                         usage();
376                 }
377
378         argc -= optind;
379         argv += optind;
380
381         if (argc < 1)
382                 usage();
383
384         service = *argv;
385         --argc;
386         ++argv;
387
388         /* defaults */
389         if (service == NULL)
390                 service = "pamtest";
391         if (rhost == NULL) {
392                 if (gethostname(hostname, sizeof(hostname)) == -1)
393                         err(1, "gethostname()");
394                 rhost = hostname;
395         }
396         if (tty == NULL)
397                 tty = ttyname(STDERR_FILENO);
398         if (user == NULL)
399                 user = getlogin();
400         if (ruser == NULL)
401                 ruser = user;
402
403         /* initialize PAM */
404         if ((pame = pt_start(service, user)) != PAM_SUCCESS)
405                 goto end;
406
407         /*
408          * pam_start(3) sets this to the machine's hostname, but we allow
409          * the user to override it.
410          */
411         if (host != NULL)
412                 if ((pame = pt_set_item(PAM_HOST, host)) != PAM_SUCCESS)
413                     goto end;
414
415         /*
416          * The remote host / user / tty are usually set by the
417          * application.
418          */
419         if ((pame = pt_set_item(PAM_RHOST, rhost)) != PAM_SUCCESS ||
420             (pame = pt_set_item(PAM_RUSER, ruser)) != PAM_SUCCESS ||
421             (pame = pt_set_item(PAM_TTY, tty)) != PAM_SUCCESS)
422                 goto end;
423
424         while (argc > 0) {
425                 if (strcmp(*argv, "listenv") == 0 ||
426                     strcmp(*argv, "env") == 0) {
427                         pame = pt_listenv();
428                 } else if (strcmp(*argv, "authenticate") == 0 ||
429                     strcmp(*argv, "auth") == 0) {
430                         pame = pt_authenticate(0);
431                 } else if (strcmp(*argv, "acct_mgmt") == 0 ||
432                     strcmp(*argv, "account") == 0) {
433                         pame = pt_acct_mgmt(0);
434                 } else if (strcmp(*argv, "chauthtok") == 0 ||
435                     strcmp(*argv, "change") == 0) {
436                         pame = pt_chauthtok(PAM_CHANGE_EXPIRED_AUTHTOK);
437                 } else if (strcmp(*argv, "forcechauthtok") == 0 ||
438                     strcmp(*argv, "forcechange") == 0) {
439                         pame = pt_chauthtok(0);
440                 } else if (strcmp(*argv, "setcred") == 0 ||
441                     strcmp(*argv, "establish_cred") == 0) {
442                         pame = pt_setcred(PAM_ESTABLISH_CRED);
443                 } else if (strcmp(*argv, "open_session") == 0 ||
444                     strcmp(*argv, "open") == 0) {
445                         pame = pt_open_session(0);
446                 } else if (strcmp(*argv, "close_session") == 0 ||
447                     strcmp(*argv, "close") == 0) {
448                         pame = pt_close_session(0);
449                 } else if (strcmp(*argv, "unsetcred") == 0 ||
450                     strcmp(*argv, "delete_cred") == 0) {
451                         pame = pt_setcred(PAM_DELETE_CRED);
452                 } else {
453                         warnx("unknown primitive: %s", *argv);
454                         pame = PAM_SYSTEM_ERR;
455                 }
456                 if (pame != PAM_SUCCESS && !keepatit) {
457                         warnx("test aborted");
458                         break;
459                 }
460                 --argc;
461                 ++argv;
462         }
463
464 end:
465         (void)pt_end(pame);
466         exit(pame == PAM_SUCCESS ? 0 : 1);
467 }