Sdiff kpropd.c


8 * a specific license from the United States Government. It is the 9 * responsibility of any person or organization contemplating export to 10 * obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of FundsXpress. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. FundsXpress makes no representations about the suitability of 20 * this software for any purpose. It is provided "as is" without express 21 * or implied warranty. 22 * 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "@(#)kpropd.c 1.7 04/09/08 SMI" 29 30 /* 31 * slave/kpropd.c 32 * 33 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 34 * All Rights Reserved. 35 * 36 * Export of this software from the United States of America may 37 * require a specific license from the United States Government. 38 * It is the responsibility of any person or organization contemplating 39 * export to obtain such a license before exporting. 40 * 41 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 42 * distribute this software and its documentation for any purpose and 43 * without fee is hereby granted, provided that the above copyright 44 * notice appear in all copies and that both that copyright notice and 45 * this permission notice appear in supporting documentation, and that 46 * the name of M.I.T. not be used in advertising or publicity pertaining 47 * to distribution of the software without specific, written prior 48 * permission. Furthermore if you modify this software you must label
71 #endif 72 #include <fcntl.h> 73 #include <sys/types.h> 74 #include <sys/time.h> 75 #include <sys/stat.h> 76 #include <sys/socket.h> 77 #include <sys/wait.h> 78 #include <netinet/in.h> 79 #include <arpa/inet.h> 80 #include <sys/param.h> 81 #include <netdb.h> 82 #include <syslog.h> 83 #include <libintl.h> 84 #include <locale.h> 85 #include <k5-int.h> 86 #include <socket-utils.h> 87 #include "com_err.h" 88 #include <errno.h> 89 90 #include "kprop.h" 91 92 #define SYSLOG_CLASS LOG_DAEMON 93 94 static char *kprop_version = KPROP_PROT_VERSION; 95 96 char *progname; 97 int debug = 0; 98 char *srvtab = 0; 99 int standalone = 0; 100 101 krb5_principal server; /* This is our server principal name */ 102 krb5_principal client; /* This is who we're talking to */ 103 krb5_context kpropd_context; 104 krb5_auth_context auth_context; 105 char *realm = NULL; /* Our realm */ 106 char *file = KPROPD_DEFAULT_FILE; 107 char *temp_file_name; 108 char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL; 109 char *kerb_database = NULL; 110 char *acl_file_name = KPROPD_ACL_FILE; 111 112 int database_fd; 113 krb5_address sender_addr; 114 krb5_address receiver_addr; 115 short port = 0; 116 117 void PRS 118 (int, char**); 119 int do_standalone 120 (void); 121 void doit 122 (int); 123 void kerberos_authenticate 124 (krb5_context, 125 int, 126 krb5_principal *, 127 krb5_enctype *, 128 struct sockaddr_storage); 129 130 krb5_boolean authorized_principal 131 (krb5_context, 132 krb5_principal, 133 krb5_enctype); 134 void recv_database 135 (krb5_context, 136 int, 137 int, 138 krb5_data *); 139 void load_database 140 (krb5_context, 141 char *, 142 char *); 143 void send_error 144 (krb5_context, 145 int, 146 krb5_error_code, 147 char *); 148 void recv_error 149 (krb5_context, 150 krb5_data *); 151 152 static void usage() 153 { 154 fprintf(stderr, 155 gettext("\nUsage: %s\n"), /* progname may be a long pathname */ 156 progname); 157 158 fprintf(stderr, 159 gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n")); 160 161 fprintf(stderr, 162 gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n")); 163 164 fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n")); 165 166 exit(1); 167 } 168 169 int 170 main(argc, argv) 171 int argc; 172 char **argv; 173 { 174 PRS(argc, argv); 175 176 if (standalone) 177 do_standalone(); 178 else 179 doit(0); 180 exit(0); 181 } 182 183 int do_standalone() 184 { 185 struct linger linger; 186 struct servent *sp; 187 int finet, fromlen, s; 188 int on = 1; 189 int ret, status = 0; 190 struct sockaddr_in6 sin6 = { AF_INET6 }; 191 int sin6_size = sizeof (sin6); 192 /* listen for either ipv4 or ipv6 */ 193 finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 194 if (finet < 0 ) { 195 com_err(progname, errno, gettext("while obtaining socket")); 196 exit(1); 197 } 198 199 if(!port) { 200 sp = getservbyname(KPROP_SERVICE, "tcp"); 201 if (sp == NULL) { 202 com_err(progname, 0, gettext("%s/tcp: unknown service"), 203 KPROP_SERVICE); 204 exit(1); 205 sin6.sin6_port = sp->s_port; 206 } else 207 sin6.sin6_port = port; 208 if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) { 209 if (debug) { 210 on = 1; 211 fprintf(stderr, 212 gettext("%s: attempting to rebind socket " 213 "with SO_REUSEADDR\n"), progname); 214 if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, 215 (char *)&on, sizeof(on)) < 0) { 216 com_err(progname, errno, 217 gettext("in setsockopt(SO_REUSEADDR)")); 218 } 219 ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6)); 220 } 221 222 if (ret < 0) { 223 perror(gettext("bind")); 224 com_err(progname, errno, 225 gettext("while binding listener socket")); 226 exit(1); 227 } 228 } 229 230 if (!debug) 231 daemon(1, 0); 232 233 #ifdef PID_FILE 234 if ((pidfile = fopen(PID_FILE, "w")) != NULL) { 235 fprintf(pidfile, gettext("%d\n"), getpid()); 236 fclose(pidfile); 237 } else 238 com_err(progname, errno, 239 gettext("while opening pid file %s for writing"), 240 PID_FILE); 241 #endif 242 243 if (listen(finet, 5) < 0) { 244 com_err(progname, errno, gettext("in listen call")); 245 exit(1); 246 } 247 while (1) { 248 int child_pid; 249 s = accept(finet, (struct sockaddr *) &sin6, &sin6_size); 250 251 if (s < 0) { 252 if (errno != EINTR) 253 com_err(progname, errno, 254 gettext("from accept system call")); 255 continue; 256 } 257 258 if (debug) 259 child_pid = 0; 260 else 261 child_pid = fork(); 262 switch (child_pid) { 263 case -1: 264 com_err(progname, errno, gettext("while forking")); 265 exit(1); 266 /*NOTREACHED*/ 267 case 0: 268 /* child */ 269 (void) close(finet); 270 doit(s); 271 close(s); 272 _exit(0); 273 /*NOTREACHED*/ 274 default: 275 /* parent */ 276 wait(0); 277 close(s); 278 279 } 280 281 } 282 } 283 284 void doit(fd) 285 int fd; 286 { 287 struct sockaddr_storage from; 288 socklen_t fromlen; 289 int on = 1; 290 struct hostent *hp; 291 krb5_error_code retval; 292 krb5_data confmsg; 293 int lock_fd; 294 int omask; 295 krb5_enctype etype; 296 char ntop[NI_MAXHOST] = ""; 297 krb5_context doit_context; 298 299 retval = krb5_init_context(&doit_context); 300 if (retval) { 301 com_err(progname, retval, gettext("while initializing krb5")); 302 exit(1); 303 } 304 305 fromlen = (socklen_t)sizeof (from); 306 307 if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) { 308 fprintf(stderr, "%s: ", progname); 309 perror(gettext("getpeername")); 310 exit(1); 311 } 312 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on, 313 sizeof (on)) < 0) { 314 com_err(progname, errno, 315 gettext("while attempting setsockopt (SO_KEEPALIVE)")); 316 } 317 318 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 319 NULL, 0, NI_NUMERICHOST) != 0) { 320 321 /* getnameifo failed so use inet_ntop() to get printable addresses */ 322 if (from.ss_family == AF_INET) { 323
433 * Send the acknowledgement message generated in 434 * recv_database, then close the socket. 435 */ 436 if (retval = krb5_write_message(doit_context, (void *) &fd, 437 &confmsg)) { 438 krb5_free_data_contents(doit_context, &confmsg); 439 com_err(progname, retval, 440 gettext("while sending # of received bytes")); 441 exit(1); 442 } 443 krb5_free_data_contents(doit_context, &confmsg); 444 if (close(fd) < 0) { 445 com_err(progname, errno, 446 gettext("while trying to close database file")); 447 exit(1); 448 } 449 450 exit(0); 451 } 452 453 static void 454 kpropd_com_err_proc(whoami, code, fmt, args) 455 const char *whoami; 456 long code; 457 const char *fmt; 458 va_list args; 459 { 460 char error_buf[8096]; 461 462 error_buf[0] = '\0'; 463 if (fmt) 464 vsprintf(error_buf, fmt, args); 465 syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "", 466 code ? error_message(code) : "", code ? " " : "", error_buf); 467 } 468 469 void PRS(argc,argv) 470 int argc; 471 char **argv; 472 { 473 register char *word, ch; 474 char *cp; 475 int c; 476 struct hostent *hp; 477 char my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ]; 478 krb5_error_code retval; 479 static const char tmp[] = ".temp"; 480 481 kadm5_config_params params; 482 (void) setlocale(LC_ALL, ""); 483 484 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 485 #define TEXT_DOMAIN "KPROPD_TEST" /* Use this only if it weren't */ 486 #endif 487 488 (void) textdomain(TEXT_DOMAIN); 489 490 (void) memset((char *) &params, 0, sizeof (params)); 491 492 retval = krb5_init_context(&kpropd_context); 493 if (retval) { 494 com_err(argv[0], retval, 495 gettext("while initializing krb5")); 496 exit(1); 497 } 498 progname = argv[0]; 499 while ((c = getopt(argc, argv, "df:F:p:P:r:s:Sa:")) != EOF){ 500 switch (c) { 501 case 'd': 502 debug++; 503 break; 504 case 'f': 505 file = optarg; 506 if (!file) 507 usage(); 508 break; 509 case 'F': 510 kerb_database = optarg; 511 if (!kerb_database) 512 usage(); 513 break; 514 case 'p': 515 kdb5_util = optarg; 516 if (!kdb5_util) 517 usage(); 518 break; 519 case 'P': 520 port = htons(atoi(optarg)); 521 if (!port) 522 usage(); 523 break; 524 case 'r': 525 realm = optarg; 526 if (!realm) 527 usage(); 528 break; 529 case 's': 530 params.realm = realm; 531 params.mask |= KADM5_CONFIG_REALM; 532 srvtab = optarg; 533 if (!srvtab) 534 usage(); 535 break; 536 case 'S': 537 standalone++; 538 break; 539 case 'a': 540 acl_file_name = optarg; 541 if (!acl_file_name) 542 usage(); 543 break; 544 case '?': 545 default: 546 usage(); 547 } 548 549 } 550 /* 551 * If not in debug mode, switch com_err reporting to syslog
564 com_err(progname, retval, 565 gettext("While trying to construct my service name")); 566 exit(1); 567 } 568 if (realm) { 569 (void) krb5_xfree(krb5_princ_realm(context, server)->data); 570 krb5_princ_set_realm_length(context, server, strlen(realm)); 571 krb5_princ_set_realm_data(context, server, strdup(realm)); 572 } 573 /* 574 * Construct the name of the temporary file. 575 */ 576 if ((temp_file_name = (char *) malloc(strlen(file) + 577 strlen(tmp) + 1)) == NULL) { 578 com_err(progname, ENOMEM, 579 gettext("while allocating filename for temp file")); 580 exit(1); 581 } 582 strcpy(temp_file_name, file); 583 strcat(temp_file_name, tmp); 584 } 585 586 /* 587 * Figure out who's calling on the other end of the connection.... 588 */ 589 void 590 kerberos_authenticate(context, fd, clientp, etype, ss) 591 krb5_context context; 592 int fd; 593 krb5_principal * clientp; 594 krb5_enctype * etype; 595 struct sockaddr_storage ss; 596 { 597 krb5_error_code retval; 598 krb5_ticket * ticket; 599 struct sockaddr_storage r_ss; 600 int ss_length; 601 krb5_keytab keytab = NULL; 602 603 /* 604 * Set recv_addr and send_addr 605 */ 606 if (cvtkaddr(&ss, &sender_addr) == NULL) {
940 fprintf(stderr, 941 gettext("Error text from client: %s\n"), 942 error->text.data); 943 } 944 krb5_free_error(context, error); 945 exit(1); 946 } 947 948 void 949 load_database(context, kdb5_util, database_file_name) 950 krb5_context context; 951 char *kdb5_util; 952 char *database_file_name; 953 { 954 static char *edit_av[10]; 955 int error_ret, save_stderr; 956 int child_pid; 957 int count; 958 int waitb; 959 krb5_error_code retval; 960 961 if (debug) 962 printf(gettext("calling kdb5_util to load database\n")); 963 964 edit_av[0] = kdb5_util; 965 count = 1; 966 if (realm) { 967 edit_av[count++] = "-r"; 968 edit_av[count++] = realm; 969 } 970 edit_av[count++] = "load"; 971 if (kerb_database) { 972 edit_av[count++] = "-d"; 973 edit_av[count++] = kerb_database; 974 } 975 edit_av[count++] = database_file_name; 976 edit_av[count++] = NULL; 977 978 switch(child_pid = fork()) { 979 case -1: 980 com_err(progname, errno, gettext("while trying to fork %s"), 981 kdb5_util); 982 exit(1); 983 /*NOTREACHED*/ 984 case 0: 985 if (!debug) { 986 save_stderr = dup(2); 987 close(0); 988 close(1); 989 close(2); 990 open("/dev/null", O_RDWR); 991 dup(0); 992 dup(0); 993 } 994


8 * a specific license from the United States Government. It is the 9 * responsibility of any person or organization contemplating export to 10 * obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of FundsXpress. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. FundsXpress makes no representations about the suitability of 20 * this software for any purpose. It is provided "as is" without express 21 * or implied warranty. 22 * 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "@(#)kpropd.c 1.6 04/07/27 SMI" 29 30 /* 31 * slave/kpropd.c 32 * 33 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 34 * All Rights Reserved. 35 * 36 * Export of this software from the United States of America may 37 * require a specific license from the United States Government. 38 * It is the responsibility of any person or organization contemplating 39 * export to obtain such a license before exporting. 40 * 41 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 42 * distribute this software and its documentation for any purpose and 43 * without fee is hereby granted, provided that the above copyright 44 * notice appear in all copies and that both that copyright notice and 45 * this permission notice appear in supporting documentation, and that 46 * the name of M.I.T. not be used in advertising or publicity pertaining 47 * to distribution of the software without specific, written prior 48 * permission. Furthermore if you modify this software you must label
71 #endif 72 #include <fcntl.h> 73 #include <sys/types.h> 74 #include <sys/time.h> 75 #include <sys/stat.h> 76 #include <sys/socket.h> 77 #include <sys/wait.h> 78 #include <netinet/in.h> 79 #include <arpa/inet.h> 80 #include <sys/param.h> 81 #include <netdb.h> 82 #include <syslog.h> 83 #include <libintl.h> 84 #include <locale.h> 85 #include <k5-int.h> 86 #include <socket-utils.h> 87 #include "com_err.h" 88 #include <errno.h> 89 90 #include "kprop.h" 91 #include <iprop_hdr.h> 92 #include "iprop.h" 93 #include <kadm5/admin.h> 94 #include <kdb/kdb_log.h> 95 96 #define SYSLOG_CLASS LOG_DAEMON 97 98 char *poll_time = NULL; 99 char *def_realm = NULL; 100 boolean_t runonce = B_FALSE; 101 102 /* 103 * This struct simulates the use of _kadm5_server_handle_t 104 */ 105 typedef struct _kadm5_iprop_handle_t { 106 krb5_ui_4 magic_number; 107 krb5_ui_4 struct_version; 108 krb5_ui_4 api_version; 109 char *cache_name; 110 int destroy_cache; 111 CLIENT *clnt; 112 krb5_context context; 113 kadm5_config_params params; 114 struct _kadm5_iprop_handle_t *lhandle; 115 } *kadm5_iprop_handle_t; 116 117 static char *kprop_version = KPROP_PROT_VERSION; 118 119 char *progname; 120 int debug = 0; 121 char *srvtab = 0; 122 int standalone = 0; 123 124 krb5_principal server; /* This is our server principal name */ 125 krb5_principal client; /* This is who we're talking to */ 126 krb5_context kpropd_context; 127 krb5_auth_context auth_context; 128 char *realm = NULL; /* Our realm */ 129 char *file = KPROPD_DEFAULT_FILE; 130 char *temp_file_name; 131 char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL; 132 char *kerb_database = NULL; 133 char *acl_file_name = KPROPD_ACL_FILE; 134 135 int database_fd; 136 krb5_address sender_addr; 137 krb5_address receiver_addr; 138 short port = 0; 139 140 void PRS 141 (int, char**); 142 int do_standalone 143 (iprop_role iproprole); 144 void doit 145 (int); 146 krb5_error_code do_iprop(kdb_log_context *log_ctx); 147 148 void kerberos_authenticate 149 (krb5_context, 150 int, 151 krb5_principal *, 152 krb5_enctype *, 153 struct sockaddr_storage); 154 155 krb5_boolean authorized_principal 156 (krb5_context, 157 krb5_principal, 158 krb5_enctype); 159 void recv_database 160 (krb5_context, 161 int, 162 int, 163 krb5_data *); 164 void load_database 165 (krb5_context, 166 char *, 167 char *); 168 void send_error 169 (krb5_context, 170 int, 171 krb5_error_code, 172 char *); 173 void recv_error 174 (krb5_context, 175 krb5_data *); 176 int convert_polltime 177 (char *); 178 unsigned int backoff_from_master 179 (int *); 180 181 static void usage() 182 { 183 fprintf(stderr, 184 gettext("\nUsage: %s\n"), /* progname may be a long pathname */ 185 progname); 186 187 fprintf(stderr, 188 gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n")); 189 190 fprintf(stderr, 191 gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n")); 192 193 fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n")); 194 195 exit(1); 196 } 197 198 int 199 main(argc, argv) 200 int argc; 201 char **argv; 202 { 203 krb5_error_code retval; 204 int ret = 0; 205 kdb_log_context *log_ctx; 206 207 PRS(argc, argv); 208 209 log_ctx = kpropd_context->kdblog_context; 210 211 if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 212 /* 213 * We wanna do iprop ! 214 */ 215 retval = do_iprop(log_ctx); 216 if (retval) { 217 com_err(progname, retval, 218 gettext("do_iprop failed.\n")); 219 exit(1); 220 } 221 222 } else { 223 if (standalone) 224 ret = do_standalone(IPROP_NULL); 225 else 226 doit(0); 227 } 228 229 exit(ret); 230 } 231 232 int do_standalone(iprop_role iproprole) 233 { 234 struct linger linger; 235 struct servent *sp; 236 int finet, fromlen, s; 237 int on = 1; 238 int ret, status = 0; 239 struct sockaddr_in6 sin6 = { AF_INET6 }; 240 int sin6_size = sizeof (sin6); 241 242 /* listen for either ipv4 or ipv6 */ 243 finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 244 if (finet < 0 ) { 245 com_err(progname, errno, gettext("while obtaining socket")); 246 exit(1); 247 } 248 249 if(!port) { 250 sp = getservbyname(KPROP_SERVICE, "tcp"); 251 if (sp == NULL) { 252 com_err(progname, 0, gettext("%s/tcp: unknown service"), 253 KPROP_SERVICE); 254 exit(1); 255 } 256 sin6.sin6_port = sp->s_port; 257 } else 258 sin6.sin6_port = port; 259 260 /* 261 * We need to close the socket immediately if iprop is enabled, 262 * since back-to-back full resyncs are possible, so we do not 263 * linger around for too long 264 */ 265 if (iproprole == IPROP_SLAVE) { 266 if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, 267 (char *)&on, sizeof(on)) < 0) 268 com_err(progname, errno, 269 gettext("in setsockopt(SO_REUSEADDR)")); 270 linger.l_onoff = 1; 271 linger.l_linger = 2; 272 if (setsockopt(finet, SOL_SOCKET, SO_LINGER, 273 (void *)&linger, sizeof(linger)) < 0) 274 com_err(progname, errno, 275 gettext("in setsockopt(SO_LINGER)")); 276 } 277 if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) { 278 if (debug) { 279 on = 1; 280 fprintf(stderr, 281 gettext("%s: attempting to rebind socket " 282 "with SO_REUSEADDR\n"), progname); 283 if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, 284 (char *)&on, sizeof(on)) < 0) { 285 com_err(progname, errno, 286 gettext("in setsockopt(SO_REUSEADDR)")); 287 } 288 ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6)); 289 } 290 291 if (ret < 0) { 292 perror(gettext("bind")); 293 com_err(progname, errno, 294 gettext("while binding listener socket")); 295 exit(1); 296 } 297 } 298 299 if (!debug && (iproprole != IPROP_SLAVE)) 300 daemon(1, 0); 301 302 #ifdef PID_FILE 303 if ((pidfile = fopen(PID_FILE, "w")) != NULL) { 304 fprintf(pidfile, gettext("%d\n"), getpid()); 305 fclose(pidfile); 306 } else 307 com_err(progname, errno, 308 gettext("while opening pid file %s for writing"), 309 PID_FILE); 310 #endif 311 312 if (listen(finet, 5) < 0) { 313 com_err(progname, errno, gettext("in listen call")); 314 exit(1); 315 } 316 317 while (1) { 318 int child_pid; 319 320 s = accept(finet, (struct sockaddr *) &sin6, &sin6_size); 321 322 if (s < 0) { 323 if (errno != EINTR) 324 com_err(progname, errno, 325 gettext("from accept system call")); 326 continue; 327 } 328 329 if (debug && (iproprole != IPROP_SLAVE)) 330 child_pid = 0; 331 else 332 child_pid = fork(); 333 334 switch (child_pid) { 335 case -1: 336 com_err(progname, errno, gettext("while forking")); 337 exit(1); 338 /*NOTREACHED*/ 339 case 0: 340 /* child */ 341 (void) close(finet); 342 doit(s); 343 close(s); 344 _exit(0); 345 /*NOTREACHED*/ 346 default: 347 /* parent */ 348 if (wait(&status) < 0) { 349 com_err(progname, errno, 350 gettext("while waiting to receive database")); 351 exit(1); 352 } 353 354 close(s); 355 if (iproprole == IPROP_SLAVE) 356 close(finet); 357 358 if ((ret = WEXITSTATUS(status)) != 0) 359 return (ret); 360 } 361 362 if (iproprole == IPROP_SLAVE) 363 break; 364 } 365 366 return (0); 367 } 368 369 void doit(fd) 370 int fd; 371 { 372 struct sockaddr_storage from; 373 socklen_t fromlen; 374 int on = 1; 375 struct hostent *hp; 376 krb5_error_code retval; 377 krb5_data confmsg; 378 int lock_fd; 379 int omask; 380 krb5_enctype etype; 381 char ntop[NI_MAXHOST] = ""; 382 krb5_context doit_context; 383 kdb_log_context *log_ctx; 384 385 retval = krb5_init_context(&doit_context); 386 if (retval) { 387 com_err(progname, retval, gettext("while initializing krb5")); 388 exit(1); 389 } 390 log_ctx = kpropd_context->kdblog_context; 391 if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) 392 ulog_set_role(doit_context, IPROP_SLAVE); 393 394 fromlen = (socklen_t)sizeof (from); 395 396 if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) { 397 fprintf(stderr, "%s: ", progname); 398 perror(gettext("getpeername")); 399 exit(1); 400 } 401 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on, 402 sizeof (on)) < 0) { 403 com_err(progname, errno, 404 gettext("while attempting setsockopt (SO_KEEPALIVE)")); 405 } 406 407 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 408 NULL, 0, NI_NUMERICHOST) != 0) { 409 410 /* getnameifo failed so use inet_ntop() to get printable addresses */ 411 if (from.ss_family == AF_INET) { 412
522 * Send the acknowledgement message generated in 523 * recv_database, then close the socket. 524 */ 525 if (retval = krb5_write_message(doit_context, (void *) &fd, 526 &confmsg)) { 527 krb5_free_data_contents(doit_context, &confmsg); 528 com_err(progname, retval, 529 gettext("while sending # of received bytes")); 530 exit(1); 531 } 532 krb5_free_data_contents(doit_context, &confmsg); 533 if (close(fd) < 0) { 534 com_err(progname, errno, 535 gettext("while trying to close database file")); 536 exit(1); 537 } 538 539 exit(0); 540 } 541 542 543 /* 544 * Routine to handle incremental update transfer(s) from master KDC 545 */ 546 krb5_error_code do_iprop(kdb_log_context *log_ctx) { 547 CLIENT *cl; 548 kadm5_ret_t retval; 549 kadm5_config_params params; 550 krb5_ccache cc; 551 krb5_principal iprop_svc_principal; 552 void *server_handle = NULL; 553 char *iprop_svc_princstr = NULL; 554 char *master_svc_princstr = NULL; 555 char *admin_server = NULL; 556 char *keytab_name = NULL; 557 unsigned int pollin, backoff_time; 558 int backoff_cnt = 0; 559 int reinit_cnt = 0; 560 int ret; 561 boolean_t frdone = B_FALSE; 562 563 kdb_incr_result_t *incr_ret; 564 static kdb_last_t mylast; 565 566 kdb_fullresync_result_t *full_ret; 567 char *full_resync_arg = NULL; 568 569 kadm5_iprop_handle_t handle; 570 kdb_hlog_t *ulog; 571 572 if (!debug) 573 daemon(0, 0); 574 575 pollin = (unsigned int)0; 576 (void) memset((char *)&params, 0, sizeof (params)); 577 ulog = log_ctx->ulog; 578 579 params.mask |= KADM5_CONFIG_REALM; 580 params.realm = def_realm; 581 582 if (master_svc_princstr == NULL) { 583 if (retval = kadm5_get_kiprop_host_srv_name(kpropd_context, 584 def_realm, &master_svc_princstr)) { 585 com_err(progname, retval, 586 gettext("%s: unable to get kiprop host based " 587 "service name for realm %s\n"), 588 progname, def_realm); 589 exit(1); 590 } 591 } 592 593 /* 594 * Set cc to the default credentials cache 595 */ 596 if (retval = krb5_cc_default(kpropd_context, &cc)) { 597 com_err(progname, retval, 598 gettext("while opening default " 599 "credentials cache")); 600 exit(1); 601 } 602 603 retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME, 604 KRB5_NT_SRV_HST, &iprop_svc_principal); 605 if (retval) { 606 com_err(progname, retval, gettext("while trying to construct " 607 "host service principal")); 608 exit(1); 609 } 610 611 if (retval = krb5_unparse_name(kpropd_context, iprop_svc_principal, 612 &iprop_svc_princstr)) { 613 com_err(progname, retval, 614 gettext("while canonicalizing " 615 "principal name")); 616 krb5_free_principal(kpropd_context, iprop_svc_principal); 617 exit(1); 618 } 619 krb5_free_principal(kpropd_context, iprop_svc_principal); 620 621 reinit: 622 /* 623 * Authentication, initialize rpcsec_gss handle etc. 624 */ 625 retval = kadm5_init_with_skey(iprop_svc_princstr, keytab_name, 626 master_svc_princstr, 627 &params, 628 KADM5_STRUCT_VERSION, 629 KADM5_API_VERSION_2, 630 &server_handle); 631 632 if (retval) { 633 if (retval == KADM5_RPC_ERROR) { 634 reinit_cnt++; 635 if (server_handle) 636 kadm5_destroy((void *) server_handle); 637 server_handle = (void *)NULL; 638 handle = (kadm5_iprop_handle_t)NULL; 639 640 com_err(progname, retval, gettext( 641 "while attempting to connect" 642 " to master KDC ... retrying")); 643 backoff_time = backoff_from_master(&reinit_cnt); 644 (void) sleep(backoff_time); 645 goto reinit; 646 } else { 647 com_err(progname, retval, 648 gettext("while initializing %s interface"), 649 progname); 650 if (retval == KADM5_BAD_CLIENT_PARAMS || 651 retval == KADM5_BAD_SERVER_PARAMS) 652 usage(); 653 exit(1); 654 } 655 } 656 657 /* 658 * Reset re-initialization count to zero now. 659 */ 660 reinit_cnt = backoff_time = 0; 661 662 /* 663 * Reset the handle to the correct type for the RPC call 664 */ 665 handle = server_handle; 666 667 /* 668 * If we have reached this far, we have succesfully established 669 * a RPCSEC_GSS connection; we now start polling for updates 670 */ 671 if (poll_time == NULL) { 672 if ((poll_time = (char *)strdup("2m")) == NULL) { 673 com_err(progname, ENOMEM, 674 gettext("Unable to allocate poll_time")); 675 exit(1); 676 } 677 } 678 679 if (pollin == (unsigned int)0) 680 pollin = convert_polltime(poll_time); 681 682 for (;;) { 683 incr_ret = NULL; 684 full_ret = NULL; 685 686 /* 687 * Get the most recent ulog entry sno + ts, which 688 * we package in the request to the master KDC 689 */ 690 mylast.last_sno = ulog->kdb_last_sno; 691 mylast.last_time = ulog->kdb_last_time; 692 693 /* 694 * Loop continuously on an iprop_get_updates_1(), 695 * so that we can keep probing the master for updates 696 * or (if needed) do a full resync of the krb5 db. 697 */ 698 699 incr_ret = iprop_get_updates_1(&mylast, handle->clnt); 700 if (incr_ret == (kdb_incr_result_t *)NULL) { 701 clnt_perror(handle->clnt, 702 "iprop_get_updates call failed"); 703 if (server_handle) 704 kadm5_destroy((void *)server_handle); 705 server_handle = (void *)NULL; 706 handle = (kadm5_iprop_handle_t)NULL; 707 goto reinit; 708 } 709 710 switch (incr_ret->ret) { 711 712 case UPDATE_FULL_RESYNC_NEEDED: 713 /* 714 * We dont do a full resync again, if the last 715 * X'fer was a resync and if the master sno is 716 * still "0", i.e. no updates so far. 717 */ 718 if ((frdone == B_TRUE) && (incr_ret->lastentry.last_sno 719 == 0)) { 720 break; 721 } else { 722 723 full_ret = iprop_full_resync_1((void *) 724 &full_resync_arg, handle->clnt); 725 726 if (full_ret == (kdb_fullresync_result_t *) 727 NULL) { 728 clnt_perror(handle->clnt, 729 "iprop_full_resync call failed"); 730 if (server_handle) 731 kadm5_destroy((void *) 732 server_handle); 733 server_handle = (void *)NULL; 734 handle = (kadm5_iprop_handle_t)NULL; 735 goto reinit; 736 } 737 } 738 739 switch (full_ret->ret) { 740 case UPDATE_OK: 741 backoff_cnt = 0; 742 /* 743 * We now listen on the kprop port for 744 * the full dump 745 */ 746 ret = do_standalone(log_ctx->iproprole); 747 if (ret) 748 syslog(LOG_WARNING, 749 gettext("kpropd: Full resync, " 750 "invalid return.")); 751 if (debug) 752 if (ret) 753 fprintf(stderr, 754 gettext("Full resync " 755 "was unsuccessful\n")); 756 else 757 fprintf(stderr, 758 gettext("Full resync " 759 "was successful\n")); 760 frdone = B_TRUE; 761 break; 762 763 case UPDATE_BUSY: 764 /* 765 * Exponential backoff 766 */ 767 backoff_cnt++; 768 break; 769 770 case UPDATE_FULL_RESYNC_NEEDED: 771 case UPDATE_NIL: 772 default: 773 backoff_cnt = 0; 774 frdone = B_FALSE; 775 syslog(LOG_ERR, gettext("kpropd: Full resync," 776 " invalid return from master KDC.")); 777 break; 778 779 case UPDATE_PERM_DENIED: 780 syslog(LOG_ERR, gettext("kpropd: Full resync," 781 " permission denied.")); 782 goto error; 783 784 case UPDATE_ERROR: 785 syslog(LOG_ERR, gettext("kpropd: Full resync," 786 " error returned from master KDC.")); 787 goto error; 788 } 789 break; 790 791 case UPDATE_OK: 792 backoff_cnt = 0; 793 frdone = B_FALSE; 794 795 /* 796 * ulog_replay() will convert the ulog updates to db 797 * entries using the kdb conv api and will commit 798 * the entries to the slave kdc database 799 */ 800 retval = ulog_replay(kpropd_context, incr_ret); 801 802 if (retval) { 803 syslog(LOG_ERR, gettext("kpropd: ulog_replay" 804 " failed, updates not registered.")); 805 break; 806 } 807 808 if (debug) 809 fprintf(stderr, gettext("Update transfer " 810 "from master was OK\n")); 811 break; 812 813 case UPDATE_PERM_DENIED: 814 syslog(LOG_ERR, gettext("kpropd: get_updates," 815 " permission denied.")); 816 goto error; 817 818 case UPDATE_ERROR: 819 syslog(LOG_ERR, gettext("kpropd: get_updates, error " 820 "returned from master KDC.")); 821 goto error; 822 823 case UPDATE_BUSY: 824 /* 825 * Exponential backoff 826 */ 827 backoff_cnt++; 828 break; 829 830 case UPDATE_NIL: 831 /* 832 * Master-slave are in sync 833 */ 834 if (debug) 835 fprintf(stderr, gettext("Master, slave KDC's " 836 "are in-sync, no updates\n")); 837 backoff_cnt = 0; 838 frdone = B_FALSE; 839 break; 840 841 default: 842 backoff_cnt = 0; 843 syslog(LOG_ERR, gettext("kpropd: get_updates," 844 " invalid return from master KDC.")); 845 break; 846 } 847 848 if (runonce == B_TRUE) 849 goto done; 850 851 /* 852 * Sleep for the specified poll interval (Default is 2 mts), 853 * or do a binary exponential backoff if we get an 854 * UPDATE_BUSY signal 855 */ 856 if (backoff_cnt > 0) { 857 backoff_time = backoff_from_master(&backoff_cnt); 858 if (debug) 859 fprintf(stderr, gettext("Busy signal received " 860 "from master, backoff for %d secs\n"), 861 backoff_time); 862 (void) sleep(backoff_time); 863 } 864 else 865 (void) sleep(pollin); 866 867 } 868 869 870 error: 871 if (debug) 872 fprintf(stderr, gettext("ERROR returned by master, bailing\n")); 873 syslog(LOG_ERR, gettext("kpropd: ERROR returned by master KDC," 874 " bailing.\n")); 875 done: 876 if (poll_time) 877 free(poll_time); 878 if(iprop_svc_princstr) 879 free(iprop_svc_princstr); 880 if (master_svc_princstr) 881 free(master_svc_princstr); 882 if (retval = krb5_cc_close(kpropd_context, cc)) { 883 com_err(progname, retval, 884 gettext("while closing default ccache")); 885 exit(1); 886 } 887 if (def_realm) 888 free(def_realm); 889 if (server_handle) 890 kadm5_destroy((void *)server_handle); 891 if (kpropd_context) 892 krb5_free_context(kpropd_context); 893 894 if (runonce == B_TRUE) 895 return (0); 896 else 897 exit(1); 898 } 899 900 901 /* 902 * Do exponential backoff, since master KDC is BUSY or down 903 */ 904 unsigned int backoff_from_master(int *cnt) { 905 unsigned int btime; 906 907 btime = (unsigned int)(2<<(*cnt)); 908 if (btime > MAX_BACKOFF) { 909 btime = MAX_BACKOFF; 910 *cnt--; 911 } 912 913 return (btime); 914 } 915 916 917 /* 918 * Routine to convert the `pollstr' string to seconds 919 */ 920 int convert_polltime(char *pollstr) { 921 char *tokenptr = NULL; 922 int len, polltime; 923 924 len = polltime = 0; 925 926 if ((len = strcspn(pollstr, "s")) < strlen(pollstr)) { 927 tokenptr = malloc((len + 1) * sizeof(char)); 928 (void) strlcpy(tokenptr, pollstr, len + 1); 929 polltime = atoi(tokenptr); 930 } 931 932 if ((len = strcspn(pollstr, "m")) < strlen(pollstr)) { 933 tokenptr = malloc((len + 1) * sizeof(char)); 934 (void) strlcpy(tokenptr, pollstr, len + 1); 935 polltime = atoi(tokenptr) * 60; 936 } 937 938 if ((len = strcspn(pollstr, "h")) < strlen(pollstr)) { 939 tokenptr = malloc((len + 1) * sizeof(char)); 940 (void) strlcpy(tokenptr, pollstr, len + 1); 941 polltime = atoi(tokenptr) * 3600; 942 } 943 944 if (tokenptr != NULL) 945 free(tokenptr); 946 /* 947 * If we have a bogus pollstr value, set polltime to the 948 * default of 2 mts (120 seconds). 949 */ 950 if (polltime == 0) 951 polltime = 120; 952 return (polltime); 953 } 954 955 static void 956 kpropd_com_err_proc(whoami, code, fmt, args) 957 const char *whoami; 958 long code; 959 const char *fmt; 960 va_list args; 961 { 962 char error_buf[8096]; 963 964 error_buf[0] = '\0'; 965 if (fmt) 966 vsprintf(error_buf, fmt, args); 967 syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "", 968 code ? error_message(code) : "", code ? " " : "", error_buf); 969 } 970 971 void PRS(argc,argv) 972 int argc; 973 char **argv; 974 { 975 register char *word, ch; 976 char *cp; 977 int c; 978 struct hostent *hp; 979 char my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ]; 980 krb5_error_code retval; 981 static const char tmp[] = ".temp"; 982 kadm5_config_params params; 983 984 (void) setlocale(LC_ALL, ""); 985 986 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 987 #define TEXT_DOMAIN "KPROPD_TEST" /* Use this only if it weren't */ 988 #endif 989 990 (void) textdomain(TEXT_DOMAIN); 991 992 (void) memset((char *) &params, 0, sizeof (params)); 993 994 retval = krb5_init_context(&kpropd_context); 995 if (retval) { 996 com_err(argv[0], retval, 997 gettext("while initializing krb5")); 998 exit(1); 999 } 1000 progname = argv[0]; 1001 while ((c = getopt(argc, argv, "dtf:F:p:P:r:s:Sa:")) != EOF){ 1002 switch (c) { 1003 case 'd': 1004 debug++; 1005 break; 1006 case 't': 1007 /* 1008 * Undocumented option - for testing only. 1009 * 1010 * Option to run the kpropd server exactly 1011 * once (this is true only if iprop is enabled). 1012 */ 1013 runonce = B_TRUE; 1014 break; 1015 1016 case 'f': 1017 file = optarg; 1018 if (!file) 1019 usage(); 1020 break; 1021 case 'F': 1022 kerb_database = optarg; 1023 if (!kerb_database) 1024 usage(); 1025 break; 1026 case 'p': 1027 kdb5_util = optarg; 1028 if (!kdb5_util) 1029 usage(); 1030 break; 1031 case 'P': 1032 port = htons(atoi(optarg)); 1033 if (!port) 1034 usage(); 1035 break; 1036 case 'r': 1037 realm = optarg; 1038 if (!realm) 1039 usage(); 1040 params.realm = realm; 1041 params.mask |= KADM5_CONFIG_REALM; 1042 break; 1043 case 's': 1044 srvtab = optarg; 1045 if (!srvtab) 1046 usage(); 1047 break; 1048 case 'S': 1049 standalone++; 1050 break; 1051 case 'a': 1052 acl_file_name = optarg; 1053 if (!acl_file_name) 1054 usage(); 1055 break; 1056 case '?': 1057 default: 1058 usage(); 1059 } 1060 1061 } 1062 /* 1063 * If not in debug mode, switch com_err reporting to syslog
1076 com_err(progname, retval, 1077 gettext("While trying to construct my service name")); 1078 exit(1); 1079 } 1080 if (realm) { 1081 (void) krb5_xfree(krb5_princ_realm(context, server)->data); 1082 krb5_princ_set_realm_length(context, server, strlen(realm)); 1083 krb5_princ_set_realm_data(context, server, strdup(realm)); 1084 } 1085 /* 1086 * Construct the name of the temporary file. 1087 */ 1088 if ((temp_file_name = (char *) malloc(strlen(file) + 1089 strlen(tmp) + 1)) == NULL) { 1090 com_err(progname, ENOMEM, 1091 gettext("while allocating filename for temp file")); 1092 exit(1); 1093 } 1094 strcpy(temp_file_name, file); 1095 strcat(temp_file_name, tmp); 1096 1097 retval = kadm5_get_config_params(kpropd_context, NULL, NULL, &params, 1098 &params); 1099 if (retval) { 1100 com_err(progname, retval, gettext("while initializing")); 1101 exit(1); 1102 } 1103 if (params.iprop_enabled == TRUE) { 1104 ulog_set_role(kpropd_context, IPROP_SLAVE); 1105 poll_time = params.iprop_polltime; 1106 1107 if (ulog_map(kpropd_context, &params, FKPROPD)) { 1108 com_err(progname, errno, 1109 gettext("Unable to map log!\n")); 1110 exit(1); 1111 } 1112 } 1113 1114 /* 1115 * Grab the realm info and check if iprop is enabled. 1116 */ 1117 if (def_realm == NULL) { 1118 retval = krb5_get_default_realm(kpropd_context, &def_realm); 1119 if (retval) { 1120 com_err(progname, retval, 1121 gettext("Unable to get default realm")); 1122 exit(1); 1123 } 1124 } 1125 } 1126 1127 /* 1128 * Figure out who's calling on the other end of the connection.... 1129 */ 1130 void 1131 kerberos_authenticate(context, fd, clientp, etype, ss) 1132 krb5_context context; 1133 int fd; 1134 krb5_principal * clientp; 1135 krb5_enctype * etype; 1136 struct sockaddr_storage ss; 1137 { 1138 krb5_error_code retval; 1139 krb5_ticket * ticket; 1140 struct sockaddr_storage r_ss; 1141 int ss_length; 1142 krb5_keytab keytab = NULL; 1143 1144 /* 1145 * Set recv_addr and send_addr 1146 */ 1147 if (cvtkaddr(&ss, &sender_addr) == NULL) {
1481 fprintf(stderr, 1482 gettext("Error text from client: %s\n"), 1483 error->text.data); 1484 } 1485 krb5_free_error(context, error); 1486 exit(1); 1487 } 1488 1489 void 1490 load_database(context, kdb5_util, database_file_name) 1491 krb5_context context; 1492 char *kdb5_util; 1493 char *database_file_name; 1494 { 1495 static char *edit_av[10]; 1496 int error_ret, save_stderr; 1497 int child_pid; 1498 int count; 1499 int waitb; 1500 krb5_error_code retval; 1501 kdb_log_context *log_ctx; 1502 1503 if (debug) 1504 printf(gettext("calling kdb5_util to load database\n")); 1505 1506 log_ctx = context->kdblog_context; 1507 1508 edit_av[0] = kdb5_util; 1509 count = 1; 1510 if (realm) { 1511 edit_av[count++] = "-r"; 1512 edit_av[count++] = realm; 1513 } 1514 edit_av[count++] = "load"; 1515 if (kerb_database) { 1516 edit_av[count++] = "-d"; 1517 edit_av[count++] = kerb_database; 1518 } 1519 1520 if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 1521 edit_av[count++] = "-i"; 1522 } 1523 edit_av[count++] = database_file_name; 1524 edit_av[count++] = NULL; 1525 1526 switch(child_pid = fork()) { 1527 case -1: 1528 com_err(progname, errno, gettext("while trying to fork %s"), 1529 kdb5_util); 1530 exit(1); 1531 /*NOTREACHED*/ 1532 case 0: 1533 if (!debug) { 1534 save_stderr = dup(2); 1535 close(0); 1536 close(1); 1537 close(2); 1538 open("/dev/null", O_RDWR); 1539 dup(0); 1540 dup(0); 1541 } 1542