1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * RPC server procedures for the usermode daemon kwarnd. 28 */ 29 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <pwd.h> 33 #include <grp.h> 34 #include <strings.h> 35 #include <string.h> 36 #include <sys/param.h> 37 #include <sys/syslog.h> 38 #include "kwarnd.h" 39 #include <rpc/rpc.h> 40 #include <stdlib.h> 41 #include <syslog.h> 42 #include <poll.h> 43 #include <utmpx.h> 44 #include <pwd.h> 45 #include <strings.h> 46 #include <ctype.h> 47 48 #include <k5-int.h> 49 #include <profile/prof_int.h> 50 #include <com_err.h> 51 #include <libintl.h> 52 #include <krb5.h> 53 54 extern char progname[]; 55 56 struct k5_data 57 { 58 krb5_context ctx; 59 krb5_ccache cc; 60 krb5_principal me; 61 char *name; 62 }; 63 64 65 #define MAIL "mail" 66 #define MAILPATH "/usr/bin/mail" 67 #define DEFAULT_CONFIG "* terminal 30m" 68 #define CONF_FILENAME "/etc/krb5/warn.conf" 69 70 /* warn.conf info */ 71 72 typedef struct config_entry_s { 73 struct config_entry_s *next; 74 int seconds_to_warn; 75 char *principal; 76 char *where_to; 77 char *email; 78 int renew; 79 int log_success; 80 int log_failure; 81 } config_entry_list_t; 82 static config_entry_list_t *config_entry_list; 83 84 /* list of principals to be warned */ 85 86 typedef struct cred_warning_list_s { 87 struct cred_warning_list_s *next; 88 WARNING_NAME_T warn_name; 89 time_t cred_exp_time; 90 time_t cred_warn_time; 91 mutex_t cwm; 92 } cred_warning_list_t; 93 static cred_warning_list_t *cred_warning_list; 94 static rwlock_t cred_lock = DEFAULTRWLOCK; 95 96 static bool_t 97 del_warning_pvt(char *); 98 99 static config_entry_list_t * 100 find_warning_info(char *); 101 102 static bool_t 103 parseConfigLine(char *buffer); 104 105 extern int warn_send(char *, char *); 106 107 extern int kwarnd_debug; 108 109 cred_warning_list_t * 110 find_cred_warning(WARNING_NAME_T warn_name) 111 { 112 cred_warning_list_t *cw; 113 if (!cred_warning_list) 114 return (NULL); 115 for (cw = cred_warning_list; cw != NULL; cw = cw->next) { 116 if (strcmp(warn_name, cw->warn_name) != 0) 117 continue; 118 return (cw); 119 } 120 return (NULL); 121 } 122 123 /* 124 * add a principal to the principal warning list 125 */ 126 127 bool_t 128 kwarn_add_warning_1_svc(kwarn_add_warning_arg *argp, 129 kwarn_add_warning_res *res, 130 struct svc_req *rqstp) 131 { 132 cred_warning_list_t *cred_warning; 133 config_entry_list_t *config_entry; 134 135 if (kwarnd_debug) { 136 printf("kwarn_add_warning_1_svc start; cWlist=%p\n", 137 cred_warning_list); 138 139 printf("kwarn_add_warning_1_svc: principal %s", 140 argp->warning_name); 141 printf(" exp time: %d\n", argp->cred_exp_time); 142 } 143 144 /* 145 * if there is no entry in the config file that matches the principal to 146 * be added to the warning list, return true because we are not going to 147 * send a warning for this principal. 148 */ 149 150 if ((config_entry = find_warning_info(argp->warning_name)) == NULL) { 151 if (kwarnd_debug) 152 printf( 153 "kwarn_add_warning_1_svc find_warn_info: fails, cWlist=%p\n", 154 cred_warning_list); 155 156 return (TRUE); 157 } 158 159 /* 160 * see if a warning has already been created for this principal, if so 161 * update the warning time. 162 */ 163 164 rw_wrlock(&cred_lock); 165 if (cred_warning = find_cred_warning(argp->warning_name)) { 166 rw_unlock(&cred_lock); 167 mutex_lock(&cred_warning->cwm); 168 cred_warning->cred_exp_time = argp->cred_exp_time; 169 cred_warning->cred_warn_time = argp->cred_exp_time 170 - config_entry->seconds_to_warn; 171 mutex_unlock(&cred_warning->cwm); 172 } else { 173 cred_warning = (cred_warning_list_t *)malloc( 174 sizeof (*cred_warning_list)); 175 if (cred_warning == NULL) { 176 rw_unlock(&cred_lock); 177 res->status = 1; 178 return (FALSE); 179 } 180 (void) memset((char *)cred_warning, 0, 181 sizeof (*cred_warning_list)); 182 cred_warning->cred_exp_time = argp->cred_exp_time; 183 cred_warning->cred_warn_time = argp->cred_exp_time 184 - config_entry->seconds_to_warn; 185 cred_warning->warn_name = strdup(argp->warning_name); 186 if (cred_warning->warn_name == NULL) { 187 free(cred_warning); 188 rw_unlock(&cred_lock); 189 res->status = 1; 190 return (FALSE); 191 } 192 mutex_init(&cred_warning->cwm, USYNC_THREAD, NULL); 193 cred_warning->next = cred_warning_list; 194 cred_warning_list = cred_warning; 195 rw_unlock(&cred_lock); 196 } 197 res->status = 0; 198 199 if (kwarnd_debug) 200 printf( 201 "kwarn_add_warning_1_svc end: returns true; cWlist=%p\n", 202 cred_warning_list); 203 204 return (TRUE); 205 } 206 207 /* 208 * delete a warning request for a given principal 209 */ 210 211 bool_t 212 kwarn_del_warning_1_svc(kwarn_del_warning_arg *argp, 213 kwarn_del_warning_res *res, 214 struct svc_req *rqstp) 215 { 216 if (kwarnd_debug) 217 printf(gettext("delete principal %s requested\n"), 218 argp->warning_name); 219 220 if (del_warning_pvt(argp->warning_name) == TRUE) { 221 res->status = 0; 222 223 if (kwarnd_debug) 224 printf(gettext("delete principal %s completed\n"), 225 argp->warning_name); 226 227 return (TRUE); 228 } else { 229 res->status = 1; 230 231 if (kwarnd_debug) 232 printf(gettext("delete principal %s failed\n"), 233 argp->warning_name); 234 235 return (TRUE); 236 } 237 } 238 239 static bool_t 240 del_warning_pvt(char *warning_name) 241 { 242 cred_warning_list_t *cred_warning, *prev; 243 rw_wrlock(&cred_lock); 244 for (prev = NULL, cred_warning = cred_warning_list; 245 cred_warning != NULL; prev = cred_warning, 246 cred_warning = cred_warning->next) { 247 if (strcmp(cred_warning->warn_name, warning_name) == 0) { 248 if (!prev) 249 cred_warning_list = cred_warning->next; 250 else 251 prev->next = cred_warning->next; 252 253 free(cred_warning->warn_name); 254 free(cred_warning); 255 rw_unlock(&cred_lock); 256 return (TRUE); 257 } 258 } 259 rw_unlock(&cred_lock); 260 return (FALSE); 261 } 262 263 /* 264 * load the warn.conf file into the config_entry list. 265 */ 266 267 bool_t 268 loadConfigFile(void) 269 { 270 char buffer[BUFSIZ]; 271 FILE *cfgfile; 272 bool_t retval = TRUE; 273 274 if ((cfgfile = fopen(CONF_FILENAME, "r")) == NULL) { 275 syslog(LOG_ERR, gettext( 276 "could not open config file \"%s\"\n"), 277 CONF_FILENAME); 278 syslog(LOG_ERR, gettext( 279 "using default options \"%s\"\n"), 280 DEFAULT_CONFIG); 281 retval = parseConfigLine(DEFAULT_CONFIG); 282 } else { 283 (void) memset(buffer, 0, sizeof (buffer)); 284 while ((fgets(buffer, BUFSIZ, cfgfile) != NULL) && 285 (retval == TRUE)) 286 retval = parseConfigLine(buffer); 287 fclose(cfgfile); 288 } 289 return (retval); 290 } 291 292 /* 293 * Return TRUE if we get a valid opt and update flags appro. 294 */ 295 static bool_t 296 cmp_renew_opts(char *opt, 297 int *log_success, /* out */ 298 int *log_failure) /* out */ 299 { 300 301 if (strncasecmp(opt, "log", 302 sizeof ("log")) == 0) { 303 *log_success = *log_failure = 1; 304 } else if (strncasecmp(opt, "log-success", 305 sizeof ("log-success")) == 0) { 306 *log_success = 1; 307 } else if (strncasecmp(opt, "log-failure", 308 sizeof ("log-failure")) == 0) { 309 *log_failure = 1; 310 } else { 311 if (kwarnd_debug) 312 printf("cmp_renew_opts: renew bad opt=`%s'\n", 313 opt ? opt : "null"); 314 return (FALSE); 315 } 316 317 return (TRUE); 318 } 319 320 /* 321 * Make the config_entry item for the config_entry_list, based on 322 * buffer. The formats are 323 * 324 * <principal> [renew[:<opt1,...optN>]] syslog|terminal <time> 325 * <principal> [renew[:<opt1,...optN>]] mail <time> <e-mail address> 326 * 327 * where renew opts will be: 328 * 329 * log-success 330 * - Log the result of the renew attempt on success using 331 * the specified method (syslog|terminal|mail) 332 * 333 * log-failure 334 * - Log the result of the renew attempt on failure using 335 * the specified method (syslog|terminal|mail) 336 * 337 * log 338 * - Same as specifing both log-failure and log-success 339 * 340 * Note if no log options are given, there will be no logging. 341 * 342 */ 343 344 static bool_t 345 parseConfigLine(char *buffer) 346 { 347 char *principal, *send_to, *emailid, *ends, *tm; 348 char *exptime; 349 int time_mode; 350 time_t etime; 351 config_entry_list_t *config_entry; 352 int renew = 0; 353 int log_success = 0; 354 int log_failure = 0; 355 356 /* ignore comments */ 357 if (*buffer == '#') 358 return (TRUE); 359 360 if (kwarnd_debug) 361 printf("parseconf: buffer=%s", buffer); 362 363 /* find end of principal */ 364 principal = buffer; 365 for (send_to = buffer; *send_to && !isspace(*send_to); 366 send_to++); 367 368 /* find first non whitespace after principal (start of send_to) */ 369 if (*send_to) { 370 *send_to = '\0'; 371 send_to++; 372 while (*send_to && isspace(*send_to)) 373 send_to++; 374 } 375 376 /* if no send_to, continue, bad entry */ 377 if (! *send_to) 378 return (TRUE); 379 380 /* find end of send_to */ 381 for (ends = send_to; *ends && !isspace(*ends); 382 ends++); 383 if (*ends) 384 *ends = '\0'; 385 386 387 if (strchr(send_to, ':')) { 388 /* we've got renew opts */ 389 char *st = NULL, *op = NULL; 390 391 op = strdup(send_to); 392 if (!op) 393 return (FALSE); 394 st = strchr(op, ':'); 395 *st = '\0'; 396 397 if (strncasecmp(op, "renew", sizeof ("renew")) == 0) { 398 renew = 1; 399 } else { 400 free(op); 401 /* got a ':' but not preceeded w/renew, badent, skip */ 402 if (kwarnd_debug) 403 printf("parseconf: colon badent, skip\n"); 404 return (TRUE); 405 } 406 free(op); 407 op = NULL; 408 409 st++; 410 if (!st || !*st || isspace(*st)) { 411 if (kwarnd_debug) 412 printf("parseconf: st badent, skip\n"); 413 /* bad ent, skip */ 414 return (TRUE); 415 } 416 if (renew && strchr(st, ',')) { 417 while (1) { 418 /* loop thru comma seperated list-o-opts */ 419 char *comma = NULL, *c = NULL, *l = NULL; 420 421 if (st && (comma = strchr(st, ','))) { 422 l = strdup(st); 423 if (!l) 424 return (FALSE); 425 c = strchr(l, ','); 426 *c = '\0'; 427 if (!cmp_renew_opts(l, &log_success, 428 &log_failure)) { 429 free(l); 430 /* badent, skip */ 431 return (TRUE); 432 } 433 free(l); 434 l = NULL; 435 436 st = comma; 437 st++; 438 } else { 439 if (st) { 440 if (!cmp_renew_opts(st, 441 &log_success, 442 &log_failure)) { 443 /* badent, skip */ 444 return (TRUE); 445 } 446 } 447 break; 448 } 449 } /* while */ 450 } else if (st) { 451 /* we just have one opt */ 452 if (!cmp_renew_opts(st, &log_success, &log_failure)) { 453 /* badent, skip */ 454 return (TRUE); 455 } 456 } 457 458 /* if send_to is "renew", note it and refind send_to */ 459 } else if (strncasecmp(send_to, "renew", 460 sizeof ("renew")) == 0) { 461 renew = 1; 462 463 } 464 465 if (kwarnd_debug) { 466 printf("parseconf: renew=%d, log failure=%d, log success=%d\n", 467 renew, log_failure, log_success); 468 } 469 470 if (renew) { 471 /* find first non whitespace after send_to (start of exptime) */ 472 for (send_to = ends+1; *send_to && isspace(*send_to); 473 send_to++); 474 475 /* if no send_to, continue, bad entry */ 476 if (! *send_to) { 477 if (kwarnd_debug) 478 printf("parseconf: no send_to, badent, skip\n"); 479 return (TRUE); 480 } 481 482 /* find end of send_to */ 483 for (ends = send_to; *ends && !isspace(*ends); 484 ends++); 485 if (*ends) 486 *ends = '\0'; 487 } 488 489 490 /* find first non whitespace after send_to (start of exptime) */ 491 for (exptime = ends+1; *exptime && isspace(*exptime); 492 exptime++); 493 494 /* if no exptime, continue, bad entry */ 495 if (! *exptime) { 496 if (kwarnd_debug) 497 printf("parseconf: no exptime, badent, skip\n"); 498 return (TRUE); 499 } 500 501 /* find end of exptime */ 502 for (ends = exptime; *ends && !isspace(*ends); ends++); 503 504 tm = ends - 1; 505 if (*tm == 's') 506 time_mode = 1; 507 else if (*tm == 'm') 508 time_mode = 2; 509 else if (*tm == 'h') 510 time_mode = 3; 511 else 512 time_mode = 1; 513 514 if (*tm) 515 *tm = '\0'; 516 517 if (kwarnd_debug) { 518 printf("parseconf: send_to = '%s', exptime='%s'\n", 519 send_to, exptime); 520 } 521 522 /* find first non whitespace after exptime (start of emailid) */ 523 for (emailid = ends+1; *emailid && isspace(*emailid); emailid++); 524 525 /* find end of emailid */ 526 if (*emailid) { 527 for (ends = emailid; *ends && !isspace(*ends); 528 ends++); 529 530 if (*ends) 531 *ends = '\0'; 532 } 533 534 /* if send to mail and no mail address, bad entry */ 535 if ((strcmp(send_to, "mail") == 0) && (!*emailid)) { 536 if (kwarnd_debug) 537 printf("parseconf: returns true; no mail addr\n"); 538 539 syslog(LOG_ERR, gettext("missing mail address" 540 " in config entry: \n%s %s %s " 541 " cannot mail warning"), principal, 542 send_to, exptime); 543 return (TRUE); 544 } 545 546 /* create an entry */ 547 config_entry = (config_entry_list_t *) 548 malloc(sizeof (*config_entry_list)); 549 if (config_entry == NULL) 550 return (FALSE); 551 (void) memset(config_entry, 0, sizeof (*config_entry_list)); 552 config_entry->principal = strdup(principal); 553 if (config_entry->principal == NULL) 554 return (FALSE); 555 config_entry->where_to = strdup(send_to); 556 if (config_entry->where_to == NULL) 557 return (FALSE); 558 etime = atol(exptime); 559 if (time_mode == 1) 560 config_entry->seconds_to_warn = etime; 561 else if (time_mode == 2) 562 config_entry->seconds_to_warn = etime * 60; 563 else if (time_mode == 3) 564 config_entry->seconds_to_warn = etime * 60 * 60; 565 566 if (*emailid) { 567 config_entry->email = strdup(emailid); 568 if (config_entry->email == NULL) 569 return (FALSE); 570 } 571 572 config_entry->renew = renew; 573 config_entry->log_success = log_success; 574 config_entry->log_failure = log_failure; 575 config_entry->next = config_entry_list; 576 config_entry_list = config_entry; 577 if (kwarnd_debug) 578 printf("parseconf: returns true; celist=%p\n", 579 config_entry_list); 580 581 return (TRUE); 582 } 583 584 /* 585 * find a specific warn.conf entry. 586 */ 587 588 static config_entry_list_t * 589 find_warning_info(char *principal) 590 { 591 config_entry_list_t *config_entry; 592 /* look for a specific entry */ 593 for (config_entry = config_entry_list; config_entry; 594 config_entry = config_entry->next) { 595 if (strcmp(config_entry->principal, principal) == 0) { 596 return (config_entry); 597 } 598 } 599 /* look for a wild card entry */ 600 for (config_entry = config_entry_list; config_entry; 601 config_entry = config_entry->next) { 602 if (strcmp(config_entry->principal, "*") == 0) { 603 return (config_entry); 604 } 605 } 606 /* nothing found */ 607 return (NULL); 608 609 } 610 611 /* 612 * create a pipe, fork and exec a command, 613 */ 614 static FILE * 615 safe_popen_w(char *path_to_cmd, char **argv) 616 { 617 618 int fd[2]; 619 FILE *fp; 620 char *envp[2]; 621 622 if (pipe(fd) == -1) 623 return (NULL); 624 625 626 switch (fork()) { 627 case -1: 628 (void) close(fd[0]); 629 (void) close(fd[1]); 630 return (NULL); 631 632 case 0: 633 close(fd[1]); 634 /* fd[0] is the end we read from */ 635 if (fd[0] != 0) { 636 close(0); 637 dup(fd[0]); 638 } 639 close(1); 640 close(2); 641 envp[0] = "PATH=/usr/bin"; 642 envp[1] = NULL; 643 #ifdef DEBUG 644 { 645 int fd; 646 fd = open("/tmp/kwarn.out", O_WRONLY|O_TRUNC|O_CREAT, 647 0666); 648 if (fd != 1) 649 dup(fd); 650 if (fd != 2) 651 dup(fd); 652 } 653 #endif 654 (void) execve(path_to_cmd, argv, envp); 655 syslog(LOG_ERR, "warnd: %m"); 656 _exit(1); 657 658 default: 659 close(fd[0]); 660 /* fd[1] is the end we write to */ 661 662 fp = fdopen(fd[1], "w"); 663 664 if (fp == NULL) { 665 (void) close(fd[1]); 666 return (NULL); 667 } 668 return (fp); 669 } 670 } 671 672 673 static uid_t krb5_cc_uid; 674 675 void 676 set_warnd_uid(uid_t uid) 677 { 678 /* 679 * set the value of krb5_cc_uid, so it can be retrieved when 680 * app_krb5_user_uid() is called by the underlying mechanism libraries. 681 */ 682 if (kwarnd_debug) 683 printf("set_warnd_uid called with uid = %d\n", uid); 684 krb5_cc_uid = uid; 685 } 686 687 uid_t 688 app_krb5_user_uid(void) 689 { 690 691 /* 692 * return the value set when one of the kwarnd procedures was 693 * entered. This is the value of the uid under which the 694 * underlying mechanism library must operate in order to 695 * get the user's credentials. This call is necessary since 696 * kwarnd runs as root and credentials are many times stored 697 * in files and directories specific to the user 698 */ 699 if (kwarnd_debug) 700 printf("app_krb5_user_uid called and returning uid = %d\n", 701 krb5_cc_uid); 702 return (krb5_cc_uid); 703 } 704 705 706 static bool_t 707 getpruid(char *pr, uid_t *uid) 708 { 709 char *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL; 710 struct passwd *pw; 711 712 rcp1 = strdup(pr); 713 if (!rcp1) 714 return (FALSE); 715 rcp2 = strtok(rcp1, "@"); 716 rcp3 = strtok(rcp2, "/"); 717 718 if (rcp3) { 719 pw = getpwnam(rcp3); 720 *uid = pw->pw_uid; 721 free(rcp1); 722 return (TRUE); 723 } 724 725 free(rcp1); 726 return (FALSE); 727 } 728 729 730 static krb5_error_code 731 renew_creds( 732 char *princ, 733 time_t *new_exp_time) /* out */ 734 { 735 krb5_creds my_creds; 736 krb5_error_code code = 0; 737 struct k5_data k5; 738 739 uid_t saved_u = app_krb5_user_uid(); 740 uid_t u; 741 742 if (kwarnd_debug) 743 printf("renew start: uid=%d\n", app_krb5_user_uid()); 744 745 if (!getpruid(princ, &u)) { 746 if (kwarnd_debug) 747 printf("renew: getpruid failed, princ='%s'\n", 748 princ ? princ : "<null>"); 749 750 return (-1); /* better err num? */ 751 } 752 753 set_warnd_uid(u); 754 755 (void) memset(&my_creds, 0, sizeof (my_creds)); 756 (void) memset(&k5, 0, sizeof (k5)); 757 758 if (code = krb5_init_context(&k5.ctx)) { 759 com_err(progname, code, 760 gettext("while initializing Kerberos 5 library")); 761 goto out; 762 } 763 764 if ((code = krb5_cc_default(k5.ctx, &k5.cc))) { 765 com_err(progname, code, 766 gettext("while getting default ccache")); 767 goto out; 768 769 } 770 771 if ((code = krb5_parse_name(k5.ctx, princ, 772 &k5.me))) { 773 com_err(progname, code, gettext("when parsing name %s"), 774 princ); 775 goto out; 776 } 777 778 if ((code = krb5_get_renewed_creds(k5.ctx, &my_creds, k5.me, k5.cc, 779 NULL))) { 780 com_err(progname, code, gettext("while renewing creds")); 781 goto out; 782 } 783 784 if (code = krb5_cc_initialize(k5.ctx, k5.cc, k5.me)) { 785 com_err(progname, code, gettext("when initializing cache %s"), 786 "defcc"); 787 goto out; 788 } 789 790 if (code = krb5_cc_store_cred(k5.ctx, k5.cc, &my_creds)) { 791 com_err(progname, code, gettext("while storing credentials")); 792 goto out; 793 } 794 795 /* "return" new expire time */ 796 *new_exp_time = my_creds.times.endtime; 797 798 out: 799 krb5_free_cred_contents(k5.ctx, &my_creds); 800 801 if (k5.name) 802 krb5_free_unparsed_name(k5.ctx, k5.name); 803 if (k5.me) 804 krb5_free_principal(k5.ctx, k5.me); 805 if (k5.cc) 806 krb5_cc_close(k5.ctx, k5.cc); 807 if (k5.ctx) 808 krb5_free_context(k5.ctx); 809 810 set_warnd_uid(saved_u); 811 812 if (kwarnd_debug) 813 printf("renew end: code=%s, uid=%d\n", error_message(code), 814 app_krb5_user_uid()); 815 816 return (code); 817 } 818 819 static bool_t 820 loggedon(char *name) 821 { 822 register struct utmpx *ubuf; 823 char *rcp1 = NULL, *rcp2 = NULL, *rcp3 = NULL; 824 825 /* 826 * strip any realm or instance from principal so we can match 827 * against unix userid. 828 */ 829 rcp1 = strdup(name); 830 if (!rcp1) 831 return (FALSE); 832 rcp2 = strtok(rcp1, "@"); 833 rcp3 = strtok(rcp2, "/"); 834 835 /* 836 * Scan through the "utmpx" file for the 837 * entry for the person we want to send to. 838 */ 839 840 setutxent(); 841 while ((ubuf = getutxent()) != NULL) { 842 if (ubuf->ut_type == USER_PROCESS) { 843 if (strncmp(rcp3, ubuf->ut_user, 844 sizeof (ubuf->ut_user)) == 0) { 845 free(rcp1); 846 endutxent(); 847 return (TRUE); 848 849 } 850 } 851 } 852 free(rcp1); 853 endutxent(); 854 855 if (kwarnd_debug) 856 printf("loggedon: returning false for user `%s'\n", rcp1); 857 858 return (FALSE); 859 } 860 861 /* 862 * main loop to check the cred warning list and send the warnings 863 * the appropriate location based on warn.conf or auto-renew creds. 864 */ 865 866 void 867 kwarnd_check_warning_list(void) 868 { /* func */ 869 cred_warning_list_t *cw; /* cred warning */ 870 config_entry_list_t *ce; /* config entry */ 871 time_t now; 872 int minutes; 873 char buff[256]; 874 char cmdline[256]; 875 FILE *fp; 876 char *subj = "Kerberos credentials expiring"; 877 char *renew_subj = "Kerberos credentials renewed"; 878 879 if (kwarnd_debug) 880 printf("check list: start: uid=%d, cw list=%p\n", 881 app_krb5_user_uid(), cred_warning_list); 882 883 while (1) { 884 (void) poll(NULL, 0, 60000); 885 886 for (cw = cred_warning_list; 887 cw != NULL; 888 cw = cw->next) { 889 int send_msg = 0; 890 891 time(&now); 892 if (now >= cw->cred_warn_time) { 893 int renew_attempted = 0; 894 int renew_failed = 0; 895 int renew_tooclose = 0; 896 897 if (kwarnd_debug) 898 printf("checklist: now >= warn_t\n"); 899 900 ce = find_warning_info(cw->warn_name); 901 minutes = (cw->cred_exp_time - 902 now + 59) / 60; 903 904 if (kwarnd_debug) 905 printf("checklist: where_to=%s\n", 906 ce->where_to ? 907 ce->where_to : "null"); 908 909 if (ce->renew && 910 loggedon(cw->warn_name)) { 911 krb5_error_code code; 912 time_t new_exp_time; 913 914 renew_attempted = 1; 915 code = renew_creds( 916 cw->warn_name, 917 &new_exp_time); 918 if (!code) { 919 /* krb5 api renew success */ 920 921 /* 922 * So we had api success 923 * but the new exp time 924 * is same as current one 925 * so we are too close 926 * to Renewable_life time. 927 */ 928 if (cw->cred_exp_time 929 == new_exp_time) { 930 renew_tooclose = 1; 931 if (kwarnd_debug) 932 printf( 933 "checklist: new expire time same as old expire time\n"); 934 935 if (ce->log_failure) { 936 send_msg = 1; 937 snprintf(buff, 938 sizeof (buff), 939 gettext("%s:\r\nYour kerberos" 940 " credentials have not been renewed" 941 " (too close to Renewable_life).\r\n" 942 "Please run kinit(1).\r\n"), 943 cw->warn_name); 944 } 945 } else { 946 /* update times */ 947 cw->cred_exp_time = 948 new_exp_time; 949 cw->cred_warn_time = 950 new_exp_time - 951 ce->seconds_to_warn; 952 } 953 954 if (kwarnd_debug) 955 printf( 956 "check list: new_w_t=%d\n", 957 cw->cred_warn_time); 958 959 if (!renew_tooclose && 960 ce->log_success) { 961 if (kwarnd_debug) 962 printf( 963 "check list: log success\n"); 964 965 send_msg = 1; 966 snprintf(buff, 967 sizeof (buff), 968 gettext("%s:\r\nYour kerberos" 969 " credentials have been renewed.\r\n"), 970 cw->warn_name); 971 } 972 973 } /* !(code) */ 974 975 if (!renew_tooclose && code && 976 ce->log_failure) { 977 if (kwarnd_debug) 978 printf( 979 "check list: log FAIL\n"); 980 981 send_msg = 1; 982 snprintf(buff, 983 sizeof (buff), 984 gettext("%s:\r\nYour kerberos" 985 " credentials failed to be renewed (%s).\r\n"), 986 cw->warn_name, 987 error_message(code)); 988 } 989 renew_failed = code ? 1 : 0; 990 991 } else if (minutes > 0) { 992 send_msg = 1; 993 snprintf(buff, sizeof (buff), 994 gettext("%s:\r\nyour kerberos" 995 " credentials expire in less than" 996 " %d minutes.\r\n"), 997 cw->warn_name, 998 minutes); 999 } else { 1000 send_msg = 1; 1001 snprintf(buff, sizeof (buff), 1002 gettext("%s:\r\nyour kerberos" 1003 " credentials have expired.\r\n"), 1004 cw->warn_name); 1005 } 1006 1007 if (kwarnd_debug) 1008 printf("checklist: send_msg=%d\n", 1009 send_msg); 1010 if (!send_msg) 1011 goto del_warning; 1012 1013 if (strncmp(ce->where_to, 1014 "mail", sizeof ("mail")) == 0) { 1015 char *argv[3]; 1016 1017 argv[0] = MAIL; 1018 (void) snprintf(cmdline, 1019 sizeof (cmdline), 1020 "%s", 1021 ce->email); 1022 argv[1] = cmdline; 1023 argv[2] = NULL; 1024 1025 fp = safe_popen_w(MAILPATH, argv); 1026 1027 if (fp) { 1028 1029 (void) fprintf(fp, 1030 "To: %s\nSubject: %s\n\n%s\n", 1031 ce->email, 1032 renew_attempted 1033 ? renew_subj : subj, 1034 buff); 1035 1036 fclose(fp); 1037 } else { 1038 syslog(LOG_ERR, 1039 gettext("could not fork " 1040 "mail program to e-mail " 1041 "warning to %s\n"), 1042 cmdline); 1043 } 1044 1045 } else if (strncmp(ce->where_to, 1046 "terminal", 1047 sizeof ("terminal")) == 0) { 1048 1049 warn_send(cw->warn_name, 1050 buff); 1051 1052 } else if (send_msg && strncmp(ce->where_to, 1053 "syslog", 1054 sizeof ("syslog")) == 0) { 1055 syslog(LOG_NOTICE|LOG_AUTH, 1056 "%s", 1057 buff); 1058 #if 0 1059 } else if (strncmp(ce->where_to, 1060 "snmp", 1061 sizeof ("snmp")) == 0) { 1062 #endif 1063 } else { 1064 if (kwarnd_debug) 1065 printf( 1066 "unknown msg method=`%s'\n", 1067 ce->where_to); 1068 1069 exit(1); 1070 } 1071 1072 del_warning: 1073 if (!renew_attempted || renew_failed || 1074 renew_tooclose) { 1075 if (del_warning_pvt(cw->warn_name) 1076 == TRUE) { 1077 1078 if (kwarnd_debug) 1079 printf( 1080 "check list: del warn succ\n"); 1081 1082 break; 1083 } else { 1084 if (kwarnd_debug) 1085 printf( 1086 "could not delete warning\n"); 1087 1088 syslog(LOG_ERR, gettext( 1089 "could not delete warning")); 1090 1091 exit(1); 1092 } 1093 } 1094 1095 } /* if (now) */ 1096 } /* for */ 1097 } /* while */ 1098 } /* func */ 1099