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