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