1/* 2 * $Id: pam_env.c,v 1.5 2002/03/27 02:36:24 bbraun Exp $ 3 * 4 * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31 5 * Inspired by Andrew Morgan <morgan@kernel.org>, who also supplied the 6 * template for this file (via pam_mail) 7 * 8 * Portions Copyright (C) 2002-2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms of Linux-PAM, with 11 * or without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * 1. Redistributions of source code must retain any existing copyright 15 * notice, and this entire permission notice in its entirety, 16 * including the disclaimer of warranties. 17 * 18 * 2. Redistributions in binary form must reproduce all prior and current 19 * copyright notices, this list of conditions, and the following 20 * disclaimer in the documentation and/or other materials provided 21 * with the distribution. 22 * 23 * 3. The name of any author may not be used to endorse or promote 24 * products derived from this software without their specific prior 25 * written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 33 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 35 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 36 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 37 * DAMAGE. 38 */ 39 40#ifndef DEFAULT_CONF_FILE 41#define DEFAULT_CONF_FILE "/etc/security/pam_env.conf" 42#endif 43 44#define DEFAULT_ETC_ENVFILE "/etc/environment" 45#define DEFAULT_READ_ENVFILE 1 46 47#include <ctype.h> 48#include <errno.h> 49#include <pwd.h> 50#include <stdarg.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <sys/stat.h> 55#include <sys/types.h> 56#include <unistd.h> 57 58/* 59 * here, we make a definition for the externally accessible function 60 * in this file (this definition is required for static a module 61 * but strongly encouraged generally) it is used to instruct the 62 * modules include file to define the function prototypes. 63 */ 64 65#define PAM_SM_AUTH /* This is primarily a AUTH_SETCRED module */ 66#define PAM_SM_SESSION /* But I like to be friendly */ 67#define PAM_SM_PASSWORD /* "" */ 68#define PAM_SM_ACCOUNT /* "" */ 69 70#include <security/pam_modules.h> 71#include <security/pam_appl.h> 72 73/* This little structure makes it easier to keep variables together */ 74 75typedef struct var { 76 char *name; 77 char *value; 78 char *defval; 79 char *override; 80} VAR; 81 82#define BUF_SIZE 1024 83#define MAX_ENV 8192 84 85#define GOOD_LINE 0 86#define BAD_LINE 100 /* This must be > the largest PAM_* error code */ 87 88#define DEFINE_VAR 101 89#define UNDEFINE_VAR 102 90#define ILLEGAL_VAR 103 91 92static int _assemble_line(pam_handle_t *, FILE *, char *, int); 93static int _parse_line(pam_handle_t *, char *, VAR *); 94static int _check_var(pam_handle_t *, VAR *); /* This is the real meat */ 95static void _clean_var(pam_handle_t *, VAR *); 96static int _expand_arg(pam_handle_t *, char **); 97static const char * _pam_get_item_byname(pam_handle_t *, const char *); 98static int _define_var(pam_handle_t *, VAR *); 99static int _undefine_var(pam_handle_t *, VAR *); 100 101/* This is a flag used to designate an empty string */ 102static char quote='Z'; 103 104/* argument parsing */ 105 106#define PAM_DEBUG_ARG 0x01 107#define PAM_NEW_CONF_FILE 0x02 108#define PAM_ENV_SILENT 0x04 109#define PAM_NEW_ENV_FILE 0x10 110 111static int _pam_parse(pam_handle_t *pamh, int flags, int argc, const char **argv, char **conffile, 112 char **envfile, int *readenv) 113{ 114 int ctrl=0; 115 const char *readenvchar = NULL; 116 117 /* generic options */ 118 119 if (NULL != openpam_get_option(pamh, "debug")) { 120 openpam_log(PAM_LOG_DEBUG, "debugging on"); 121 ctrl |= PAM_DEBUG_ARG; 122 } 123 if (NULL != (*conffile = (char *)openpam_get_option(pamh, "conffile"))) { 124 openpam_log(PAM_LOG_DEBUG, "new Configuration File: %s", *conffile); 125 ctrl |= PAM_NEW_CONF_FILE; 126 } 127 if (NULL != (*envfile = (char *)openpam_get_option(pamh, "conffile"))) { 128 openpam_log(PAM_LOG_DEBUG, "new Env File: %s", *envfile); 129 ctrl |= PAM_NEW_ENV_FILE; 130 } 131 readenvchar = (char *)openpam_get_option(pamh, "readenv"); 132 if (NULL != readenvchar && 0 != (*readenv = atoi(readenvchar))) { 133 openpam_log(PAM_LOG_DEBUG, "readenv: %d", *readenv); 134 } 135 136 return ctrl; 137} 138 139static int _parse_config_file(pam_handle_t *pamh, int ctrl, char **conffile) 140{ 141 int retval; 142 const char *file; 143 char buffer[BUF_SIZE]; 144 FILE *conf; 145 VAR Var, *var=&Var; 146 147 var->name=NULL; var->defval=NULL; var->override=NULL; 148 openpam_log(PAM_LOG_DEBUG, "Called."); 149 150 if (ctrl & PAM_NEW_CONF_FILE) { 151 file = *conffile; 152 } else { 153 file = DEFAULT_CONF_FILE; 154 } 155 156 openpam_log(PAM_LOG_DEBUG, "Config file name is: %s", file); 157 158 /* 159 * Lets try to open the config file, parse it and process 160 * any variables found. 161 */ 162 163 if ((conf = fopen(file,"r")) == NULL) { 164 openpam_log(PAM_LOG_ERROR, "Unable to open config file: %s", 165 strerror(errno)); 166 return PAM_IGNORE; 167 } 168 169 /* _pam_assemble_line will provide a complete line from the config file, with all 170 * comments removed and any escaped newlines fixed up 171 */ 172 173 while (( retval = _assemble_line(pamh, conf, buffer, BUF_SIZE)) > 0) { 174 openpam_log(PAM_LOG_DEBUG, "Read line: %s", buffer); 175 176 if ((retval = _parse_line(pamh, buffer, var)) == GOOD_LINE) { 177 retval = _check_var(pamh, var); 178 179 if (DEFINE_VAR == retval) { 180 retval = _define_var(pamh, var); 181 182 } else if (UNDEFINE_VAR == retval) { 183 retval = _undefine_var(pamh, var); 184 } 185 } 186 if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval 187 && BAD_LINE != retval) break; 188 189 _clean_var(pamh, var); 190 191 } /* while */ 192 193 (void) fclose(conf); 194 195 /* tidy up */ 196 _clean_var(pamh, var); /* We could have got here prematurely, this is safe though */ 197 if (NULL != conffile) { 198 memset(conffile, 0, sizeof(*conffile)); 199 *conffile = NULL; 200 } 201 file = NULL; 202 openpam_log(PAM_LOG_DEBUG, "Exit."); 203 return (retval<0?PAM_ABORT:PAM_SUCCESS); 204} 205 206static int _parse_env_file(pam_handle_t *pamh, int ctrl, char **env_file) 207{ 208 int retval=PAM_SUCCESS, i, t; 209 const char *file; 210 char buffer[BUF_SIZE], *key, *mark; 211 FILE *conf; 212 213 if (ctrl & PAM_NEW_ENV_FILE) 214 file = *env_file; 215 else 216 file = DEFAULT_ETC_ENVFILE; 217 218 openpam_log(PAM_LOG_DEBUG, "Env file name is: %s", file); 219 220 if ((conf = fopen(file,"r")) == NULL) { 221 openpam_log(PAM_LOG_DEBUG, "Unable to open env file: %s", strerror(errno)); 222 return PAM_ABORT; 223 } 224 225 while (_assemble_line(pamh, conf, buffer, BUF_SIZE) > 0) { 226 openpam_log(PAM_LOG_DEBUG, "Read line: %s", buffer); 227 key = buffer; 228 229 /* skip leading white space */ 230 key += strspn(key, " \n\t"); 231 232 /* skip blanks lines and comments */ 233 if (!key || key[0] == '#') 234 continue; 235 236 /* skip over "export " if present so we can be compat with 237 bash type declerations */ 238 if (strncmp(key, "export ", (size_t) 7) == 0) 239 key += 7; 240 241 /* now find the end of value */ 242 mark = key; 243 while(mark[0] != '\n' && mark[0] != '#' && mark[0] != '\0') 244 mark++; 245 if (mark[0] != '\0') 246 mark[0] = '\0'; 247 248 /* 249 * sanity check, the key must be alpha-numeric 250 */ 251 252 for ( i = 0 ; key[i] != '=' && key[i] != '\0' ; i++ ) 253 if (!isalnum(key[i]) && key[i] != '_') { 254 openpam_log(PAM_LOG_DEBUG, "key is not alpha numeric - '%s', ignoring", key); 255 continue; 256 } 257 258 /* now we try to be smart about quotes around the value, 259 but not too smart, we can't get all fancy with escaped 260 values like bash */ 261 if (key[i] == '=' && (key[++i] == '\"' || key[i] == '\'')) { 262 for ( t = i+1 ; key[t] != '\0' ; t++) 263 if (key[t] != '\"' && key[t] != '\'') 264 key[i++] = key[t]; 265 else if (key[t+1] != '\0') 266 key[i++] = key[t]; 267 key[i] = '\0'; 268 } 269 270 /* set the env var, if it fails, we break out of the loop */ 271 retval = pam_putenv(pamh, key); 272 if (retval != PAM_SUCCESS) { 273 openpam_log(PAM_LOG_DEBUG, "error setting env \"%s\"", key); 274 break; 275 } 276 } 277 278 (void) fclose(conf); 279 280 /* tidy up */ 281 if (NULL != env_file) { 282 memset(env_file, 0, sizeof(*env_file)); 283 *env_file = NULL; 284 } 285 file = NULL; 286 openpam_log(PAM_LOG_DEBUG, "Exit."); 287 return (retval<0?PAM_IGNORE:PAM_SUCCESS); 288} 289 290/* 291 * This is where we read a line of the PAM config file. The line may be 292 * preceeded by lines of comments and also extended with "\\\n" 293 */ 294 295static int _assemble_line(pam_handle_t *pamh, FILE *f, char *buffer, int buf_len) 296{ 297 char *p = buffer; 298 char *s, *os; 299 int used = 0; 300 301 /* loop broken with a 'break' when a non-'\\n' ended line is read */ 302 303 openpam_log(PAM_LOG_DEBUG, "called."); 304 for (;;) { 305 if (used >= buf_len) { 306 /* Overflow */ 307 openpam_log(PAM_LOG_DEBUG, "_assemble_line: overflow"); 308 return -1; 309 } 310 if (fgets(p, buf_len - used, f) == NULL) { 311 if (used) { 312 /* Incomplete read */ 313 return -1; 314 } else { 315 /* EOF */ 316 return 0; 317 } 318 } 319 320 /* skip leading spaces --- line may be blank */ 321 322 s = p + strspn(p, " \n\t"); 323 if (*s && (*s != '#')) { 324 os = s; 325 326 /* 327 * we are only interested in characters before the first '#' 328 * character 329 */ 330 331 while (*s && *s != '#') 332 ++s; 333 if (*s == '#') { 334 *s = '\0'; 335 used += strlen(os); 336 break; /* the line has been read */ 337 } 338 339 s = os; 340 341 /* 342 * Check for backslash by scanning back from the end of 343 * the entered line, the '\n' has been included since 344 * normally a line is terminated with this 345 * character. fgets() should only return one though! 346 */ 347 348 s += strlen(s); 349 while (s > os && ((*--s == ' ') || (*s == '\t') 350 || (*s == '\n'))); 351 352 /* check if it ends with a backslash */ 353 if (*s == '\\') { 354 *s = '\0'; /* truncate the line here */ 355 used += strlen(os); 356 p = s; /* there is more ... */ 357 } else { 358 /* End of the line! */ 359 used += strlen(os); 360 break; /* this is the complete line */ 361 } 362 363 } else { 364 /* Nothing in this line */ 365 /* Don't move p */ 366 } 367 } 368 369 return used; 370} 371 372static int _parse_line(pam_handle_t *pamh, char *buffer, VAR *var) 373{ 374 /* 375 * parse buffer into var, legal syntax is 376 * VARIABLE [DEFAULT=[[string]] [OVERRIDE=[value]] 377 * 378 * Any other options defined make this a bad line, 379 * error logged and no var set 380 */ 381 382 int length, quoteflg=0; 383 char *ptr, **valptr, *tmpptr; 384 385 openpam_log(PAM_LOG_DEBUG, "Called buffer = <%s>", buffer); 386 387 length = strcspn(buffer," \t\n"); 388 389 if ((var->name = malloc(length + 1)) == NULL) { 390 openpam_log(PAM_LOG_ERROR, "Couldn't malloc %d bytes", length+1); 391 return PAM_BUF_ERR; 392 } 393 394 /* 395 * The first thing on the line HAS to be the variable name, 396 * it may be the only thing though. 397 */ 398 strncpy(var->name, buffer, length); 399 var->name[length] = '\0'; 400 openpam_log(PAM_LOG_DEBUG, "var->name = <%s>, length = %d", var->name, length); 401 402 /* 403 * Now we check for arguments, we only support two kinds and ('cause I am lazy) 404 * each one can actually be listed any number of times 405 */ 406 407 ptr = buffer+length; 408 while ((length = strspn(ptr, " \t")) > 0) { 409 ptr += length; /* remove leading whitespace */ 410 openpam_log(PAM_LOG_DEBUG, "ptr: %s", ptr); 411 if (strncmp(ptr,"DEFAULT=",8) == 0) { 412 ptr+=8; 413 openpam_log(PAM_LOG_DEBUG, "Default arg found: <%s>", ptr); 414 valptr=&(var->defval); 415 } else if (strncmp(ptr, "OVERRIDE=", 9) == 0) { 416 ptr+=9; 417 openpam_log(PAM_LOG_DEBUG, "Override arg found: <%s>", ptr); 418 valptr=&(var->override); 419 } else { 420 openpam_log(PAM_LOG_DEBUG, "Unrecognized options: <%s> - ignoring line", ptr); 421 openpam_log(PAM_LOG_ERROR, "Unrecognized Option: %s - ignoring line", ptr); 422 return BAD_LINE; 423 } 424 425 if ('"' != *ptr) { /* Escaped quotes not supported */ 426 length = strcspn(ptr, " \t\n"); 427 tmpptr = ptr+length; 428 } else { 429 tmpptr = strchr(++ptr, '"'); 430 if (!tmpptr) { 431 openpam_log(PAM_LOG_DEBUG, "Unterminated quoted string: %s", ptr-1); 432 openpam_log(PAM_LOG_ERROR, "Unterminated quoted string: %s", ptr-1); 433 return BAD_LINE; 434 } 435 length = tmpptr - ptr; 436 if (*++tmpptr && ' ' != *tmpptr && '\t' != *tmpptr && '\n' != *tmpptr) { 437 openpam_log(PAM_LOG_DEBUG, "Quotes must cover the entire string: <%s>", ptr); 438 openpam_log(PAM_LOG_ERROR, "Quotes must cover the entire string: <%s>", ptr); 439 return BAD_LINE; 440 } 441 quoteflg++; 442 } 443 if (length) { 444 if ((*valptr = malloc(length + 1)) == NULL) { 445 openpam_log(PAM_LOG_DEBUG, "Couldn't malloc %d bytes", length+1); 446 openpam_log(PAM_LOG_ERROR, "Couldn't malloc %d bytes", length+1); 447 return PAM_BUF_ERR; 448 } 449 (void)strncpy(*valptr,ptr,length); 450 (*valptr)[length]='\0'; 451 } else if (quoteflg--) { 452 *valptr = "e; /* a quick hack to handle the empty string */ 453 } 454 ptr = tmpptr; /* Start the search where we stopped */ 455 } /* while */ 456 457 /* 458 * The line is parsed, all is well. 459 */ 460 461 openpam_log(PAM_LOG_DEBUG, "Exit."); 462 ptr = NULL; tmpptr = NULL; valptr = NULL; 463 return GOOD_LINE; 464} 465 466static int _check_var(pam_handle_t *pamh, VAR *var) 467{ 468 /* 469 * Examine the variable and determine what action to take. 470 * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take 471 * or a PAM_* error code if passed back from other routines 472 * 473 * if no DEFAULT provided, the empty string is assumed 474 * if no OVERRIDE provided, the empty string is assumed 475 * if DEFAULT= and OVERRIDE evaluates to the empty string, 476 * this variable should be undefined 477 * if DEFAULT="" and OVERRIDE evaluates to the empty string, 478 * this variable should be defined with no value 479 * if OVERRIDE=value and value turns into the empty string, DEFAULT is used 480 * 481 * If DEFINE_VAR is to be returned, the correct value to define will 482 * be pointed to by var->value 483 */ 484 485 int retval; 486 487 openpam_log(PAM_LOG_DEBUG, "Called."); 488 489 /* 490 * First thing to do is to expand any arguments, but only 491 * if they are not the special quote values (cause expand_arg 492 * changes memory). 493 */ 494 495 if (var->defval && ("e != var->defval) && 496 ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { 497 return retval; 498 } 499 if (var->override && ("e != var->override) && 500 ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { 501 return retval; 502 } 503 504 /* Now its easy */ 505 506 if (var->override && *(var->override) && "e != var->override) { 507 /* if there is a non-empty string in var->override, we use it */ 508 openpam_log(PAM_LOG_DEBUG, "OVERRIDE variable <%s> being used: <%s>", var->name, var->override); 509 var->value = var->override; 510 retval = DEFINE_VAR; 511 } else { 512 513 var->value = var->defval; 514 if ("e == var->defval) { 515 /* 516 * This means that the empty string was given for defval value 517 * which indicates that a variable should be defined with no value 518 */ 519 *var->defval = '\0'; 520 openpam_log(PAM_LOG_DEBUG, "An empty variable: <%s>", var->name); 521 retval = DEFINE_VAR; 522 } else if (var->defval) { 523 openpam_log(PAM_LOG_DEBUG, "DEFAULT variable <%s> being used: <%s>", var->name, var->defval); 524 retval = DEFINE_VAR; 525 } else { 526 openpam_log(PAM_LOG_DEBUG, "UNDEFINE variable <%s>", var->name); 527 retval = UNDEFINE_VAR; 528 } 529 } 530 531 openpam_log(PAM_LOG_DEBUG, "Exit."); 532 return retval; 533} 534 535static int _expand_arg(pam_handle_t *pamh, char **value) 536{ 537 const char *orig=*value, *tmpptr=NULL; 538 char *ptr; /* 539 * Sure would be nice to use tmpptr but it needs to be 540 * a constant so that the compiler will shut up when I 541 * call pam_getenv and _pam_get_item_byname -- sigh 542 */ 543 544 /* No unexpanded variable can be bigger than BUF_SIZE */ 545 char type, tmpval[BUF_SIZE]; 546 547 /* I know this shouldn't be hard-coded but it's so much easier this way */ 548 char tmp[MAX_ENV]; 549 550 openpam_log(PAM_LOG_DEBUG, "Remember to initialize tmp!"); 551 memset(tmp, 0, MAX_ENV); 552 553 /* 554 * (possibly non-existent) environment variables can be used as values 555 * by prepending a "$" and wrapping in {} (ie: ${HOST}), can escape with "\" 556 * (possibly non-existent) PAM items can be used as values 557 * by prepending a "@" and wrapping in {} (ie: @{PAM_RHOST}, can escape 558 * 559 */ 560 openpam_log(PAM_LOG_DEBUG, "Expanding <%s>",orig); 561 while (*orig) { /* while there is some input to deal with */ 562 if ('\\' == *orig) { 563 ++orig; 564 if ('$' != *orig && '@' != *orig) { 565 openpam_log(PAM_LOG_DEBUG, "Unrecognized escaped character: <%c> - ignoring", *orig); 566 openpam_log(PAM_LOG_ERROR, "Unrecognized escaped character: <%c> - ignoring", 567 *orig); 568 } else if ((strlen(tmp) + 1) < MAX_ENV) { 569 tmp[strlen(tmp)] = *orig++; /* Note the increment */ 570 } else { 571 /* is it really a good idea to try to log this? */ 572 openpam_log(PAM_LOG_DEBUG, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); 573 openpam_log(PAM_LOG_ERROR, "Variable buffer overflow: <%s> + <%s>", 574 tmp, tmpptr); 575 } 576 continue; 577 } 578 if ('$' == *orig || '@' == *orig) { 579 if ('{' != *(orig+1)) { 580 openpam_log(PAM_LOG_DEBUG, "Expandable variables must be wrapped in {}" 581 " <%s> - ignoring", orig); 582 openpam_log(PAM_LOG_ERROR, "Expandable variables must be wrapped in {}" 583 " <%s> - ignoring", orig); 584 if ((strlen(tmp) + 1) < MAX_ENV) { 585 tmp[strlen(tmp)] = *orig++; /* Note the increment */ 586 } 587 continue; 588 } else { 589 openpam_log(PAM_LOG_DEBUG, "Expandable argument: <%s>", orig); 590 type = *orig; 591 orig+=2; /* skip the ${ or @{ characters */ 592 ptr = strchr(orig, '}'); 593 if (ptr) { 594 *ptr++ = '\0'; 595 } else { 596 openpam_log(PAM_LOG_DEBUG, "Unterminated expandable variable: <%s>", orig-2); 597 openpam_log(PAM_LOG_ERROR, "Unterminated expandable variable: <%s>", orig-2); 598 return PAM_ABORT; 599 } 600 strncpy(tmpval, orig, sizeof(tmpval)); 601 tmpval[sizeof(tmpval)-1] = '\0'; 602 orig=ptr; 603 /* 604 * so, we know we need to expand tmpval, it is either 605 * an environment variable or a PAM_ITEM. type will tell us which 606 */ 607 switch (type) { 608 609 case '$': 610 openpam_log(PAM_LOG_DEBUG, "Expanding env var: <%s>",tmpval); 611 tmpptr = pam_getenv(pamh, tmpval); 612 openpam_log(PAM_LOG_DEBUG, "Expanded to <%s>", tmpptr); 613 break; 614 615 case '@': 616 openpam_log(PAM_LOG_DEBUG, "Expanding pam item: <%s>",tmpval); 617 tmpptr = _pam_get_item_byname(pamh, tmpval); 618 openpam_log(PAM_LOG_DEBUG, "Expanded to <%s>", tmpptr); 619 break; 620 621 default: 622 openpam_log(PAM_LOG_DEBUG, "Impossible error, type == <%c>", type); 623 openpam_log(PAM_LOG_ERROR, "Impossible error, type == <%c>", type); 624 return PAM_ABORT; 625 } /* switch */ 626 627 if (tmpptr) { 628 if (strlcat(tmp, tmpptr, MAX_ENV) >= MAX_ENV) { 629 /* is it really a good idea to try to log this? */ 630 openpam_log(PAM_LOG_DEBUG, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); 631 openpam_log(PAM_LOG_ERROR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); 632 } 633 } 634 } /* if ('{' != *orig++) */ 635 } else { /* if ( '$' == *orig || '@' == *orig) */ 636 if ((strlen(tmp) + 1) < MAX_ENV) { 637 tmp[strlen(tmp)] = *orig++; /* Note the increment */ 638 } else { 639 /* is it really a good idea to try to log this? */ 640 openpam_log(PAM_LOG_DEBUG, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); 641 openpam_log(PAM_LOG_ERROR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); 642 } 643 } 644 } /* for (;*orig;) */ 645 646 size_t tmp_len = strlen(tmp); 647 if (tmp_len > strlen(*value)) { 648 free(*value); 649 if ((*value = malloc(tmp_len+1)) == NULL) { 650 openpam_log(PAM_LOG_DEBUG, "Couldn't malloc %lu bytes for expanded var", tmp_len+1); 651 openpam_log(PAM_LOG_ERROR,"Couldn't malloc %lu bytes for expanded var", 652 tmp_len+1); 653 return PAM_BUF_ERR; 654 } 655 } 656 strlcpy(*value, tmp, tmp_len+1); 657 openpam_log(PAM_LOG_DEBUG, "Exit."); 658 659 return PAM_SUCCESS; 660} 661 662static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) 663{ 664 /* 665 * This function just allows me to use names as given in the config 666 * file and translate them into the appropriate PAM_ITEM macro 667 */ 668 669 int item; 670 const char *itemval; 671 672 openpam_log(PAM_LOG_DEBUG, "Called."); 673 if (strcmp(name, "PAM_USER") == 0) { 674 item = PAM_USER; 675 } else if (strcmp(name, "PAM_USER_PROMPT") == 0) { 676 item = PAM_USER_PROMPT; 677 } else if (strcmp(name, "PAM_TTY") == 0) { 678 item = PAM_TTY; 679 } else if (strcmp(name, "PAM_RUSER") == 0) { 680 item = PAM_RUSER; 681 } else if (strcmp(name, "PAM_RHOST") == 0) { 682 item = PAM_RHOST; 683 } else { 684 openpam_log(PAM_LOG_DEBUG, "Unknown PAM_ITEM: <%s>", name); 685 openpam_log(PAM_LOG_ERROR, "Unknown PAM_ITEM: <%s>", name); 686 return NULL; 687 } 688 689 if (pam_get_item(pamh, item, (const void **)&itemval) != PAM_SUCCESS) { 690 openpam_log(PAM_LOG_DEBUG, "pam_get_item failed"); 691 return NULL; /* let pam_get_item() log the error */ 692 } 693 openpam_log(PAM_LOG_DEBUG, "Exit."); 694 return itemval; 695} 696 697static int _define_var(pam_handle_t *pamh, VAR *var) 698{ 699 /* We have a variable to define, this is a simple function */ 700 701 char *envvar; 702 int size, retval=PAM_SUCCESS; 703 704 openpam_log(PAM_LOG_DEBUG, "Called."); 705 size = strlen(var->name)+strlen(var->value)+2; 706 if ((envvar = malloc(size)) == NULL) { 707 openpam_log(PAM_LOG_DEBUG, "Malloc fail, size = %d", size); 708 openpam_log(PAM_LOG_ERROR, "Malloc fail, size = %d", size); 709 return PAM_BUF_ERR; 710 } 711 (void) snprintf(envvar,size,"%s=%s",var->name,var->value); 712 retval = pam_putenv(pamh, envvar); 713 free(envvar); envvar=NULL; 714 openpam_log(PAM_LOG_DEBUG, "Exit."); 715 return retval; 716} 717 718static int _undefine_var(pam_handle_t *pamh, VAR *var) 719{ 720 /* We have a variable to undefine, this is a simple function */ 721 722 openpam_log(PAM_LOG_DEBUG, "Called and exit."); 723 return pam_putenv(pamh, var->name); 724} 725 726static void _clean_var(pam_handle_t *pamh, VAR *var) 727{ 728 if (var->name) { 729 free(var->name); 730 } 731 if (var->defval && ("e != var->defval)) { 732 free(var->defval); 733 } 734 if (var->override && ("e != var->override)) { 735 free(var->override); 736 } 737 var->name = NULL; 738 var->value = NULL; /* never has memory specific to it */ 739 var->defval = NULL; 740 var->override = NULL; 741 return; 742} 743 744 745 746/* --- authentication management functions (only) --- */ 747 748PAM_EXTERN 749int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, 750 const char **argv) 751{ 752 return PAM_IGNORE; 753} 754 755PAM_EXTERN 756int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, 757 const char **argv) 758{ 759 int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; 760 char *conf_file=NULL, *env_file=NULL; 761 762 /* 763 * this module sets environment variables read in from a file 764 */ 765 766 openpam_log(PAM_LOG_DEBUG, "Called."); 767 ctrl = _pam_parse(pamh, flags, argc, argv, &conf_file, &env_file, &readenv); 768 769 retval = _parse_config_file(pamh, ctrl, &conf_file); 770 771 if(readenv) 772 _parse_env_file(pamh, ctrl, &env_file); 773 774 /* indicate success or failure */ 775 776 openpam_log(PAM_LOG_DEBUG, "Exit."); 777 return retval; 778} 779 780PAM_EXTERN 781int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, 782 const char **argv) 783{ 784 openpam_log(PAM_LOG_NOTICE, "pam_sm_acct_mgmt called inappropriatly"); 785 return PAM_SERVICE_ERR; 786} 787 788PAM_EXTERN 789int pam_sm_open_session(pam_handle_t *pamh,int flags,int argc 790 ,const char **argv) 791{ 792 int retval, ctrl, readenv=DEFAULT_READ_ENVFILE; 793 char *conf_file=NULL, *env_file=NULL; 794 795 /* 796 * this module sets environment variables read in from a file 797 */ 798 799 openpam_log(PAM_LOG_DEBUG, "Called."); 800 ctrl = _pam_parse(pamh, flags, argc, argv, &conf_file, &env_file, &readenv); 801 802 retval = _parse_config_file(pamh, ctrl, &conf_file); 803 804 if(readenv) 805 _parse_env_file(pamh, ctrl, &env_file); 806 807 /* indicate success or failure */ 808 809 openpam_log(PAM_LOG_DEBUG, "Exit."); 810 return retval; 811} 812 813PAM_EXTERN 814int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc, 815 const char **argv) 816{ 817 openpam_log(PAM_LOG_DEBUG, "Called and Exit"); 818 return PAM_SUCCESS; 819} 820 821PAM_EXTERN 822int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, 823 const char **argv) 824{ 825 openpam_log(PAM_LOG_NOTICE, "pam_sm_chauthtok called inappropriatly"); 826 return PAM_SERVICE_ERR; 827} 828 829#ifdef PAM_STATIC 830 831/* static module data */ 832 833struct pam_module _pam_env_modstruct = { 834 "pam_env", 835 pam_sm_authenticate, 836 pam_sm_setcred, 837 pam_sm_acct_mgmt, 838 pam_sm_open_session, 839 pam_sm_close_session, 840 pam_sm_chauthtok, 841}; 842 843#endif 844 845/* end of module definition */ 846