1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * All rights reserved. 6*0Sstevel@tonic-gate * 7*0Sstevel@tonic-gate * Export of this software from the United States of America may require 8*0Sstevel@tonic-gate * a specific license from the United States Government. It is the 9*0Sstevel@tonic-gate * responsibility of any person or organization contemplating export to 10*0Sstevel@tonic-gate * obtain such a license before exporting. 11*0Sstevel@tonic-gate * 12*0Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13*0Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 14*0Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 15*0Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 16*0Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 17*0Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining 18*0Sstevel@tonic-gate * to distribution of the software without specific, written prior 19*0Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of 20*0Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 21*0Sstevel@tonic-gate * or implied warranty. 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25*0Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26*0Sstevel@tonic-gate */ 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * slave/kpropd.c 32*0Sstevel@tonic-gate * 33*0Sstevel@tonic-gate * Copyright 1990,1991 by the Massachusetts Institute of Technology. 34*0Sstevel@tonic-gate * All Rights Reserved. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * Export of this software from the United States of America may 37*0Sstevel@tonic-gate * require a specific license from the United States Government. 38*0Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 39*0Sstevel@tonic-gate * export to obtain such a license before exporting. 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 42*0Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 43*0Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 44*0Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 45*0Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 46*0Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 47*0Sstevel@tonic-gate * to distribution of the software without specific, written prior 48*0Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 49*0Sstevel@tonic-gate * your software as modified software and not distribute it in such a 50*0Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 51*0Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 52*0Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 53*0Sstevel@tonic-gate * or implied warranty. 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * 56*0Sstevel@tonic-gate * XXX We need to modify the protocol so that an acknowledge is set 57*0Sstevel@tonic-gate * after each block, instead after the entire series is sent over. 58*0Sstevel@tonic-gate * The reason for this is so that error packets can get interpreted 59*0Sstevel@tonic-gate * right away. If you don't do this, the sender may never get the 60*0Sstevel@tonic-gate * error packet, because it will die an EPIPE trying to complete the 61*0Sstevel@tonic-gate * write... 62*0Sstevel@tonic-gate */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate #include <stdio.h> 65*0Sstevel@tonic-gate #include <ctype.h> 66*0Sstevel@tonic-gate #include <sys/file.h> 67*0Sstevel@tonic-gate #include <signal.h> 68*0Sstevel@tonic-gate #include <string.h> 69*0Sstevel@tonic-gate #ifndef POSIX_TERMIOS 70*0Sstevel@tonic-gate #include <sgtty.h> 71*0Sstevel@tonic-gate #endif 72*0Sstevel@tonic-gate #include <fcntl.h> 73*0Sstevel@tonic-gate #include <sys/types.h> 74*0Sstevel@tonic-gate #include <sys/time.h> 75*0Sstevel@tonic-gate #include <sys/stat.h> 76*0Sstevel@tonic-gate #include <sys/socket.h> 77*0Sstevel@tonic-gate #include <sys/wait.h> 78*0Sstevel@tonic-gate #include <netinet/in.h> 79*0Sstevel@tonic-gate #include <arpa/inet.h> 80*0Sstevel@tonic-gate #include <sys/param.h> 81*0Sstevel@tonic-gate #include <netdb.h> 82*0Sstevel@tonic-gate #include <syslog.h> 83*0Sstevel@tonic-gate #include <libintl.h> 84*0Sstevel@tonic-gate #include <locale.h> 85*0Sstevel@tonic-gate #include <k5-int.h> 86*0Sstevel@tonic-gate #include <socket-utils.h> 87*0Sstevel@tonic-gate #include "com_err.h" 88*0Sstevel@tonic-gate #include <errno.h> 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate #include "kprop.h" 91*0Sstevel@tonic-gate #include <iprop_hdr.h> 92*0Sstevel@tonic-gate #include "iprop.h" 93*0Sstevel@tonic-gate #include <kadm5/admin.h> 94*0Sstevel@tonic-gate #include <kdb/kdb_log.h> 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate #define SYSLOG_CLASS LOG_DAEMON 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate char *poll_time = NULL; 99*0Sstevel@tonic-gate char *def_realm = NULL; 100*0Sstevel@tonic-gate boolean_t runonce = B_FALSE; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * This struct simulates the use of _kadm5_server_handle_t 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate typedef struct _kadm5_iprop_handle_t { 106*0Sstevel@tonic-gate krb5_ui_4 magic_number; 107*0Sstevel@tonic-gate krb5_ui_4 struct_version; 108*0Sstevel@tonic-gate krb5_ui_4 api_version; 109*0Sstevel@tonic-gate char *cache_name; 110*0Sstevel@tonic-gate int destroy_cache; 111*0Sstevel@tonic-gate CLIENT *clnt; 112*0Sstevel@tonic-gate krb5_context context; 113*0Sstevel@tonic-gate kadm5_config_params params; 114*0Sstevel@tonic-gate struct _kadm5_iprop_handle_t *lhandle; 115*0Sstevel@tonic-gate } *kadm5_iprop_handle_t; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate static char *kprop_version = KPROP_PROT_VERSION; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate char *progname; 120*0Sstevel@tonic-gate int debug = 0; 121*0Sstevel@tonic-gate char *srvtab = 0; 122*0Sstevel@tonic-gate int standalone = 0; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate krb5_principal server; /* This is our server principal name */ 125*0Sstevel@tonic-gate krb5_principal client; /* This is who we're talking to */ 126*0Sstevel@tonic-gate krb5_context kpropd_context; 127*0Sstevel@tonic-gate krb5_auth_context auth_context; 128*0Sstevel@tonic-gate char *realm = NULL; /* Our realm */ 129*0Sstevel@tonic-gate char *file = KPROPD_DEFAULT_FILE; 130*0Sstevel@tonic-gate char *temp_file_name; 131*0Sstevel@tonic-gate char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL; 132*0Sstevel@tonic-gate char *kerb_database = NULL; 133*0Sstevel@tonic-gate char *acl_file_name = KPROPD_ACL_FILE; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate int database_fd; 136*0Sstevel@tonic-gate krb5_address sender_addr; 137*0Sstevel@tonic-gate krb5_address receiver_addr; 138*0Sstevel@tonic-gate short port = 0; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate void PRS 141*0Sstevel@tonic-gate (int, char**); 142*0Sstevel@tonic-gate int do_standalone 143*0Sstevel@tonic-gate (iprop_role iproprole); 144*0Sstevel@tonic-gate void doit 145*0Sstevel@tonic-gate (int); 146*0Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx); 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate void kerberos_authenticate 149*0Sstevel@tonic-gate (krb5_context, 150*0Sstevel@tonic-gate int, 151*0Sstevel@tonic-gate krb5_principal *, 152*0Sstevel@tonic-gate krb5_enctype *, 153*0Sstevel@tonic-gate struct sockaddr_storage); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate krb5_boolean authorized_principal 156*0Sstevel@tonic-gate (krb5_context, 157*0Sstevel@tonic-gate krb5_principal, 158*0Sstevel@tonic-gate krb5_enctype); 159*0Sstevel@tonic-gate void recv_database 160*0Sstevel@tonic-gate (krb5_context, 161*0Sstevel@tonic-gate int, 162*0Sstevel@tonic-gate int, 163*0Sstevel@tonic-gate krb5_data *); 164*0Sstevel@tonic-gate void load_database 165*0Sstevel@tonic-gate (krb5_context, 166*0Sstevel@tonic-gate char *, 167*0Sstevel@tonic-gate char *); 168*0Sstevel@tonic-gate void send_error 169*0Sstevel@tonic-gate (krb5_context, 170*0Sstevel@tonic-gate int, 171*0Sstevel@tonic-gate krb5_error_code, 172*0Sstevel@tonic-gate char *); 173*0Sstevel@tonic-gate void recv_error 174*0Sstevel@tonic-gate (krb5_context, 175*0Sstevel@tonic-gate krb5_data *); 176*0Sstevel@tonic-gate int convert_polltime 177*0Sstevel@tonic-gate (char *); 178*0Sstevel@tonic-gate unsigned int backoff_from_master 179*0Sstevel@tonic-gate (int *); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate static void usage() 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate fprintf(stderr, 184*0Sstevel@tonic-gate gettext("\nUsage: %s\n"), /* progname may be a long pathname */ 185*0Sstevel@tonic-gate progname); 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate fprintf(stderr, 188*0Sstevel@tonic-gate gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n")); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate fprintf(stderr, 191*0Sstevel@tonic-gate gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n")); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n")); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate exit(1); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate int 199*0Sstevel@tonic-gate main(argc, argv) 200*0Sstevel@tonic-gate int argc; 201*0Sstevel@tonic-gate char **argv; 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate krb5_error_code retval; 204*0Sstevel@tonic-gate int ret = 0; 205*0Sstevel@tonic-gate kdb_log_context *log_ctx; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate PRS(argc, argv); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate log_ctx = kpropd_context->kdblog_context; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * We wanna do iprop ! 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate retval = do_iprop(log_ctx); 216*0Sstevel@tonic-gate if (retval) { 217*0Sstevel@tonic-gate com_err(progname, retval, 218*0Sstevel@tonic-gate gettext("do_iprop failed.\n")); 219*0Sstevel@tonic-gate exit(1); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate } else { 223*0Sstevel@tonic-gate if (standalone) 224*0Sstevel@tonic-gate ret = do_standalone(IPROP_NULL); 225*0Sstevel@tonic-gate else 226*0Sstevel@tonic-gate doit(0); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate exit(ret); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate int do_standalone(iprop_role iproprole) 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate struct linger linger; 235*0Sstevel@tonic-gate struct servent *sp; 236*0Sstevel@tonic-gate int finet, fromlen, s; 237*0Sstevel@tonic-gate int on = 1; 238*0Sstevel@tonic-gate int ret, status = 0; 239*0Sstevel@tonic-gate struct sockaddr_in6 sin6 = { AF_INET6 }; 240*0Sstevel@tonic-gate int sin6_size = sizeof (sin6); 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* listen for either ipv4 or ipv6 */ 243*0Sstevel@tonic-gate finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 244*0Sstevel@tonic-gate if (finet < 0 ) { 245*0Sstevel@tonic-gate com_err(progname, errno, gettext("while obtaining socket")); 246*0Sstevel@tonic-gate exit(1); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if(!port) { 250*0Sstevel@tonic-gate sp = getservbyname(KPROP_SERVICE, "tcp"); 251*0Sstevel@tonic-gate if (sp == NULL) { 252*0Sstevel@tonic-gate com_err(progname, 0, gettext("%s/tcp: unknown service"), 253*0Sstevel@tonic-gate KPROP_SERVICE); 254*0Sstevel@tonic-gate exit(1); 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate sin6.sin6_port = sp->s_port; 257*0Sstevel@tonic-gate } else 258*0Sstevel@tonic-gate sin6.sin6_port = port; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate /* 261*0Sstevel@tonic-gate * We need to close the socket immediately if iprop is enabled, 262*0Sstevel@tonic-gate * since back-to-back full resyncs are possible, so we do not 263*0Sstevel@tonic-gate * linger around for too long 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate if (iproprole == IPROP_SLAVE) { 266*0Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, 267*0Sstevel@tonic-gate (char *)&on, sizeof(on)) < 0) 268*0Sstevel@tonic-gate com_err(progname, errno, 269*0Sstevel@tonic-gate gettext("in setsockopt(SO_REUSEADDR)")); 270*0Sstevel@tonic-gate linger.l_onoff = 1; 271*0Sstevel@tonic-gate linger.l_linger = 2; 272*0Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_LINGER, 273*0Sstevel@tonic-gate (void *)&linger, sizeof(linger)) < 0) 274*0Sstevel@tonic-gate com_err(progname, errno, 275*0Sstevel@tonic-gate gettext("in setsockopt(SO_LINGER)")); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) { 278*0Sstevel@tonic-gate if (debug) { 279*0Sstevel@tonic-gate on = 1; 280*0Sstevel@tonic-gate fprintf(stderr, 281*0Sstevel@tonic-gate gettext("%s: attempting to rebind socket " 282*0Sstevel@tonic-gate "with SO_REUSEADDR\n"), progname); 283*0Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, 284*0Sstevel@tonic-gate (char *)&on, sizeof(on)) < 0) { 285*0Sstevel@tonic-gate com_err(progname, errno, 286*0Sstevel@tonic-gate gettext("in setsockopt(SO_REUSEADDR)")); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6)); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (ret < 0) { 292*0Sstevel@tonic-gate perror(gettext("bind")); 293*0Sstevel@tonic-gate com_err(progname, errno, 294*0Sstevel@tonic-gate gettext("while binding listener socket")); 295*0Sstevel@tonic-gate exit(1); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate if (!debug && (iproprole != IPROP_SLAVE)) 300*0Sstevel@tonic-gate daemon(1, 0); 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate #ifdef PID_FILE 303*0Sstevel@tonic-gate if ((pidfile = fopen(PID_FILE, "w")) != NULL) { 304*0Sstevel@tonic-gate fprintf(pidfile, gettext("%d\n"), getpid()); 305*0Sstevel@tonic-gate fclose(pidfile); 306*0Sstevel@tonic-gate } else 307*0Sstevel@tonic-gate com_err(progname, errno, 308*0Sstevel@tonic-gate gettext("while opening pid file %s for writing"), 309*0Sstevel@tonic-gate PID_FILE); 310*0Sstevel@tonic-gate #endif 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (listen(finet, 5) < 0) { 313*0Sstevel@tonic-gate com_err(progname, errno, gettext("in listen call")); 314*0Sstevel@tonic-gate exit(1); 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate while (1) { 318*0Sstevel@tonic-gate int child_pid; 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate s = accept(finet, (struct sockaddr *) &sin6, &sin6_size); 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate if (s < 0) { 323*0Sstevel@tonic-gate if (errno != EINTR) 324*0Sstevel@tonic-gate com_err(progname, errno, 325*0Sstevel@tonic-gate gettext("from accept system call")); 326*0Sstevel@tonic-gate continue; 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate if (debug && (iproprole != IPROP_SLAVE)) 330*0Sstevel@tonic-gate child_pid = 0; 331*0Sstevel@tonic-gate else 332*0Sstevel@tonic-gate child_pid = fork(); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate switch (child_pid) { 335*0Sstevel@tonic-gate case -1: 336*0Sstevel@tonic-gate com_err(progname, errno, gettext("while forking")); 337*0Sstevel@tonic-gate exit(1); 338*0Sstevel@tonic-gate /*NOTREACHED*/ 339*0Sstevel@tonic-gate case 0: 340*0Sstevel@tonic-gate /* child */ 341*0Sstevel@tonic-gate (void) close(finet); 342*0Sstevel@tonic-gate doit(s); 343*0Sstevel@tonic-gate close(s); 344*0Sstevel@tonic-gate _exit(0); 345*0Sstevel@tonic-gate /*NOTREACHED*/ 346*0Sstevel@tonic-gate default: 347*0Sstevel@tonic-gate /* parent */ 348*0Sstevel@tonic-gate if (wait(&status) < 0) { 349*0Sstevel@tonic-gate com_err(progname, errno, 350*0Sstevel@tonic-gate gettext("while waiting to receive database")); 351*0Sstevel@tonic-gate exit(1); 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate close(s); 355*0Sstevel@tonic-gate if (iproprole == IPROP_SLAVE) 356*0Sstevel@tonic-gate close(finet); 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if ((ret = WEXITSTATUS(status)) != 0) 359*0Sstevel@tonic-gate return (ret); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate if (iproprole == IPROP_SLAVE) 363*0Sstevel@tonic-gate break; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate return (0); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate void doit(fd) 370*0Sstevel@tonic-gate int fd; 371*0Sstevel@tonic-gate { 372*0Sstevel@tonic-gate struct sockaddr_storage from; 373*0Sstevel@tonic-gate socklen_t fromlen; 374*0Sstevel@tonic-gate int on = 1; 375*0Sstevel@tonic-gate struct hostent *hp; 376*0Sstevel@tonic-gate krb5_error_code retval; 377*0Sstevel@tonic-gate krb5_data confmsg; 378*0Sstevel@tonic-gate int lock_fd; 379*0Sstevel@tonic-gate int omask; 380*0Sstevel@tonic-gate krb5_enctype etype; 381*0Sstevel@tonic-gate char ntop[NI_MAXHOST] = ""; 382*0Sstevel@tonic-gate krb5_context doit_context; 383*0Sstevel@tonic-gate kdb_log_context *log_ctx; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate retval = krb5_init_context(&doit_context); 386*0Sstevel@tonic-gate if (retval) { 387*0Sstevel@tonic-gate com_err(progname, retval, gettext("while initializing krb5")); 388*0Sstevel@tonic-gate exit(1); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate log_ctx = kpropd_context->kdblog_context; 391*0Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) 392*0Sstevel@tonic-gate ulog_set_role(doit_context, IPROP_SLAVE); 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate fromlen = (socklen_t)sizeof (from); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) { 397*0Sstevel@tonic-gate fprintf(stderr, "%s: ", progname); 398*0Sstevel@tonic-gate perror(gettext("getpeername")); 399*0Sstevel@tonic-gate exit(1); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on, 402*0Sstevel@tonic-gate sizeof (on)) < 0) { 403*0Sstevel@tonic-gate com_err(progname, errno, 404*0Sstevel@tonic-gate gettext("while attempting setsockopt (SO_KEEPALIVE)")); 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 408*0Sstevel@tonic-gate NULL, 0, NI_NUMERICHOST) != 0) { 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate /* getnameifo failed so use inet_ntop() to get printable addresses */ 411*0Sstevel@tonic-gate if (from.ss_family == AF_INET) { 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate inet_ntop(AF_INET, 414*0Sstevel@tonic-gate (const void *)&ss2sin(&from)->sin_addr, 415*0Sstevel@tonic-gate ntop, sizeof(ntop)); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate } else if (from.ss_family == AF_INET6 && 418*0Sstevel@tonic-gate ! IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) { 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate ipaddr_t v4addr; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate inet_ntop(AF_INET6, 423*0Sstevel@tonic-gate (const void *)&ss2sin6(&from)->sin6_addr, ntop, 424*0Sstevel@tonic-gate sizeof(ntop)); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate /* ipv4 mapped ipv6 addrs handled later */ 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate if (from.ss_family == AF_INET || from.ss_family == AF_INET6) { 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate if (from.ss_family == AF_INET6 && 432*0Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) { 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate ipaddr_t v4addr; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* coerce ipv4 mapped ipv6 addr to normal ipv4 addr */ 437*0Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&(ss2sin6(&from)->sin6_addr), 438*0Sstevel@tonic-gate v4addr); 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate inet_ntop(AF_INET, (const void *) &v4addr, 441*0Sstevel@tonic-gate ntop, sizeof(ntop)); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate syslog(LOG_INFO, gettext("Connection from %s"), ntop); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate if (debug) 447*0Sstevel@tonic-gate printf("Connection from %s\n", ntop); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate } else { 450*0Sstevel@tonic-gate /* address family isn't either AF_INET || AF_INET6 */ 451*0Sstevel@tonic-gate syslog(LOG_INFO, 452*0Sstevel@tonic-gate gettext("Connection from unknown address family:%d"), 453*0Sstevel@tonic-gate from.ss_family); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate if (debug) { 456*0Sstevel@tonic-gate printf(gettext("Connection from unknown address family:%d"), 457*0Sstevel@tonic-gate from.ss_family); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * Now do the authentication 463*0Sstevel@tonic-gate */ 464*0Sstevel@tonic-gate kerberos_authenticate(doit_context, fd, &client, &etype, from); 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if (!authorized_principal(doit_context, client, etype)) { 467*0Sstevel@tonic-gate char *name; 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate if (retval = krb5_unparse_name(doit_context, client, &name)) { 470*0Sstevel@tonic-gate com_err(progname, retval, 471*0Sstevel@tonic-gate gettext("While unparsing client name")); 472*0Sstevel@tonic-gate exit(1); 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate syslog(LOG_WARNING, 475*0Sstevel@tonic-gate gettext("Rejected connection from unauthorized principal %s"), 476*0Sstevel@tonic-gate name); 477*0Sstevel@tonic-gate free(name); 478*0Sstevel@tonic-gate exit(1); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate omask = umask(077); 481*0Sstevel@tonic-gate lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600); 482*0Sstevel@tonic-gate (void) umask(omask); 483*0Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd, 484*0Sstevel@tonic-gate KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK); 485*0Sstevel@tonic-gate if (retval) { 486*0Sstevel@tonic-gate com_err(progname, retval, 487*0Sstevel@tonic-gate gettext("while trying to lock '%s'"), 488*0Sstevel@tonic-gate temp_file_name); 489*0Sstevel@tonic-gate exit(1); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate if ((database_fd = open(temp_file_name, 492*0Sstevel@tonic-gate O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) { 493*0Sstevel@tonic-gate com_err(progname, errno, 494*0Sstevel@tonic-gate gettext("while opening database file, '%s'"), 495*0Sstevel@tonic-gate temp_file_name); 496*0Sstevel@tonic-gate exit(1); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate recv_database(doit_context, fd, database_fd, &confmsg); 499*0Sstevel@tonic-gate if (rename(temp_file_name, file)) { 500*0Sstevel@tonic-gate com_err(progname, errno, 501*0Sstevel@tonic-gate gettext("While renaming %s to %s"), 502*0Sstevel@tonic-gate temp_file_name, file); 503*0Sstevel@tonic-gate exit(1); 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_SHARED); 506*0Sstevel@tonic-gate if (retval) { 507*0Sstevel@tonic-gate com_err(progname, retval, 508*0Sstevel@tonic-gate gettext("while downgrading lock on '%s'"), 509*0Sstevel@tonic-gate temp_file_name); 510*0Sstevel@tonic-gate exit(1); 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate load_database(doit_context, kdb5_util, file); 513*0Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_UNLOCK); 514*0Sstevel@tonic-gate if (retval) { 515*0Sstevel@tonic-gate com_err(progname, retval, 516*0Sstevel@tonic-gate gettext("while unlocking '%s'"), temp_file_name); 517*0Sstevel@tonic-gate exit(1); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate (void)close(lock_fd); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* 522*0Sstevel@tonic-gate * Send the acknowledgement message generated in 523*0Sstevel@tonic-gate * recv_database, then close the socket. 524*0Sstevel@tonic-gate */ 525*0Sstevel@tonic-gate if (retval = krb5_write_message(doit_context, (void *) &fd, 526*0Sstevel@tonic-gate &confmsg)) { 527*0Sstevel@tonic-gate krb5_free_data_contents(doit_context, &confmsg); 528*0Sstevel@tonic-gate com_err(progname, retval, 529*0Sstevel@tonic-gate gettext("while sending # of received bytes")); 530*0Sstevel@tonic-gate exit(1); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate krb5_free_data_contents(doit_context, &confmsg); 533*0Sstevel@tonic-gate if (close(fd) < 0) { 534*0Sstevel@tonic-gate com_err(progname, errno, 535*0Sstevel@tonic-gate gettext("while trying to close database file")); 536*0Sstevel@tonic-gate exit(1); 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate exit(0); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * Routine to handle incremental update transfer(s) from master KDC 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx) { 547*0Sstevel@tonic-gate CLIENT *cl; 548*0Sstevel@tonic-gate kadm5_ret_t retval; 549*0Sstevel@tonic-gate kadm5_config_params params; 550*0Sstevel@tonic-gate krb5_ccache cc; 551*0Sstevel@tonic-gate krb5_principal iprop_svc_principal; 552*0Sstevel@tonic-gate void *server_handle = NULL; 553*0Sstevel@tonic-gate char *iprop_svc_princstr = NULL; 554*0Sstevel@tonic-gate char *master_svc_princstr = NULL; 555*0Sstevel@tonic-gate char *admin_server = NULL; 556*0Sstevel@tonic-gate char *keytab_name = NULL; 557*0Sstevel@tonic-gate unsigned int pollin, backoff_time; 558*0Sstevel@tonic-gate int backoff_cnt = 0; 559*0Sstevel@tonic-gate int reinit_cnt = 0; 560*0Sstevel@tonic-gate int ret; 561*0Sstevel@tonic-gate boolean_t frdone = B_FALSE; 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate kdb_incr_result_t *incr_ret; 564*0Sstevel@tonic-gate static kdb_last_t mylast; 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate kdb_fullresync_result_t *full_ret; 567*0Sstevel@tonic-gate char *full_resync_arg = NULL; 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate kadm5_iprop_handle_t handle; 570*0Sstevel@tonic-gate kdb_hlog_t *ulog; 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate if (!debug) 573*0Sstevel@tonic-gate daemon(0, 0); 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate pollin = (unsigned int)0; 576*0Sstevel@tonic-gate (void) memset((char *)¶ms, 0, sizeof (params)); 577*0Sstevel@tonic-gate ulog = log_ctx->ulog; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM; 580*0Sstevel@tonic-gate params.realm = def_realm; 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if (master_svc_princstr == NULL) { 583*0Sstevel@tonic-gate if (retval = kadm5_get_kiprop_host_srv_name(kpropd_context, 584*0Sstevel@tonic-gate def_realm, &master_svc_princstr)) { 585*0Sstevel@tonic-gate com_err(progname, retval, 586*0Sstevel@tonic-gate gettext("%s: unable to get kiprop host based " 587*0Sstevel@tonic-gate "service name for realm %s\n"), 588*0Sstevel@tonic-gate progname, def_realm); 589*0Sstevel@tonic-gate exit(1); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate /* 594*0Sstevel@tonic-gate * Set cc to the default credentials cache 595*0Sstevel@tonic-gate */ 596*0Sstevel@tonic-gate if (retval = krb5_cc_default(kpropd_context, &cc)) { 597*0Sstevel@tonic-gate com_err(progname, retval, 598*0Sstevel@tonic-gate gettext("while opening default " 599*0Sstevel@tonic-gate "credentials cache")); 600*0Sstevel@tonic-gate exit(1); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME, 604*0Sstevel@tonic-gate KRB5_NT_SRV_HST, &iprop_svc_principal); 605*0Sstevel@tonic-gate if (retval) { 606*0Sstevel@tonic-gate com_err(progname, retval, gettext("while trying to construct " 607*0Sstevel@tonic-gate "host service principal")); 608*0Sstevel@tonic-gate exit(1); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate if (retval = krb5_unparse_name(kpropd_context, iprop_svc_principal, 612*0Sstevel@tonic-gate &iprop_svc_princstr)) { 613*0Sstevel@tonic-gate com_err(progname, retval, 614*0Sstevel@tonic-gate gettext("while canonicalizing " 615*0Sstevel@tonic-gate "principal name")); 616*0Sstevel@tonic-gate krb5_free_principal(kpropd_context, iprop_svc_principal); 617*0Sstevel@tonic-gate exit(1); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate krb5_free_principal(kpropd_context, iprop_svc_principal); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate reinit: 622*0Sstevel@tonic-gate /* 623*0Sstevel@tonic-gate * Authentication, initialize rpcsec_gss handle etc. 624*0Sstevel@tonic-gate */ 625*0Sstevel@tonic-gate retval = kadm5_init_with_skey(iprop_svc_princstr, keytab_name, 626*0Sstevel@tonic-gate master_svc_princstr, 627*0Sstevel@tonic-gate ¶ms, 628*0Sstevel@tonic-gate KADM5_STRUCT_VERSION, 629*0Sstevel@tonic-gate KADM5_API_VERSION_2, 630*0Sstevel@tonic-gate &server_handle); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate if (retval) { 633*0Sstevel@tonic-gate if (retval == KADM5_RPC_ERROR) { 634*0Sstevel@tonic-gate reinit_cnt++; 635*0Sstevel@tonic-gate if (server_handle) 636*0Sstevel@tonic-gate kadm5_destroy((void *) server_handle); 637*0Sstevel@tonic-gate server_handle = (void *)NULL; 638*0Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate com_err(progname, retval, gettext( 641*0Sstevel@tonic-gate "while attempting to connect" 642*0Sstevel@tonic-gate " to master KDC ... retrying")); 643*0Sstevel@tonic-gate backoff_time = backoff_from_master(&reinit_cnt); 644*0Sstevel@tonic-gate (void) sleep(backoff_time); 645*0Sstevel@tonic-gate goto reinit; 646*0Sstevel@tonic-gate } else { 647*0Sstevel@tonic-gate com_err(progname, retval, 648*0Sstevel@tonic-gate gettext("while initializing %s interface"), 649*0Sstevel@tonic-gate progname); 650*0Sstevel@tonic-gate if (retval == KADM5_BAD_CLIENT_PARAMS || 651*0Sstevel@tonic-gate retval == KADM5_BAD_SERVER_PARAMS) 652*0Sstevel@tonic-gate usage(); 653*0Sstevel@tonic-gate exit(1); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate } 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Reset re-initialization count to zero now. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate reinit_cnt = backoff_time = 0; 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate /* 663*0Sstevel@tonic-gate * Reset the handle to the correct type for the RPC call 664*0Sstevel@tonic-gate */ 665*0Sstevel@tonic-gate handle = server_handle; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* 668*0Sstevel@tonic-gate * If we have reached this far, we have succesfully established 669*0Sstevel@tonic-gate * a RPCSEC_GSS connection; we now start polling for updates 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate if (poll_time == NULL) { 672*0Sstevel@tonic-gate if ((poll_time = (char *)strdup("2m")) == NULL) { 673*0Sstevel@tonic-gate com_err(progname, ENOMEM, 674*0Sstevel@tonic-gate gettext("Unable to allocate poll_time")); 675*0Sstevel@tonic-gate exit(1); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate if (pollin == (unsigned int)0) 680*0Sstevel@tonic-gate pollin = convert_polltime(poll_time); 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate for (;;) { 683*0Sstevel@tonic-gate incr_ret = NULL; 684*0Sstevel@tonic-gate full_ret = NULL; 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * Get the most recent ulog entry sno + ts, which 688*0Sstevel@tonic-gate * we package in the request to the master KDC 689*0Sstevel@tonic-gate */ 690*0Sstevel@tonic-gate mylast.last_sno = ulog->kdb_last_sno; 691*0Sstevel@tonic-gate mylast.last_time = ulog->kdb_last_time; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate /* 694*0Sstevel@tonic-gate * Loop continuously on an iprop_get_updates_1(), 695*0Sstevel@tonic-gate * so that we can keep probing the master for updates 696*0Sstevel@tonic-gate * or (if needed) do a full resync of the krb5 db. 697*0Sstevel@tonic-gate */ 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate incr_ret = iprop_get_updates_1(&mylast, handle->clnt); 700*0Sstevel@tonic-gate if (incr_ret == (kdb_incr_result_t *)NULL) { 701*0Sstevel@tonic-gate clnt_perror(handle->clnt, 702*0Sstevel@tonic-gate "iprop_get_updates call failed"); 703*0Sstevel@tonic-gate if (server_handle) 704*0Sstevel@tonic-gate kadm5_destroy((void *)server_handle); 705*0Sstevel@tonic-gate server_handle = (void *)NULL; 706*0Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL; 707*0Sstevel@tonic-gate goto reinit; 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate switch (incr_ret->ret) { 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate case UPDATE_FULL_RESYNC_NEEDED: 713*0Sstevel@tonic-gate /* 714*0Sstevel@tonic-gate * We dont do a full resync again, if the last 715*0Sstevel@tonic-gate * X'fer was a resync and if the master sno is 716*0Sstevel@tonic-gate * still "0", i.e. no updates so far. 717*0Sstevel@tonic-gate */ 718*0Sstevel@tonic-gate if ((frdone == B_TRUE) && (incr_ret->lastentry.last_sno 719*0Sstevel@tonic-gate == 0)) { 720*0Sstevel@tonic-gate break; 721*0Sstevel@tonic-gate } else { 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate full_ret = iprop_full_resync_1((void *) 724*0Sstevel@tonic-gate &full_resync_arg, handle->clnt); 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate if (full_ret == (kdb_fullresync_result_t *) 727*0Sstevel@tonic-gate NULL) { 728*0Sstevel@tonic-gate clnt_perror(handle->clnt, 729*0Sstevel@tonic-gate "iprop_full_resync call failed"); 730*0Sstevel@tonic-gate if (server_handle) 731*0Sstevel@tonic-gate kadm5_destroy((void *) 732*0Sstevel@tonic-gate server_handle); 733*0Sstevel@tonic-gate server_handle = (void *)NULL; 734*0Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL; 735*0Sstevel@tonic-gate goto reinit; 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate switch (full_ret->ret) { 740*0Sstevel@tonic-gate case UPDATE_OK: 741*0Sstevel@tonic-gate backoff_cnt = 0; 742*0Sstevel@tonic-gate /* 743*0Sstevel@tonic-gate * We now listen on the kprop port for 744*0Sstevel@tonic-gate * the full dump 745*0Sstevel@tonic-gate */ 746*0Sstevel@tonic-gate ret = do_standalone(log_ctx->iproprole); 747*0Sstevel@tonic-gate if (ret) 748*0Sstevel@tonic-gate syslog(LOG_WARNING, 749*0Sstevel@tonic-gate gettext("kpropd: Full resync, " 750*0Sstevel@tonic-gate "invalid return.")); 751*0Sstevel@tonic-gate if (debug) 752*0Sstevel@tonic-gate if (ret) 753*0Sstevel@tonic-gate fprintf(stderr, 754*0Sstevel@tonic-gate gettext("Full resync " 755*0Sstevel@tonic-gate "was unsuccessful\n")); 756*0Sstevel@tonic-gate else 757*0Sstevel@tonic-gate fprintf(stderr, 758*0Sstevel@tonic-gate gettext("Full resync " 759*0Sstevel@tonic-gate "was successful\n")); 760*0Sstevel@tonic-gate frdone = B_TRUE; 761*0Sstevel@tonic-gate break; 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate case UPDATE_BUSY: 764*0Sstevel@tonic-gate /* 765*0Sstevel@tonic-gate * Exponential backoff 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate backoff_cnt++; 768*0Sstevel@tonic-gate break; 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate case UPDATE_FULL_RESYNC_NEEDED: 771*0Sstevel@tonic-gate case UPDATE_NIL: 772*0Sstevel@tonic-gate default: 773*0Sstevel@tonic-gate backoff_cnt = 0; 774*0Sstevel@tonic-gate frdone = B_FALSE; 775*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync," 776*0Sstevel@tonic-gate " invalid return from master KDC.")); 777*0Sstevel@tonic-gate break; 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate case UPDATE_PERM_DENIED: 780*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync," 781*0Sstevel@tonic-gate " permission denied.")); 782*0Sstevel@tonic-gate goto error; 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate case UPDATE_ERROR: 785*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync," 786*0Sstevel@tonic-gate " error returned from master KDC.")); 787*0Sstevel@tonic-gate goto error; 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate break; 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate case UPDATE_OK: 792*0Sstevel@tonic-gate backoff_cnt = 0; 793*0Sstevel@tonic-gate frdone = B_FALSE; 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate /* 796*0Sstevel@tonic-gate * ulog_replay() will convert the ulog updates to db 797*0Sstevel@tonic-gate * entries using the kdb conv api and will commit 798*0Sstevel@tonic-gate * the entries to the slave kdc database 799*0Sstevel@tonic-gate */ 800*0Sstevel@tonic-gate retval = ulog_replay(kpropd_context, incr_ret); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate if (retval) { 803*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: ulog_replay" 804*0Sstevel@tonic-gate " failed, updates not registered.")); 805*0Sstevel@tonic-gate break; 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate if (debug) 809*0Sstevel@tonic-gate fprintf(stderr, gettext("Update transfer " 810*0Sstevel@tonic-gate "from master was OK\n")); 811*0Sstevel@tonic-gate break; 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate case UPDATE_PERM_DENIED: 814*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates," 815*0Sstevel@tonic-gate " permission denied.")); 816*0Sstevel@tonic-gate goto error; 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate case UPDATE_ERROR: 819*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates, error " 820*0Sstevel@tonic-gate "returned from master KDC.")); 821*0Sstevel@tonic-gate goto error; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate case UPDATE_BUSY: 824*0Sstevel@tonic-gate /* 825*0Sstevel@tonic-gate * Exponential backoff 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate backoff_cnt++; 828*0Sstevel@tonic-gate break; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate case UPDATE_NIL: 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * Master-slave are in sync 833*0Sstevel@tonic-gate */ 834*0Sstevel@tonic-gate if (debug) 835*0Sstevel@tonic-gate fprintf(stderr, gettext("Master, slave KDC's " 836*0Sstevel@tonic-gate "are in-sync, no updates\n")); 837*0Sstevel@tonic-gate backoff_cnt = 0; 838*0Sstevel@tonic-gate frdone = B_FALSE; 839*0Sstevel@tonic-gate break; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate default: 842*0Sstevel@tonic-gate backoff_cnt = 0; 843*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates," 844*0Sstevel@tonic-gate " invalid return from master KDC.")); 845*0Sstevel@tonic-gate break; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate if (runonce == B_TRUE) 849*0Sstevel@tonic-gate goto done; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate /* 852*0Sstevel@tonic-gate * Sleep for the specified poll interval (Default is 2 mts), 853*0Sstevel@tonic-gate * or do a binary exponential backoff if we get an 854*0Sstevel@tonic-gate * UPDATE_BUSY signal 855*0Sstevel@tonic-gate */ 856*0Sstevel@tonic-gate if (backoff_cnt > 0) { 857*0Sstevel@tonic-gate backoff_time = backoff_from_master(&backoff_cnt); 858*0Sstevel@tonic-gate if (debug) 859*0Sstevel@tonic-gate fprintf(stderr, gettext("Busy signal received " 860*0Sstevel@tonic-gate "from master, backoff for %d secs\n"), 861*0Sstevel@tonic-gate backoff_time); 862*0Sstevel@tonic-gate (void) sleep(backoff_time); 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate else 865*0Sstevel@tonic-gate (void) sleep(pollin); 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate error: 871*0Sstevel@tonic-gate if (debug) 872*0Sstevel@tonic-gate fprintf(stderr, gettext("ERROR returned by master, bailing\n")); 873*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: ERROR returned by master KDC," 874*0Sstevel@tonic-gate " bailing.\n")); 875*0Sstevel@tonic-gate done: 876*0Sstevel@tonic-gate if (poll_time) 877*0Sstevel@tonic-gate free(poll_time); 878*0Sstevel@tonic-gate if(iprop_svc_princstr) 879*0Sstevel@tonic-gate free(iprop_svc_princstr); 880*0Sstevel@tonic-gate if (master_svc_princstr) 881*0Sstevel@tonic-gate free(master_svc_princstr); 882*0Sstevel@tonic-gate if (retval = krb5_cc_close(kpropd_context, cc)) { 883*0Sstevel@tonic-gate com_err(progname, retval, 884*0Sstevel@tonic-gate gettext("while closing default ccache")); 885*0Sstevel@tonic-gate exit(1); 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate if (def_realm) 888*0Sstevel@tonic-gate free(def_realm); 889*0Sstevel@tonic-gate if (server_handle) 890*0Sstevel@tonic-gate kadm5_destroy((void *)server_handle); 891*0Sstevel@tonic-gate if (kpropd_context) 892*0Sstevel@tonic-gate krb5_free_context(kpropd_context); 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate if (runonce == B_TRUE) 895*0Sstevel@tonic-gate return (0); 896*0Sstevel@tonic-gate else 897*0Sstevel@tonic-gate exit(1); 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate /* 902*0Sstevel@tonic-gate * Do exponential backoff, since master KDC is BUSY or down 903*0Sstevel@tonic-gate */ 904*0Sstevel@tonic-gate unsigned int backoff_from_master(int *cnt) { 905*0Sstevel@tonic-gate unsigned int btime; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate btime = (unsigned int)(2<<(*cnt)); 908*0Sstevel@tonic-gate if (btime > MAX_BACKOFF) { 909*0Sstevel@tonic-gate btime = MAX_BACKOFF; 910*0Sstevel@tonic-gate *cnt--; 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate return (btime); 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate /* 918*0Sstevel@tonic-gate * Routine to convert the `pollstr' string to seconds 919*0Sstevel@tonic-gate */ 920*0Sstevel@tonic-gate int convert_polltime(char *pollstr) { 921*0Sstevel@tonic-gate char *tokenptr = NULL; 922*0Sstevel@tonic-gate int len, polltime; 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate len = polltime = 0; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate if ((len = strcspn(pollstr, "s")) < strlen(pollstr)) { 927*0Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char)); 928*0Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1); 929*0Sstevel@tonic-gate polltime = atoi(tokenptr); 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate if ((len = strcspn(pollstr, "m")) < strlen(pollstr)) { 933*0Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char)); 934*0Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1); 935*0Sstevel@tonic-gate polltime = atoi(tokenptr) * 60; 936*0Sstevel@tonic-gate } 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate if ((len = strcspn(pollstr, "h")) < strlen(pollstr)) { 939*0Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char)); 940*0Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1); 941*0Sstevel@tonic-gate polltime = atoi(tokenptr) * 3600; 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate if (tokenptr != NULL) 945*0Sstevel@tonic-gate free(tokenptr); 946*0Sstevel@tonic-gate /* 947*0Sstevel@tonic-gate * If we have a bogus pollstr value, set polltime to the 948*0Sstevel@tonic-gate * default of 2 mts (120 seconds). 949*0Sstevel@tonic-gate */ 950*0Sstevel@tonic-gate if (polltime == 0) 951*0Sstevel@tonic-gate polltime = 120; 952*0Sstevel@tonic-gate return (polltime); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate static void 956*0Sstevel@tonic-gate kpropd_com_err_proc(whoami, code, fmt, args) 957*0Sstevel@tonic-gate const char *whoami; 958*0Sstevel@tonic-gate long code; 959*0Sstevel@tonic-gate const char *fmt; 960*0Sstevel@tonic-gate va_list args; 961*0Sstevel@tonic-gate { 962*0Sstevel@tonic-gate char error_buf[8096]; 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate error_buf[0] = '\0'; 965*0Sstevel@tonic-gate if (fmt) 966*0Sstevel@tonic-gate vsprintf(error_buf, fmt, args); 967*0Sstevel@tonic-gate syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "", 968*0Sstevel@tonic-gate code ? error_message(code) : "", code ? " " : "", error_buf); 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate void PRS(argc,argv) 972*0Sstevel@tonic-gate int argc; 973*0Sstevel@tonic-gate char **argv; 974*0Sstevel@tonic-gate { 975*0Sstevel@tonic-gate register char *word, ch; 976*0Sstevel@tonic-gate char *cp; 977*0Sstevel@tonic-gate int c; 978*0Sstevel@tonic-gate struct hostent *hp; 979*0Sstevel@tonic-gate char my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ]; 980*0Sstevel@tonic-gate krb5_error_code retval; 981*0Sstevel@tonic-gate static const char tmp[] = ".temp"; 982*0Sstevel@tonic-gate kadm5_config_params params; 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 987*0Sstevel@tonic-gate #define TEXT_DOMAIN "KPROPD_TEST" /* Use this only if it weren't */ 988*0Sstevel@tonic-gate #endif 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate (void) memset((char *) ¶ms, 0, sizeof (params)); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate retval = krb5_init_context(&kpropd_context); 995*0Sstevel@tonic-gate if (retval) { 996*0Sstevel@tonic-gate com_err(argv[0], retval, 997*0Sstevel@tonic-gate gettext("while initializing krb5")); 998*0Sstevel@tonic-gate exit(1); 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate progname = argv[0]; 1001*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "dtf:F:p:P:r:s:Sa:")) != EOF){ 1002*0Sstevel@tonic-gate switch (c) { 1003*0Sstevel@tonic-gate case 'd': 1004*0Sstevel@tonic-gate debug++; 1005*0Sstevel@tonic-gate break; 1006*0Sstevel@tonic-gate case 't': 1007*0Sstevel@tonic-gate /* 1008*0Sstevel@tonic-gate * Undocumented option - for testing only. 1009*0Sstevel@tonic-gate * 1010*0Sstevel@tonic-gate * Option to run the kpropd server exactly 1011*0Sstevel@tonic-gate * once (this is true only if iprop is enabled). 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate runonce = B_TRUE; 1014*0Sstevel@tonic-gate break; 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate case 'f': 1017*0Sstevel@tonic-gate file = optarg; 1018*0Sstevel@tonic-gate if (!file) 1019*0Sstevel@tonic-gate usage(); 1020*0Sstevel@tonic-gate break; 1021*0Sstevel@tonic-gate case 'F': 1022*0Sstevel@tonic-gate kerb_database = optarg; 1023*0Sstevel@tonic-gate if (!kerb_database) 1024*0Sstevel@tonic-gate usage(); 1025*0Sstevel@tonic-gate break; 1026*0Sstevel@tonic-gate case 'p': 1027*0Sstevel@tonic-gate kdb5_util = optarg; 1028*0Sstevel@tonic-gate if (!kdb5_util) 1029*0Sstevel@tonic-gate usage(); 1030*0Sstevel@tonic-gate break; 1031*0Sstevel@tonic-gate case 'P': 1032*0Sstevel@tonic-gate port = htons(atoi(optarg)); 1033*0Sstevel@tonic-gate if (!port) 1034*0Sstevel@tonic-gate usage(); 1035*0Sstevel@tonic-gate break; 1036*0Sstevel@tonic-gate case 'r': 1037*0Sstevel@tonic-gate realm = optarg; 1038*0Sstevel@tonic-gate if (!realm) 1039*0Sstevel@tonic-gate usage(); 1040*0Sstevel@tonic-gate params.realm = realm; 1041*0Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM; 1042*0Sstevel@tonic-gate break; 1043*0Sstevel@tonic-gate case 's': 1044*0Sstevel@tonic-gate srvtab = optarg; 1045*0Sstevel@tonic-gate if (!srvtab) 1046*0Sstevel@tonic-gate usage(); 1047*0Sstevel@tonic-gate break; 1048*0Sstevel@tonic-gate case 'S': 1049*0Sstevel@tonic-gate standalone++; 1050*0Sstevel@tonic-gate break; 1051*0Sstevel@tonic-gate case 'a': 1052*0Sstevel@tonic-gate acl_file_name = optarg; 1053*0Sstevel@tonic-gate if (!acl_file_name) 1054*0Sstevel@tonic-gate usage(); 1055*0Sstevel@tonic-gate break; 1056*0Sstevel@tonic-gate case '?': 1057*0Sstevel@tonic-gate default: 1058*0Sstevel@tonic-gate usage(); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate /* 1063*0Sstevel@tonic-gate * If not in debug mode, switch com_err reporting to syslog 1064*0Sstevel@tonic-gate */ 1065*0Sstevel@tonic-gate if (! debug) { 1066*0Sstevel@tonic-gate openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS); 1067*0Sstevel@tonic-gate set_com_err_hook(kpropd_com_err_proc); 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate /* 1070*0Sstevel@tonic-gate * Get my hostname, so we can construct my service name 1071*0Sstevel@tonic-gate */ 1072*0Sstevel@tonic-gate retval = krb5_sname_to_principal(kpropd_context, 1073*0Sstevel@tonic-gate NULL, KPROP_SERVICE_NAME, 1074*0Sstevel@tonic-gate KRB5_NT_SRV_HST, &server); 1075*0Sstevel@tonic-gate if (retval) { 1076*0Sstevel@tonic-gate com_err(progname, retval, 1077*0Sstevel@tonic-gate gettext("While trying to construct my service name")); 1078*0Sstevel@tonic-gate exit(1); 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate if (realm) { 1081*0Sstevel@tonic-gate (void) krb5_xfree(krb5_princ_realm(context, server)->data); 1082*0Sstevel@tonic-gate krb5_princ_set_realm_length(context, server, strlen(realm)); 1083*0Sstevel@tonic-gate krb5_princ_set_realm_data(context, server, strdup(realm)); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate /* 1086*0Sstevel@tonic-gate * Construct the name of the temporary file. 1087*0Sstevel@tonic-gate */ 1088*0Sstevel@tonic-gate if ((temp_file_name = (char *) malloc(strlen(file) + 1089*0Sstevel@tonic-gate strlen(tmp) + 1)) == NULL) { 1090*0Sstevel@tonic-gate com_err(progname, ENOMEM, 1091*0Sstevel@tonic-gate gettext("while allocating filename for temp file")); 1092*0Sstevel@tonic-gate exit(1); 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate strcpy(temp_file_name, file); 1095*0Sstevel@tonic-gate strcat(temp_file_name, tmp); 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate retval = kadm5_get_config_params(kpropd_context, NULL, NULL, ¶ms, 1098*0Sstevel@tonic-gate ¶ms); 1099*0Sstevel@tonic-gate if (retval) { 1100*0Sstevel@tonic-gate com_err(progname, retval, gettext("while initializing")); 1101*0Sstevel@tonic-gate exit(1); 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate if (params.iprop_enabled == TRUE) { 1104*0Sstevel@tonic-gate ulog_set_role(kpropd_context, IPROP_SLAVE); 1105*0Sstevel@tonic-gate poll_time = params.iprop_polltime; 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate if (ulog_map(kpropd_context, ¶ms, FKPROPD)) { 1108*0Sstevel@tonic-gate com_err(progname, errno, 1109*0Sstevel@tonic-gate gettext("Unable to map log!\n")); 1110*0Sstevel@tonic-gate exit(1); 1111*0Sstevel@tonic-gate } 1112*0Sstevel@tonic-gate } 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate /* 1115*0Sstevel@tonic-gate * Grab the realm info and check if iprop is enabled. 1116*0Sstevel@tonic-gate */ 1117*0Sstevel@tonic-gate if (def_realm == NULL) { 1118*0Sstevel@tonic-gate retval = krb5_get_default_realm(kpropd_context, &def_realm); 1119*0Sstevel@tonic-gate if (retval) { 1120*0Sstevel@tonic-gate com_err(progname, retval, 1121*0Sstevel@tonic-gate gettext("Unable to get default realm")); 1122*0Sstevel@tonic-gate exit(1); 1123*0Sstevel@tonic-gate } 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate } 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate /* 1128*0Sstevel@tonic-gate * Figure out who's calling on the other end of the connection.... 1129*0Sstevel@tonic-gate */ 1130*0Sstevel@tonic-gate void 1131*0Sstevel@tonic-gate kerberos_authenticate(context, fd, clientp, etype, ss) 1132*0Sstevel@tonic-gate krb5_context context; 1133*0Sstevel@tonic-gate int fd; 1134*0Sstevel@tonic-gate krb5_principal * clientp; 1135*0Sstevel@tonic-gate krb5_enctype * etype; 1136*0Sstevel@tonic-gate struct sockaddr_storage ss; 1137*0Sstevel@tonic-gate { 1138*0Sstevel@tonic-gate krb5_error_code retval; 1139*0Sstevel@tonic-gate krb5_ticket * ticket; 1140*0Sstevel@tonic-gate struct sockaddr_storage r_ss; 1141*0Sstevel@tonic-gate int ss_length; 1142*0Sstevel@tonic-gate krb5_keytab keytab = NULL; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate /* 1145*0Sstevel@tonic-gate * Set recv_addr and send_addr 1146*0Sstevel@tonic-gate */ 1147*0Sstevel@tonic-gate if (cvtkaddr(&ss, &sender_addr) == NULL) { 1148*0Sstevel@tonic-gate com_err(progname, errno, 1149*0Sstevel@tonic-gate gettext("while converting socket address")); 1150*0Sstevel@tonic-gate exit(1); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate ss_length = sizeof (r_ss); 1154*0Sstevel@tonic-gate if (getsockname(fd, (struct sockaddr *) &r_ss, &ss_length)) { 1155*0Sstevel@tonic-gate com_err(progname, errno, 1156*0Sstevel@tonic-gate gettext("while getting local socket address")); 1157*0Sstevel@tonic-gate exit(1); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate if (cvtkaddr(&r_ss, &receiver_addr) == NULL) { 1161*0Sstevel@tonic-gate com_err(progname, errno, 1162*0Sstevel@tonic-gate gettext("while converting socket address")); 1163*0Sstevel@tonic-gate exit(1); 1164*0Sstevel@tonic-gate } 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate if (debug) { 1167*0Sstevel@tonic-gate char *name; 1168*0Sstevel@tonic-gate if (retval = krb5_unparse_name(context, server, &name)) { 1169*0Sstevel@tonic-gate com_err(progname, retval, gettext("While unparsing server name")); 1170*0Sstevel@tonic-gate exit(1); 1171*0Sstevel@tonic-gate } 1172*0Sstevel@tonic-gate printf(gettext("krb5_recvauth(%d, %s, %s, ...)\n"), fd, kprop_version, 1173*0Sstevel@tonic-gate name); 1174*0Sstevel@tonic-gate free(name); 1175*0Sstevel@tonic-gate } 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate if (retval = krb5_auth_con_init(context, &auth_context)) { 1178*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_init: %s"), 1179*0Sstevel@tonic-gate error_message(retval)); 1180*0Sstevel@tonic-gate exit(1); 1181*0Sstevel@tonic-gate } 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate if (retval = krb5_auth_con_setflags(context, auth_context, 1184*0Sstevel@tonic-gate KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { 1185*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_setflags: %s"), 1186*0Sstevel@tonic-gate error_message(retval)); 1187*0Sstevel@tonic-gate exit(1); 1188*0Sstevel@tonic-gate } 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate if (retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr, 1191*0Sstevel@tonic-gate &sender_addr)) { 1192*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_setaddrs: %s"), 1193*0Sstevel@tonic-gate error_message(retval)); 1194*0Sstevel@tonic-gate exit(1); 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate if (srvtab) { 1198*0Sstevel@tonic-gate if (retval = krb5_kt_resolve(context, srvtab, &keytab)) { 1199*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_kt_resolve: %s"), error_message(retval)); 1200*0Sstevel@tonic-gate exit(1); 1201*0Sstevel@tonic-gate } 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate if (retval = krb5_recvauth(context, &auth_context, (void *) &fd, 1205*0Sstevel@tonic-gate kprop_version, server, 0, keytab, &ticket)){ 1206*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_recvauth: %s"), 1207*0Sstevel@tonic-gate error_message(retval)); 1208*0Sstevel@tonic-gate exit(1); 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate if (retval = krb5_copy_principal(context, 1212*0Sstevel@tonic-gate ticket->enc_part2->client, clientp)) { 1213*0Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_copy_prinicpal: %s"), 1214*0Sstevel@tonic-gate error_message(retval)); 1215*0Sstevel@tonic-gate exit(1); 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate *etype = ticket->enc_part.enctype; 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate if (debug) { 1221*0Sstevel@tonic-gate char * name; 1222*0Sstevel@tonic-gate char etypebuf[100]; 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate if (retval = krb5_unparse_name(context, *clientp, &name)) { 1225*0Sstevel@tonic-gate com_err(progname, retval, 1226*0Sstevel@tonic-gate gettext("While unparsing client name")); 1227*0Sstevel@tonic-gate exit(1); 1228*0Sstevel@tonic-gate } 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate if (retval = krb5_enctype_to_string(*etype, etypebuf, 1231*0Sstevel@tonic-gate sizeof(etypebuf))) { 1232*0Sstevel@tonic-gate com_err(progname, retval, gettext("While unparsing ticket etype")); 1233*0Sstevel@tonic-gate exit(1); 1234*0Sstevel@tonic-gate } 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate printf("authenticated client: %s (etype == %s)\n", name, etypebuf); 1237*0Sstevel@tonic-gate free(name); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate krb5_free_ticket(context, ticket); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate krb5_boolean 1244*0Sstevel@tonic-gate authorized_principal(context, p, auth_etype) 1245*0Sstevel@tonic-gate krb5_context context; 1246*0Sstevel@tonic-gate krb5_principal p; 1247*0Sstevel@tonic-gate krb5_enctype auth_etype; 1248*0Sstevel@tonic-gate { 1249*0Sstevel@tonic-gate char *name, *ptr; 1250*0Sstevel@tonic-gate char buf[1024]; 1251*0Sstevel@tonic-gate krb5_error_code retval; 1252*0Sstevel@tonic-gate FILE *acl_file; 1253*0Sstevel@tonic-gate int end; 1254*0Sstevel@tonic-gate krb5_enctype acl_etype; 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate retval = krb5_unparse_name(context, p, &name); 1257*0Sstevel@tonic-gate if (retval) 1258*0Sstevel@tonic-gate return FALSE; 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate acl_file = fopen(acl_file_name, "r"); 1261*0Sstevel@tonic-gate if (!acl_file) 1262*0Sstevel@tonic-gate return FALSE; 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate while (!feof(acl_file)) { 1265*0Sstevel@tonic-gate if (!fgets(buf, sizeof(buf), acl_file)) 1266*0Sstevel@tonic-gate break; 1267*0Sstevel@tonic-gate end = strlen(buf) - 1; 1268*0Sstevel@tonic-gate if (buf[end] == '\n') 1269*0Sstevel@tonic-gate buf[end] = '\0'; 1270*0Sstevel@tonic-gate if (!strncmp(name, buf, strlen(name))) { 1271*0Sstevel@tonic-gate ptr = buf+strlen(name); 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate /* if the next character is not whitespace or nul, then 1274*0Sstevel@tonic-gate the match is only partial. continue on to new lines. */ 1275*0Sstevel@tonic-gate if (*ptr && !isspace(*ptr)) 1276*0Sstevel@tonic-gate continue; 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate /* otherwise, skip trailing whitespace */ 1279*0Sstevel@tonic-gate for (; *ptr && isspace(*ptr); ptr++) ; 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate /* now, look for an etype string. if there isn't one, 1282*0Sstevel@tonic-gate return true. if there is an invalid string, continue. 1283*0Sstevel@tonic-gate If there is a valid string, return true only if it 1284*0Sstevel@tonic-gate matches the etype passed in, otherwise continue */ 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate if ((*ptr) && 1287*0Sstevel@tonic-gate ((retval = krb5_string_to_enctype(ptr, &acl_etype)) || 1288*0Sstevel@tonic-gate (acl_etype != auth_etype))) 1289*0Sstevel@tonic-gate continue; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate free(name); 1292*0Sstevel@tonic-gate fclose(acl_file); 1293*0Sstevel@tonic-gate return TRUE; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate free(name); 1297*0Sstevel@tonic-gate fclose(acl_file); 1298*0Sstevel@tonic-gate return FALSE; 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate void 1302*0Sstevel@tonic-gate recv_database(context, fd, database_fd, confmsg) 1303*0Sstevel@tonic-gate krb5_context context; 1304*0Sstevel@tonic-gate int fd; 1305*0Sstevel@tonic-gate int database_fd; 1306*0Sstevel@tonic-gate krb5_data *confmsg; 1307*0Sstevel@tonic-gate { 1308*0Sstevel@tonic-gate int database_size; 1309*0Sstevel@tonic-gate int received_size, n; 1310*0Sstevel@tonic-gate char buf[1024]; 1311*0Sstevel@tonic-gate krb5_data inbuf, outbuf; 1312*0Sstevel@tonic-gate krb5_error_code retval; 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate /* 1315*0Sstevel@tonic-gate * Receive and decode size from client 1316*0Sstevel@tonic-gate */ 1317*0Sstevel@tonic-gate if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) { 1318*0Sstevel@tonic-gate send_error(context, fd, retval, gettext("while reading database size")); 1319*0Sstevel@tonic-gate com_err(progname, retval, 1320*0Sstevel@tonic-gate gettext("while reading size of database from client")); 1321*0Sstevel@tonic-gate exit(1); 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate if (krb5_is_krb_error(&inbuf)) 1324*0Sstevel@tonic-gate recv_error(context, &inbuf); 1325*0Sstevel@tonic-gate if (retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL)) { 1326*0Sstevel@tonic-gate send_error(context, fd, retval, gettext("while decoding database size")); 1327*0Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf); 1328*0Sstevel@tonic-gate com_err(progname, retval, 1329*0Sstevel@tonic-gate gettext("while decoding database size from client")); 1330*0Sstevel@tonic-gate exit(1); 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate memcpy((char *) &database_size, outbuf.data, sizeof(database_size)); 1333*0Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf); 1334*0Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf); 1335*0Sstevel@tonic-gate database_size = ntohl(database_size); 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate /* 1338*0Sstevel@tonic-gate * Initialize the initial vector. 1339*0Sstevel@tonic-gate */ 1340*0Sstevel@tonic-gate if (retval = krb5_auth_con_initivector(context, auth_context)) { 1341*0Sstevel@tonic-gate send_error(context, fd, retval, gettext("failed while initializing i_vector")); 1342*0Sstevel@tonic-gate com_err(progname, retval, gettext("while initializing i_vector")); 1343*0Sstevel@tonic-gate exit(1); 1344*0Sstevel@tonic-gate } 1345*0Sstevel@tonic-gate 1346*0Sstevel@tonic-gate /* 1347*0Sstevel@tonic-gate * Now start receiving the database from the net 1348*0Sstevel@tonic-gate */ 1349*0Sstevel@tonic-gate received_size = 0; 1350*0Sstevel@tonic-gate while (received_size < database_size) { 1351*0Sstevel@tonic-gate if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) { 1352*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), 1353*0Sstevel@tonic-gate gettext("while reading database block starting at offset %d"), 1354*0Sstevel@tonic-gate received_size); 1355*0Sstevel@tonic-gate com_err(progname, retval, buf); 1356*0Sstevel@tonic-gate send_error(context, fd, retval, buf); 1357*0Sstevel@tonic-gate exit(1); 1358*0Sstevel@tonic-gate } 1359*0Sstevel@tonic-gate if (krb5_is_krb_error(&inbuf)) 1360*0Sstevel@tonic-gate recv_error(context, &inbuf); 1361*0Sstevel@tonic-gate if (retval = krb5_rd_priv(context, auth_context, &inbuf, 1362*0Sstevel@tonic-gate &outbuf, NULL)) { 1363*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), 1364*0Sstevel@tonic-gate gettext("while decoding database block starting at offset %d"), 1365*0Sstevel@tonic-gate received_size); 1366*0Sstevel@tonic-gate com_err(progname, retval, buf); 1367*0Sstevel@tonic-gate send_error(context, fd, retval, buf); 1368*0Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf); 1369*0Sstevel@tonic-gate exit(1); 1370*0Sstevel@tonic-gate } 1371*0Sstevel@tonic-gate n = write(database_fd, outbuf.data, outbuf.length); 1372*0Sstevel@tonic-gate if (n < 0) { 1373*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), 1374*0Sstevel@tonic-gate gettext( 1375*0Sstevel@tonic-gate "while writing database block starting at offset %d"), 1376*0Sstevel@tonic-gate received_size); 1377*0Sstevel@tonic-gate send_error(context, fd, errno, buf); 1378*0Sstevel@tonic-gate } else if (n != outbuf.length) { 1379*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), 1380*0Sstevel@tonic-gate gettext( 1381*0Sstevel@tonic-gate "incomplete write while writing database block starting at\n" 1382*0Sstevel@tonic-gate "offset %d (%d written, %d expected)"), 1383*0Sstevel@tonic-gate received_size, n, outbuf.length); 1384*0Sstevel@tonic-gate send_error(context, fd, KRB5KRB_ERR_GENERIC, buf); 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate received_size += outbuf.length; 1387*0Sstevel@tonic-gate /* SUNWresync121: our krb5...contents sets length to 0 */ 1388*0Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf); 1389*0Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate /* 1392*0Sstevel@tonic-gate * OK, we've seen the entire file. Did we get too many bytes? 1393*0Sstevel@tonic-gate */ 1394*0Sstevel@tonic-gate if (received_size > database_size) { 1395*0Sstevel@tonic-gate snprintf(buf, sizeof (buf), 1396*0Sstevel@tonic-gate gettext("Received %d bytes, expected %d bytes for database file"), 1397*0Sstevel@tonic-gate received_size, database_size); 1398*0Sstevel@tonic-gate send_error(context, fd, KRB5KRB_ERR_GENERIC, buf); 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate /* 1401*0Sstevel@tonic-gate * Create message acknowledging number of bytes received, but 1402*0Sstevel@tonic-gate * don't send it until kdb5_util returns successfully. 1403*0Sstevel@tonic-gate */ 1404*0Sstevel@tonic-gate database_size = htonl(database_size); 1405*0Sstevel@tonic-gate inbuf.data = (char *) &database_size; 1406*0Sstevel@tonic-gate inbuf.length = sizeof(database_size); 1407*0Sstevel@tonic-gate if (retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL)) { 1408*0Sstevel@tonic-gate com_err(progname, retval, 1409*0Sstevel@tonic-gate gettext("while encoding # of receieved bytes")); 1410*0Sstevel@tonic-gate send_error(context, fd, retval, 1411*0Sstevel@tonic-gate gettext("while encoding # of received bytes")); 1412*0Sstevel@tonic-gate exit(1); 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate void 1418*0Sstevel@tonic-gate send_error(context, fd, err_code, err_text) 1419*0Sstevel@tonic-gate krb5_context context; 1420*0Sstevel@tonic-gate int fd; 1421*0Sstevel@tonic-gate krb5_error_code err_code; 1422*0Sstevel@tonic-gate char *err_text; 1423*0Sstevel@tonic-gate { 1424*0Sstevel@tonic-gate krb5_error error; 1425*0Sstevel@tonic-gate const char *text; 1426*0Sstevel@tonic-gate krb5_data outbuf; 1427*0Sstevel@tonic-gate char buf[1024]; 1428*0Sstevel@tonic-gate 1429*0Sstevel@tonic-gate memset((char *)&error, 0, sizeof(error)); 1430*0Sstevel@tonic-gate krb5_us_timeofday(context, &error.stime, &error.susec); 1431*0Sstevel@tonic-gate error.server = server; 1432*0Sstevel@tonic-gate error.client = client; 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate if (err_text) 1435*0Sstevel@tonic-gate text = err_text; 1436*0Sstevel@tonic-gate else 1437*0Sstevel@tonic-gate text = error_message(err_code); 1438*0Sstevel@tonic-gate 1439*0Sstevel@tonic-gate error.error = err_code - ERROR_TABLE_BASE_krb5; 1440*0Sstevel@tonic-gate if (error.error > 127) { 1441*0Sstevel@tonic-gate error.error = KRB_ERR_GENERIC; 1442*0Sstevel@tonic-gate if (err_text) { 1443*0Sstevel@tonic-gate sprintf(buf, "%s %s", error_message(err_code), 1444*0Sstevel@tonic-gate err_text); 1445*0Sstevel@tonic-gate text = buf; 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate error.text.length = strlen(text) + 1; 1449*0Sstevel@tonic-gate if (error.text.data = malloc(error.text.length)) { 1450*0Sstevel@tonic-gate strcpy(error.text.data, text); 1451*0Sstevel@tonic-gate if (!krb5_mk_error(context, &error, &outbuf)) { 1452*0Sstevel@tonic-gate (void) krb5_write_message(context, (void *)&fd,&outbuf); 1453*0Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf); 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate free(error.text.data); 1456*0Sstevel@tonic-gate } 1457*0Sstevel@tonic-gate } 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate void 1460*0Sstevel@tonic-gate recv_error(context, inbuf) 1461*0Sstevel@tonic-gate krb5_context context; 1462*0Sstevel@tonic-gate krb5_data *inbuf; 1463*0Sstevel@tonic-gate { 1464*0Sstevel@tonic-gate krb5_error *error; 1465*0Sstevel@tonic-gate krb5_error_code retval; 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate if (retval = krb5_rd_error(context, inbuf, &error)) { 1468*0Sstevel@tonic-gate com_err(progname, retval, 1469*0Sstevel@tonic-gate gettext("while decoding error packet from client")); 1470*0Sstevel@tonic-gate exit(1); 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate if (error->error == KRB_ERR_GENERIC) { 1473*0Sstevel@tonic-gate if (error->text.data) 1474*0Sstevel@tonic-gate fprintf(stderr, 1475*0Sstevel@tonic-gate gettext("Generic remote error: %s\n"), 1476*0Sstevel@tonic-gate error->text.data); 1477*0Sstevel@tonic-gate } else if (error->error) { 1478*0Sstevel@tonic-gate com_err(progname, error->error + ERROR_TABLE_BASE_krb5, 1479*0Sstevel@tonic-gate gettext("signalled from server")); 1480*0Sstevel@tonic-gate if (error->text.data) 1481*0Sstevel@tonic-gate fprintf(stderr, 1482*0Sstevel@tonic-gate gettext("Error text from client: %s\n"), 1483*0Sstevel@tonic-gate error->text.data); 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate krb5_free_error(context, error); 1486*0Sstevel@tonic-gate exit(1); 1487*0Sstevel@tonic-gate } 1488*0Sstevel@tonic-gate 1489*0Sstevel@tonic-gate void 1490*0Sstevel@tonic-gate load_database(context, kdb5_util, database_file_name) 1491*0Sstevel@tonic-gate krb5_context context; 1492*0Sstevel@tonic-gate char *kdb5_util; 1493*0Sstevel@tonic-gate char *database_file_name; 1494*0Sstevel@tonic-gate { 1495*0Sstevel@tonic-gate static char *edit_av[10]; 1496*0Sstevel@tonic-gate int error_ret, save_stderr; 1497*0Sstevel@tonic-gate int child_pid; 1498*0Sstevel@tonic-gate int count; 1499*0Sstevel@tonic-gate int waitb; 1500*0Sstevel@tonic-gate krb5_error_code retval; 1501*0Sstevel@tonic-gate kdb_log_context *log_ctx; 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gate if (debug) 1504*0Sstevel@tonic-gate printf(gettext("calling kdb5_util to load database\n")); 1505*0Sstevel@tonic-gate 1506*0Sstevel@tonic-gate log_ctx = context->kdblog_context; 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate edit_av[0] = kdb5_util; 1509*0Sstevel@tonic-gate count = 1; 1510*0Sstevel@tonic-gate if (realm) { 1511*0Sstevel@tonic-gate edit_av[count++] = "-r"; 1512*0Sstevel@tonic-gate edit_av[count++] = realm; 1513*0Sstevel@tonic-gate } 1514*0Sstevel@tonic-gate edit_av[count++] = "load"; 1515*0Sstevel@tonic-gate if (kerb_database) { 1516*0Sstevel@tonic-gate edit_av[count++] = "-d"; 1517*0Sstevel@tonic-gate edit_av[count++] = kerb_database; 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 1521*0Sstevel@tonic-gate edit_av[count++] = "-i"; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate edit_av[count++] = database_file_name; 1524*0Sstevel@tonic-gate edit_av[count++] = NULL; 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate switch(child_pid = fork()) { 1527*0Sstevel@tonic-gate case -1: 1528*0Sstevel@tonic-gate com_err(progname, errno, gettext("while trying to fork %s"), 1529*0Sstevel@tonic-gate kdb5_util); 1530*0Sstevel@tonic-gate exit(1); 1531*0Sstevel@tonic-gate /*NOTREACHED*/ 1532*0Sstevel@tonic-gate case 0: 1533*0Sstevel@tonic-gate if (!debug) { 1534*0Sstevel@tonic-gate save_stderr = dup(2); 1535*0Sstevel@tonic-gate close(0); 1536*0Sstevel@tonic-gate close(1); 1537*0Sstevel@tonic-gate close(2); 1538*0Sstevel@tonic-gate open("/dev/null", O_RDWR); 1539*0Sstevel@tonic-gate dup(0); 1540*0Sstevel@tonic-gate dup(0); 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate execv(kdb5_util, edit_av); 1544*0Sstevel@tonic-gate retval = errno; 1545*0Sstevel@tonic-gate if (!debug) 1546*0Sstevel@tonic-gate dup2(save_stderr, 2); 1547*0Sstevel@tonic-gate com_err(progname, retval, gettext("while trying to exec %s"), 1548*0Sstevel@tonic-gate kdb5_util); 1549*0Sstevel@tonic-gate _exit(1); 1550*0Sstevel@tonic-gate /*NOTREACHED*/ 1551*0Sstevel@tonic-gate default: 1552*0Sstevel@tonic-gate if (debug) 1553*0Sstevel@tonic-gate printf(gettext("Child PID is %d\n"), child_pid); 1554*0Sstevel@tonic-gate if (wait(&waitb) < 0) { 1555*0Sstevel@tonic-gate com_err(progname, errno, gettext("while waiting for %s"), 1556*0Sstevel@tonic-gate kdb5_util); 1557*0Sstevel@tonic-gate exit(1); 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate } 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate if ((error_ret = WEXITSTATUS(waitb)) != 0) { 1562*0Sstevel@tonic-gate com_err(progname, 0, 1563*0Sstevel@tonic-gate gettext("%s returned a bad exit status (%d)"), kdb5_util, 1564*0Sstevel@tonic-gate error_ret); 1565*0Sstevel@tonic-gate exit(1); 1566*0Sstevel@tonic-gate } 1567*0Sstevel@tonic-gate return; 1568*0Sstevel@tonic-gate } 1569