10Sstevel@tonic-gate /*
28714SMark.Phalan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * All rights reserved.
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * Export of this software from the United States of America may require
80Sstevel@tonic-gate * a specific license from the United States Government. It is the
90Sstevel@tonic-gate * responsibility of any person or organization contemplating export to
100Sstevel@tonic-gate * obtain such a license before exporting.
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
130Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
140Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
150Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
160Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
170Sstevel@tonic-gate * the name of FundsXpress. not be used in advertising or publicity pertaining
180Sstevel@tonic-gate * to distribution of the software without specific, written prior
190Sstevel@tonic-gate * permission. FundsXpress makes no representations about the suitability of
200Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
210Sstevel@tonic-gate * or implied warranty.
220Sstevel@tonic-gate *
230Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
240Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
250Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * slave/kpropd.c
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * Copyright 1990,1991 by the Massachusetts Institute of Technology.
320Sstevel@tonic-gate * All Rights Reserved.
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * Export of this software from the United States of America may
350Sstevel@tonic-gate * require a specific license from the United States Government.
360Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
370Sstevel@tonic-gate * export to obtain such a license before exporting.
380Sstevel@tonic-gate *
390Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
400Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
410Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
420Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
430Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
440Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
450Sstevel@tonic-gate * to distribution of the software without specific, written prior
460Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
470Sstevel@tonic-gate * your software as modified software and not distribute it in such a
480Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
490Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
500Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
510Sstevel@tonic-gate * or implied warranty.
520Sstevel@tonic-gate *
530Sstevel@tonic-gate *
540Sstevel@tonic-gate * XXX We need to modify the protocol so that an acknowledge is set
550Sstevel@tonic-gate * after each block, instead after the entire series is sent over.
560Sstevel@tonic-gate * The reason for this is so that error packets can get interpreted
570Sstevel@tonic-gate * right away. If you don't do this, the sender may never get the
580Sstevel@tonic-gate * error packet, because it will die an EPIPE trying to complete the
590Sstevel@tonic-gate * write...
600Sstevel@tonic-gate */
610Sstevel@tonic-gate
622881Smp153739
630Sstevel@tonic-gate #include <stdio.h>
640Sstevel@tonic-gate #include <ctype.h>
650Sstevel@tonic-gate #include <sys/file.h>
660Sstevel@tonic-gate #include <signal.h>
670Sstevel@tonic-gate #include <string.h>
680Sstevel@tonic-gate #include <fcntl.h>
690Sstevel@tonic-gate #include <sys/types.h>
700Sstevel@tonic-gate #include <sys/time.h>
710Sstevel@tonic-gate #include <sys/stat.h>
720Sstevel@tonic-gate #include <sys/socket.h>
730Sstevel@tonic-gate #include <sys/wait.h>
740Sstevel@tonic-gate #include <netinet/in.h>
750Sstevel@tonic-gate #include <arpa/inet.h>
760Sstevel@tonic-gate #include <sys/param.h>
770Sstevel@tonic-gate #include <netdb.h>
780Sstevel@tonic-gate #include <syslog.h>
790Sstevel@tonic-gate #include <libintl.h>
800Sstevel@tonic-gate #include <locale.h>
810Sstevel@tonic-gate #include <k5-int.h>
820Sstevel@tonic-gate #include <socket-utils.h>
830Sstevel@tonic-gate #include "com_err.h"
840Sstevel@tonic-gate #include <errno.h>
850Sstevel@tonic-gate
860Sstevel@tonic-gate #include "kprop.h"
870Sstevel@tonic-gate #include <iprop_hdr.h>
880Sstevel@tonic-gate #include "iprop.h"
890Sstevel@tonic-gate #include <kadm5/admin.h>
900Sstevel@tonic-gate #include <kdb/kdb_log.h>
910Sstevel@tonic-gate
926426Smp153739 /* Solaris Kerberos */
936426Smp153739 #include <libgen.h>
946426Smp153739
950Sstevel@tonic-gate #define SYSLOG_CLASS LOG_DAEMON
96*9033SPeter.Shoults@Sun.COM #define INITIAL_TIMER 10
970Sstevel@tonic-gate
980Sstevel@tonic-gate char *poll_time = NULL;
990Sstevel@tonic-gate char *def_realm = NULL;
1000Sstevel@tonic-gate boolean_t runonce = B_FALSE;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate /*
103*9033SPeter.Shoults@Sun.COM * Global fd to close upon alarm time-out.
104*9033SPeter.Shoults@Sun.COM */
105*9033SPeter.Shoults@Sun.COM volatile int gfd = -1;
106*9033SPeter.Shoults@Sun.COM
107*9033SPeter.Shoults@Sun.COM /*
1080Sstevel@tonic-gate * This struct simulates the use of _kadm5_server_handle_t
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate typedef struct _kadm5_iprop_handle_t {
1110Sstevel@tonic-gate krb5_ui_4 magic_number;
1120Sstevel@tonic-gate krb5_ui_4 struct_version;
1130Sstevel@tonic-gate krb5_ui_4 api_version;
1140Sstevel@tonic-gate char *cache_name;
1150Sstevel@tonic-gate int destroy_cache;
1160Sstevel@tonic-gate CLIENT *clnt;
1170Sstevel@tonic-gate krb5_context context;
1180Sstevel@tonic-gate kadm5_config_params params;
1190Sstevel@tonic-gate struct _kadm5_iprop_handle_t *lhandle;
1200Sstevel@tonic-gate } *kadm5_iprop_handle_t;
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate static char *kprop_version = KPROP_PROT_VERSION;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate char *progname;
1250Sstevel@tonic-gate int debug = 0;
1260Sstevel@tonic-gate char *srvtab = 0;
1270Sstevel@tonic-gate int standalone = 0;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate krb5_principal server; /* This is our server principal name */
1300Sstevel@tonic-gate krb5_principal client; /* This is who we're talking to */
1310Sstevel@tonic-gate krb5_context kpropd_context;
1320Sstevel@tonic-gate krb5_auth_context auth_context;
1330Sstevel@tonic-gate char *realm = NULL; /* Our realm */
1340Sstevel@tonic-gate char *file = KPROPD_DEFAULT_FILE;
1350Sstevel@tonic-gate char *temp_file_name;
1360Sstevel@tonic-gate char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
1370Sstevel@tonic-gate char *kerb_database = NULL;
1380Sstevel@tonic-gate char *acl_file_name = KPROPD_ACL_FILE;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate krb5_address sender_addr;
1410Sstevel@tonic-gate krb5_address receiver_addr;
1420Sstevel@tonic-gate short port = 0;
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate void PRS
1450Sstevel@tonic-gate (int, char**);
1460Sstevel@tonic-gate int do_standalone
1470Sstevel@tonic-gate (iprop_role iproprole);
1480Sstevel@tonic-gate void doit
1492881Smp153739 (int);
1500Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx);
1510Sstevel@tonic-gate
1528714SMark.Phalan@Sun.COM /* Solaris Kerberos */
1530Sstevel@tonic-gate void kerberos_authenticate
1542881Smp153739 (krb5_context,
1550Sstevel@tonic-gate int,
1560Sstevel@tonic-gate krb5_principal *,
1570Sstevel@tonic-gate krb5_enctype *,
1588714SMark.Phalan@Sun.COM struct sockaddr_storage *);
1590Sstevel@tonic-gate krb5_boolean authorized_principal
1602881Smp153739 (krb5_context,
1610Sstevel@tonic-gate krb5_principal,
1620Sstevel@tonic-gate krb5_enctype);
1630Sstevel@tonic-gate void recv_database
1642881Smp153739 (krb5_context,
1650Sstevel@tonic-gate int,
1660Sstevel@tonic-gate int,
1670Sstevel@tonic-gate krb5_data *);
1680Sstevel@tonic-gate void load_database
1692881Smp153739 (krb5_context,
1700Sstevel@tonic-gate char *,
1710Sstevel@tonic-gate char *);
1720Sstevel@tonic-gate void send_error
1732881Smp153739 (krb5_context,
1740Sstevel@tonic-gate int,
1750Sstevel@tonic-gate krb5_error_code,
1760Sstevel@tonic-gate char *);
1770Sstevel@tonic-gate void recv_error
1782881Smp153739 (krb5_context,
1790Sstevel@tonic-gate krb5_data *);
1800Sstevel@tonic-gate int convert_polltime
1810Sstevel@tonic-gate (char *);
1820Sstevel@tonic-gate unsigned int backoff_from_master
1830Sstevel@tonic-gate (int *);
1840Sstevel@tonic-gate
usage()1850Sstevel@tonic-gate static void usage()
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate fprintf(stderr,
1880Sstevel@tonic-gate gettext("\nUsage: %s\n"), /* progname may be a long pathname */
1890Sstevel@tonic-gate progname);
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate fprintf(stderr,
1920Sstevel@tonic-gate gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n"));
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate fprintf(stderr,
1950Sstevel@tonic-gate gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n"));
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n"));
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate exit(1);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate int
main(argc,argv)2030Sstevel@tonic-gate main(argc, argv)
2040Sstevel@tonic-gate int argc;
2050Sstevel@tonic-gate char **argv;
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate krb5_error_code retval;
2080Sstevel@tonic-gate int ret = 0;
2090Sstevel@tonic-gate kdb_log_context *log_ctx;
2104960Swillf int iprop_supported;
2116426Smp153739 krb5_boolean is_master = FALSE;
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate PRS(argc, argv);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate log_ctx = kpropd_context->kdblog_context;
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate * We wanna do iprop !
2200Sstevel@tonic-gate */
2214960Swillf retval = krb5_db_supports_iprop(kpropd_context,
2224960Swillf &iprop_supported);
2234960Swillf if (retval) {
2246426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
2254960Swillf com_err(progname, retval,
2266426Smp153739 gettext("while determining if dbmodule plugin "
2276426Smp153739 "supports iprop"));
2284960Swillf exit(1);
2294960Swillf }
2304960Swillf if (!iprop_supported) {
2316426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
2326426Smp153739 com_err(progname, 0,
2334960Swillf gettext("Current dbmodule plugin does not support "
2346426Smp153739 "iprop"));
2356426Smp153739 exit(1);
2366426Smp153739 }
2376426Smp153739
2386426Smp153739 /*
2396426Smp153739 * Solaris Kerberos:
2406426Smp153739 * Ensure that kpropd is only run on a slave
2416426Smp153739 */
2426426Smp153739 if (retval = kadm5_is_master(kpropd_context, def_realm,
2436426Smp153739 &is_master)) {
2446426Smp153739 com_err(progname, retval,
2456426Smp153739 gettext("while trying to determine whether host is "
2466426Smp153739 "master KDC for realm %s"), def_realm);
2476426Smp153739 exit(1);
2486426Smp153739 }
2496426Smp153739
2506426Smp153739 if (is_master == TRUE) {
2516426Smp153739 char *master = NULL;
2526426Smp153739 kadm5_get_master(kpropd_context, def_realm, &master);
2536426Smp153739
2546426Smp153739 com_err(progname, 0,
2556426Smp153739 gettext("%s is the master KDC for the realm %s. "
2566426Smp153739 "%s can only be run on a slave KDC"),
2576426Smp153739 master ? master : "unknown", def_realm, progname);
2584960Swillf exit(1);
2594960Swillf }
2604960Swillf
2610Sstevel@tonic-gate retval = do_iprop(log_ctx);
2620Sstevel@tonic-gate if (retval) {
2636426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
2640Sstevel@tonic-gate com_err(progname, retval,
2656426Smp153739 gettext("while doing iprop"));
2660Sstevel@tonic-gate exit(1);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate } else {
2706426Smp153739
2716426Smp153739 /*
2726426Smp153739 * Solaris Kerberos:
2736426Smp153739 * Ensure that the kpropd.acl file exists and contains at least
2746426Smp153739 * 1 entry.
2756426Smp153739 */
2766426Smp153739 FILE *tmp_acl_file;
2776426Smp153739 int seen_file = 0;
2786426Smp153739 char buf[1024];
2796426Smp153739
2806426Smp153739 tmp_acl_file = fopen(acl_file_name, "r");
2816426Smp153739 if (!tmp_acl_file) {
2826426Smp153739 com_err(progname, errno,
2836426Smp153739 gettext("while opening acl file %s"),
2846426Smp153739 acl_file_name);
2856426Smp153739 exit(1);
2866426Smp153739 }
2876426Smp153739
2886426Smp153739 while (!feof(tmp_acl_file) && !seen_file ) {
2896426Smp153739 if (!fgets(buf, sizeof(buf), tmp_acl_file))
2906426Smp153739 break;
2916426Smp153739
2926426Smp153739 if (buf[0] != '#' && !isspace(buf[0]))
2936426Smp153739 seen_file = 1;
2946426Smp153739 }
2956426Smp153739 if (!seen_file) {
2966426Smp153739 com_err(progname, 0,
2976426Smp153739 gettext("No entries found in %s. Can't "
2986426Smp153739 "authorize propagation requests"), acl_file_name);
2996426Smp153739 exit(1);
3006426Smp153739 }
3016426Smp153739 fclose(tmp_acl_file);
3026426Smp153739
3030Sstevel@tonic-gate if (standalone)
3040Sstevel@tonic-gate ret = do_standalone(IPROP_NULL);
3050Sstevel@tonic-gate else
3060Sstevel@tonic-gate doit(0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate exit(ret);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
resync_alarm(int sn)312*9033SPeter.Shoults@Sun.COM void resync_alarm(int sn)
313*9033SPeter.Shoults@Sun.COM {
314*9033SPeter.Shoults@Sun.COM close(gfd);
315*9033SPeter.Shoults@Sun.COM if (debug)
316*9033SPeter.Shoults@Sun.COM fprintf(stderr, gettext("resync_alarm: closing fd: %d\n"), gfd);
317*9033SPeter.Shoults@Sun.COM gfd = -1;
318*9033SPeter.Shoults@Sun.COM }
319*9033SPeter.Shoults@Sun.COM
do_standalone(iprop_role iproprole)3200Sstevel@tonic-gate int do_standalone(iprop_role iproprole)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate struct linger linger;
3230Sstevel@tonic-gate struct servent *sp;
3240Sstevel@tonic-gate int finet, fromlen, s;
3250Sstevel@tonic-gate int on = 1;
3260Sstevel@tonic-gate int ret, status = 0;
3270Sstevel@tonic-gate struct sockaddr_in6 sin6 = { AF_INET6 };
3280Sstevel@tonic-gate int sin6_size = sizeof (sin6);
329*9033SPeter.Shoults@Sun.COM /*
330*9033SPeter.Shoults@Sun.COM * Timer for accept/read calls, in case of network type errors.
331*9033SPeter.Shoults@Sun.COM */
332*9033SPeter.Shoults@Sun.COM int backoff_timer = INITIAL_TIMER;
333*9033SPeter.Shoults@Sun.COM
334*9033SPeter.Shoults@Sun.COM retry:
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /* listen for either ipv4 or ipv6 */
3370Sstevel@tonic-gate finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
3380Sstevel@tonic-gate if (finet < 0 ) {
3390Sstevel@tonic-gate com_err(progname, errno, gettext("while obtaining socket"));
3400Sstevel@tonic-gate exit(1);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate if(!port) {
3440Sstevel@tonic-gate sp = getservbyname(KPROP_SERVICE, "tcp");
3450Sstevel@tonic-gate if (sp == NULL) {
3460Sstevel@tonic-gate com_err(progname, 0, gettext("%s/tcp: unknown service"),
3470Sstevel@tonic-gate KPROP_SERVICE);
3480Sstevel@tonic-gate exit(1);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate sin6.sin6_port = sp->s_port;
3510Sstevel@tonic-gate } else
3520Sstevel@tonic-gate sin6.sin6_port = port;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * We need to close the socket immediately if iprop is enabled,
3560Sstevel@tonic-gate * since back-to-back full resyncs are possible, so we do not
3570Sstevel@tonic-gate * linger around for too long
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate if (iproprole == IPROP_SLAVE) {
3600Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
3610Sstevel@tonic-gate (char *)&on, sizeof(on)) < 0)
3620Sstevel@tonic-gate com_err(progname, errno,
3636426Smp153739 gettext("while setting socket option (SO_REUSEADDR)"));
3640Sstevel@tonic-gate linger.l_onoff = 1;
3650Sstevel@tonic-gate linger.l_linger = 2;
3660Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_LINGER,
3670Sstevel@tonic-gate (void *)&linger, sizeof(linger)) < 0)
3680Sstevel@tonic-gate com_err(progname, errno,
3696426Smp153739 gettext("while setting socket option (SO_LINGER)"));
370*9033SPeter.Shoults@Sun.COM /*
371*9033SPeter.Shoults@Sun.COM * We also want to set a timer so that the slave is not waiting
372*9033SPeter.Shoults@Sun.COM * until infinity for an update from the master.
373*9033SPeter.Shoults@Sun.COM */
374*9033SPeter.Shoults@Sun.COM gfd = finet;
375*9033SPeter.Shoults@Sun.COM signal(SIGALRM, resync_alarm);
376*9033SPeter.Shoults@Sun.COM if (debug) {
377*9033SPeter.Shoults@Sun.COM fprintf(stderr, "do_standalone: setting resync alarm to %d\n",
378*9033SPeter.Shoults@Sun.COM backoff_timer);
379*9033SPeter.Shoults@Sun.COM }
380*9033SPeter.Shoults@Sun.COM if (alarm(backoff_timer) != 0) {
381*9033SPeter.Shoults@Sun.COM if (debug) {
382*9033SPeter.Shoults@Sun.COM fprintf(stderr,
383*9033SPeter.Shoults@Sun.COM gettext("%s: alarm already set\n"), progname);
384*9033SPeter.Shoults@Sun.COM }
385*9033SPeter.Shoults@Sun.COM }
386*9033SPeter.Shoults@Sun.COM backoff_timer *= 2;
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) {
3890Sstevel@tonic-gate if (debug) {
3900Sstevel@tonic-gate on = 1;
3910Sstevel@tonic-gate fprintf(stderr,
3920Sstevel@tonic-gate gettext("%s: attempting to rebind socket "
3930Sstevel@tonic-gate "with SO_REUSEADDR\n"), progname);
3940Sstevel@tonic-gate if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
3950Sstevel@tonic-gate (char *)&on, sizeof(on)) < 0) {
3960Sstevel@tonic-gate com_err(progname, errno,
3976426Smp153739 gettext("while setting socket option (SO_REUSEADDR)"));
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6));
4002881Smp153739 }
4010Sstevel@tonic-gate
4022881Smp153739 if (ret < 0) {
4036426Smp153739 /*
4046426Smp153739 * Solaris Kerberos:
4056426Smp153739 * com_err will print the err msg associated with errno
4066426Smp153739 */
4076426Smp153739 #if 0
4082881Smp153739 perror(gettext("bind"));
4096426Smp153739 #endif
4102881Smp153739 com_err(progname, errno,
4112881Smp153739 gettext("while binding listener socket"));
4122881Smp153739 exit(1);
4132881Smp153739 }
4142881Smp153739 }
4156426Smp153739 if (!debug && (iproprole != IPROP_SLAVE)) {
4166426Smp153739 /* Solaris Kerberos: Indicate where further messages will be sent */
4176426Smp153739 fprintf(stderr,
4186426Smp153739 gettext("%s: Logging to SYSLOG with LOG_DAEMON facility\n"),
4196426Smp153739 progname);
4206426Smp153739 if (daemon(1, 0)) {
4216426Smp153739 com_err(progname, errno, gettext("while daemonizing"));
4226426Smp153739 exit(1);
4236426Smp153739 }
4246426Smp153739 rem_default_com_err_hook();
4256426Smp153739 }
4266426Smp153739
4270Sstevel@tonic-gate #ifdef PID_FILE
4282881Smp153739 if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
4292881Smp153739 fprintf(pidfile, gettext("%d\n"), getpid());
4302881Smp153739 fclose(pidfile);
4312881Smp153739 } else
4322881Smp153739 com_err(progname, errno,
4330Sstevel@tonic-gate gettext("while opening pid file %s for writing"),
4340Sstevel@tonic-gate PID_FILE);
4350Sstevel@tonic-gate #endif
4362881Smp153739 if (listen(finet, 5) < 0) {
4376426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
4386426Smp153739 com_err(progname, errno, gettext("while listening on socket"));
4392881Smp153739 exit(1);
4402881Smp153739 }
4412881Smp153739 while (1) {
4422881Smp153739 int child_pid;
4430Sstevel@tonic-gate
4442881Smp153739 s = accept(finet, (struct sockaddr *) &sin6, &sin6_size);
4450Sstevel@tonic-gate
4462881Smp153739 if (s < 0) {
447*9033SPeter.Shoults@Sun.COM int e = errno;
448*9033SPeter.Shoults@Sun.COM if (e != EINTR) {
449*9033SPeter.Shoults@Sun.COM /*
450*9033SPeter.Shoults@Sun.COM * Solaris Kerberos: Keep error messages
451*9033SPeter.Shoults@Sun.COM * consistent
452*9033SPeter.Shoults@Sun.COM */
453*9033SPeter.Shoults@Sun.COM com_err(progname, e,
454*9033SPeter.Shoults@Sun.COM gettext("while accepting connection"));
455*9033SPeter.Shoults@Sun.COM backoff_timer = INITIAL_TIMER;
4566426Smp153739 }
457*9033SPeter.Shoults@Sun.COM /*
458*9033SPeter.Shoults@Sun.COM * If we got EBADF, an alarm signal handler closed
459*9033SPeter.Shoults@Sun.COM * the file descriptor on us.
460*9033SPeter.Shoults@Sun.COM */
461*9033SPeter.Shoults@Sun.COM if (e != EBADF)
462*9033SPeter.Shoults@Sun.COM close(finet);
463*9033SPeter.Shoults@Sun.COM /*
464*9033SPeter.Shoults@Sun.COM * An alarm could have been set and the fd closed, we
465*9033SPeter.Shoults@Sun.COM * should retry in case of transient network error for
466*9033SPeter.Shoults@Sun.COM * up to a couple of minutes.
467*9033SPeter.Shoults@Sun.COM */
468*9033SPeter.Shoults@Sun.COM if (backoff_timer > 120)
469*9033SPeter.Shoults@Sun.COM return (EINTR);
470*9033SPeter.Shoults@Sun.COM goto retry;
4712881Smp153739 }
472*9033SPeter.Shoults@Sun.COM alarm(0);
473*9033SPeter.Shoults@Sun.COM gfd = -1;
4742881Smp153739 if (debug && (iproprole != IPROP_SLAVE))
4752881Smp153739 child_pid = 0;
4762881Smp153739 else
4772881Smp153739 child_pid = fork();
4782881Smp153739 switch (child_pid) {
4792881Smp153739 case -1:
4802881Smp153739 com_err(progname, errno, gettext("while forking"));
4812881Smp153739 exit(1);
4822881Smp153739 /*NOTREACHED*/
4832881Smp153739 case 0:
4842881Smp153739 /* child */
4852881Smp153739 (void) close(finet);
4860Sstevel@tonic-gate
4872881Smp153739 doit(s);
4882881Smp153739 close(s);
4892881Smp153739 _exit(0);
4900Sstevel@tonic-gate /*NOTREACHED*/
4912881Smp153739 default:
4920Sstevel@tonic-gate /* parent */
493*9033SPeter.Shoults@Sun.COM /*
494*9033SPeter.Shoults@Sun.COM * Errors should not be considered fatal in the iprop case as we
495*9033SPeter.Shoults@Sun.COM * could have transient type errors, such as network outage, etc.
496*9033SPeter.Shoults@Sun.COM * Sleeping 3s for 2s linger interval.
497*9033SPeter.Shoults@Sun.COM */
4980Sstevel@tonic-gate if (wait(&status) < 0) {
4990Sstevel@tonic-gate com_err(progname, errno,
5000Sstevel@tonic-gate gettext("while waiting to receive database"));
501*9033SPeter.Shoults@Sun.COM if (iproprole != IPROP_SLAVE)
502*9033SPeter.Shoults@Sun.COM exit(1);
503*9033SPeter.Shoults@Sun.COM sleep(3);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate close(s);
5070Sstevel@tonic-gate if (iproprole == IPROP_SLAVE)
5080Sstevel@tonic-gate close(finet);
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate if ((ret = WEXITSTATUS(status)) != 0)
5110Sstevel@tonic-gate return (ret);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate if (iproprole == IPROP_SLAVE)
5150Sstevel@tonic-gate break;
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate return (0);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate
doit(fd)5210Sstevel@tonic-gate void doit(fd)
5220Sstevel@tonic-gate int fd;
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate struct sockaddr_storage from;
5250Sstevel@tonic-gate socklen_t fromlen;
5260Sstevel@tonic-gate int on = 1;
5270Sstevel@tonic-gate struct hostent *hp;
5280Sstevel@tonic-gate krb5_error_code retval;
5290Sstevel@tonic-gate krb5_data confmsg;
5300Sstevel@tonic-gate int lock_fd;
5312881Smp153739 mode_t omask;
5320Sstevel@tonic-gate krb5_enctype etype;
5332881Smp153739 int database_fd;
5340Sstevel@tonic-gate char ntop[NI_MAXHOST] = "";
5350Sstevel@tonic-gate krb5_context doit_context;
5360Sstevel@tonic-gate kdb_log_context *log_ctx;
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate retval = krb5_init_context(&doit_context);
5390Sstevel@tonic-gate if (retval) {
5400Sstevel@tonic-gate com_err(progname, retval, gettext("while initializing krb5"));
5410Sstevel@tonic-gate exit(1);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate log_ctx = kpropd_context->kdblog_context;
544*9033SPeter.Shoults@Sun.COM if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
5450Sstevel@tonic-gate ulog_set_role(doit_context, IPROP_SLAVE);
546*9033SPeter.Shoults@Sun.COM /*
547*9033SPeter.Shoults@Sun.COM * We also want to set a timer so that the slave is not waiting
548*9033SPeter.Shoults@Sun.COM * until infinity for an update from the master.
549*9033SPeter.Shoults@Sun.COM */
550*9033SPeter.Shoults@Sun.COM if (debug)
551*9033SPeter.Shoults@Sun.COM fprintf(stderr, "doit: setting resync alarm to %ds\n",
552*9033SPeter.Shoults@Sun.COM INITIAL_TIMER);
553*9033SPeter.Shoults@Sun.COM signal(SIGALRM, resync_alarm);
554*9033SPeter.Shoults@Sun.COM gfd = fd;
555*9033SPeter.Shoults@Sun.COM if (alarm(INITIAL_TIMER) != 0) {
556*9033SPeter.Shoults@Sun.COM if (debug) {
557*9033SPeter.Shoults@Sun.COM fprintf(stderr,
558*9033SPeter.Shoults@Sun.COM gettext("%s: alarm already set\n"), progname);
559*9033SPeter.Shoults@Sun.COM }
560*9033SPeter.Shoults@Sun.COM }
561*9033SPeter.Shoults@Sun.COM }
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate fromlen = (socklen_t)sizeof (from);
5640Sstevel@tonic-gate if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
5650Sstevel@tonic-gate fprintf(stderr, "%s: ", progname);
5660Sstevel@tonic-gate perror(gettext("getpeername"));
5670Sstevel@tonic-gate exit(1);
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
5700Sstevel@tonic-gate sizeof (on)) < 0) {
5710Sstevel@tonic-gate com_err(progname, errno,
5720Sstevel@tonic-gate gettext("while attempting setsockopt (SO_KEEPALIVE)"));
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
5760Sstevel@tonic-gate NULL, 0, NI_NUMERICHOST) != 0) {
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate /* getnameifo failed so use inet_ntop() to get printable addresses */
5790Sstevel@tonic-gate if (from.ss_family == AF_INET) {
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate inet_ntop(AF_INET,
5820Sstevel@tonic-gate (const void *)&ss2sin(&from)->sin_addr,
5830Sstevel@tonic-gate ntop, sizeof(ntop));
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate } else if (from.ss_family == AF_INET6 &&
5860Sstevel@tonic-gate ! IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate ipaddr_t v4addr;
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate inet_ntop(AF_INET6,
5910Sstevel@tonic-gate (const void *)&ss2sin6(&from)->sin6_addr, ntop,
5920Sstevel@tonic-gate sizeof(ntop));
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate /* ipv4 mapped ipv6 addrs handled later */
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate if (from.ss_family == AF_INET || from.ss_family == AF_INET6) {
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate if (from.ss_family == AF_INET6 &&
6000Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate ipaddr_t v4addr;
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate /* coerce ipv4 mapped ipv6 addr to normal ipv4 addr */
6050Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&(ss2sin6(&from)->sin6_addr),
6060Sstevel@tonic-gate v4addr);
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate inet_ntop(AF_INET, (const void *) &v4addr,
6090Sstevel@tonic-gate ntop, sizeof(ntop));
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate syslog(LOG_INFO, gettext("Connection from %s"), ntop);
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate if (debug)
6150Sstevel@tonic-gate printf("Connection from %s\n", ntop);
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate } else {
6180Sstevel@tonic-gate /* address family isn't either AF_INET || AF_INET6 */
6190Sstevel@tonic-gate syslog(LOG_INFO,
6200Sstevel@tonic-gate gettext("Connection from unknown address family:%d"),
6210Sstevel@tonic-gate from.ss_family);
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate if (debug) {
6240Sstevel@tonic-gate printf(gettext("Connection from unknown address family:%d"),
6250Sstevel@tonic-gate from.ss_family);
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * Now do the authentication
6310Sstevel@tonic-gate */
6328714SMark.Phalan@Sun.COM /* Solaris Kerberos */
6338714SMark.Phalan@Sun.COM kerberos_authenticate(doit_context, fd, &client, &etype, &from);
6340Sstevel@tonic-gate
635*9033SPeter.Shoults@Sun.COM /*
636*9033SPeter.Shoults@Sun.COM * Turn off alarm upon successful authentication from master.
637*9033SPeter.Shoults@Sun.COM */
638*9033SPeter.Shoults@Sun.COM alarm(0);
639*9033SPeter.Shoults@Sun.COM gfd = -1;
640*9033SPeter.Shoults@Sun.COM
6410Sstevel@tonic-gate if (!authorized_principal(doit_context, client, etype)) {
6422881Smp153739 char *name;
6430Sstevel@tonic-gate
6442881Smp153739 retval = krb5_unparse_name(doit_context, client, &name);
6452881Smp153739 if (retval) {
6466426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
6472881Smp153739 com_err(progname, retval,
6486426Smp153739 gettext("while unparsing client name"));
6492881Smp153739 exit(1);
6502881Smp153739 }
6512881Smp153739 syslog(LOG_WARNING,
6522881Smp153739 gettext("Rejected connection from unauthorized principal %s"),
6532881Smp153739 name);
6542881Smp153739 free(name);
6550Sstevel@tonic-gate exit(1);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate omask = umask(077);
6580Sstevel@tonic-gate lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
6590Sstevel@tonic-gate (void) umask(omask);
6600Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd,
6610Sstevel@tonic-gate KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
6620Sstevel@tonic-gate if (retval) {
6630Sstevel@tonic-gate com_err(progname, retval,
6640Sstevel@tonic-gate gettext("while trying to lock '%s'"),
6650Sstevel@tonic-gate temp_file_name);
6660Sstevel@tonic-gate exit(1);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate if ((database_fd = open(temp_file_name,
6690Sstevel@tonic-gate O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
6700Sstevel@tonic-gate com_err(progname, errno,
6710Sstevel@tonic-gate gettext("while opening database file, '%s'"),
6720Sstevel@tonic-gate temp_file_name);
6730Sstevel@tonic-gate exit(1);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate recv_database(doit_context, fd, database_fd, &confmsg);
6760Sstevel@tonic-gate if (rename(temp_file_name, file)) {
6776426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
6780Sstevel@tonic-gate com_err(progname, errno,
6796426Smp153739 gettext("while renaming %s to %s"),
6800Sstevel@tonic-gate temp_file_name, file);
6810Sstevel@tonic-gate exit(1);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_SHARED);
6840Sstevel@tonic-gate if (retval) {
6850Sstevel@tonic-gate com_err(progname, retval,
6860Sstevel@tonic-gate gettext("while downgrading lock on '%s'"),
6870Sstevel@tonic-gate temp_file_name);
6880Sstevel@tonic-gate exit(1);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate load_database(doit_context, kdb5_util, file);
6910Sstevel@tonic-gate retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
6920Sstevel@tonic-gate if (retval) {
6930Sstevel@tonic-gate com_err(progname, retval,
6940Sstevel@tonic-gate gettext("while unlocking '%s'"), temp_file_name);
6950Sstevel@tonic-gate exit(1);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate (void)close(lock_fd);
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate * Send the acknowledgement message generated in
7010Sstevel@tonic-gate * recv_database, then close the socket.
7020Sstevel@tonic-gate */
7032881Smp153739 retval = krb5_write_message(doit_context, (void *) &fd, &confmsg);
7042881Smp153739 if (retval) {
7050Sstevel@tonic-gate krb5_free_data_contents(doit_context, &confmsg);
7060Sstevel@tonic-gate com_err(progname, retval,
7070Sstevel@tonic-gate gettext("while sending # of received bytes"));
7080Sstevel@tonic-gate exit(1);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate krb5_free_data_contents(doit_context, &confmsg);
7110Sstevel@tonic-gate if (close(fd) < 0) {
7120Sstevel@tonic-gate com_err(progname, errno,
7130Sstevel@tonic-gate gettext("while trying to close database file"));
7140Sstevel@tonic-gate exit(1);
7150Sstevel@tonic-gate }
7162881Smp153739
7170Sstevel@tonic-gate exit(0);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate /*
7220Sstevel@tonic-gate * Routine to handle incremental update transfer(s) from master KDC
7230Sstevel@tonic-gate */
do_iprop(kdb_log_context * log_ctx)7240Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx) {
7250Sstevel@tonic-gate CLIENT *cl;
7260Sstevel@tonic-gate kadm5_ret_t retval;
7270Sstevel@tonic-gate kadm5_config_params params;
7280Sstevel@tonic-gate krb5_ccache cc;
7290Sstevel@tonic-gate krb5_principal iprop_svc_principal;
7300Sstevel@tonic-gate void *server_handle = NULL;
7310Sstevel@tonic-gate char *iprop_svc_princstr = NULL;
7320Sstevel@tonic-gate char *master_svc_princstr = NULL;
7330Sstevel@tonic-gate char *admin_server = NULL;
7340Sstevel@tonic-gate char *keytab_name = NULL;
7350Sstevel@tonic-gate unsigned int pollin, backoff_time;
7360Sstevel@tonic-gate int backoff_cnt = 0;
7370Sstevel@tonic-gate int reinit_cnt = 0;
7380Sstevel@tonic-gate int ret;
7390Sstevel@tonic-gate boolean_t frdone = B_FALSE;
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate kdb_incr_result_t *incr_ret;
7420Sstevel@tonic-gate static kdb_last_t mylast;
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate kdb_fullresync_result_t *full_ret;
7450Sstevel@tonic-gate char *full_resync_arg = NULL;
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate kadm5_iprop_handle_t handle;
7480Sstevel@tonic-gate kdb_hlog_t *ulog;
7490Sstevel@tonic-gate
7506426Smp153739 krb5_keytab kt;
7516426Smp153739 krb5_keytab_entry entry;
7526426Smp153739 char kt_name[MAX_KEYTAB_NAME_LEN];
7536426Smp153739
7546426Smp153739 /*
7556426Smp153739 * Solaris Kerberos:
7566426Smp153739 * Delay daemonizing until some basic configuration checks have been
7576426Smp153739 * performed
7586426Smp153739 */
7596426Smp153739 #if 0
7600Sstevel@tonic-gate if (!debug)
7610Sstevel@tonic-gate daemon(0, 0);
7626426Smp153739 #endif
7630Sstevel@tonic-gate pollin = (unsigned int)0;
7640Sstevel@tonic-gate (void) memset((char *)¶ms, 0, sizeof (params));
7650Sstevel@tonic-gate ulog = log_ctx->ulog;
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM;
7680Sstevel@tonic-gate params.realm = def_realm;
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate if (master_svc_princstr == NULL) {
7710Sstevel@tonic-gate if (retval = kadm5_get_kiprop_host_srv_name(kpropd_context,
7720Sstevel@tonic-gate def_realm, &master_svc_princstr)) {
7736426Smp153739 /* Solaris Kerberos: keep error messages consistent */
7740Sstevel@tonic-gate com_err(progname, retval,
7756426Smp153739 gettext("while getting kiprop host based "
7766426Smp153739 "service name for realm %s"), def_realm);
7770Sstevel@tonic-gate exit(1);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate * Set cc to the default credentials cache
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate if (retval = krb5_cc_default(kpropd_context, &cc)) {
7850Sstevel@tonic-gate com_err(progname, retval,
7860Sstevel@tonic-gate gettext("while opening default "
7870Sstevel@tonic-gate "credentials cache"));
7880Sstevel@tonic-gate exit(1);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
7920Sstevel@tonic-gate KRB5_NT_SRV_HST, &iprop_svc_principal);
7930Sstevel@tonic-gate if (retval) {
7940Sstevel@tonic-gate com_err(progname, retval, gettext("while trying to construct "
7950Sstevel@tonic-gate "host service principal"));
7960Sstevel@tonic-gate exit(1);
7970Sstevel@tonic-gate }
7980Sstevel@tonic-gate
7997934SMark.Phalan@Sun.COM /* Solaris Kerberos */
8007934SMark.Phalan@Sun.COM if (krb5_is_referral_realm(krb5_princ_realm(kpropd_context,
8017934SMark.Phalan@Sun.COM iprop_svc_principal))) {
8027934SMark.Phalan@Sun.COM krb5_data *r = krb5_princ_realm(kpropd_context,
8037934SMark.Phalan@Sun.COM iprop_svc_principal);
8047934SMark.Phalan@Sun.COM assert(def_realm != NULL);
8057934SMark.Phalan@Sun.COM r->length = strlen(def_realm);
8067934SMark.Phalan@Sun.COM r->data = strdup(def_realm);
8077934SMark.Phalan@Sun.COM if (r->data == NULL) {
8087934SMark.Phalan@Sun.COM com_err(progname, retval,
8097934SMark.Phalan@Sun.COM ("while determining local service principal name"));
8107934SMark.Phalan@Sun.COM exit(1);
8117934SMark.Phalan@Sun.COM }
8127934SMark.Phalan@Sun.COM }
8137934SMark.Phalan@Sun.COM
8140Sstevel@tonic-gate if (retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
8150Sstevel@tonic-gate &iprop_svc_princstr)) {
8160Sstevel@tonic-gate com_err(progname, retval,
8170Sstevel@tonic-gate gettext("while canonicalizing "
8180Sstevel@tonic-gate "principal name"));
8190Sstevel@tonic-gate krb5_free_principal(kpropd_context, iprop_svc_principal);
8200Sstevel@tonic-gate exit(1);
8210Sstevel@tonic-gate }
8226426Smp153739
8236426Smp153739 /*
8246426Smp153739 * Solaris Kerberos:
8256426Smp153739 * Check to see if kiprop/<fqdn>@REALM is in the keytab
8266426Smp153739 */
8276426Smp153739 kt_name[0] = '\0';
8286426Smp153739 if (retval = krb5_kt_default_name(kpropd_context, kt_name,
8296426Smp153739 MAX_KEYTAB_NAME_LEN)){
8306426Smp153739 com_err(progname, retval, gettext ("while resolving the "
8316426Smp153739 "name of the default keytab"));
8326426Smp153739 }
8336426Smp153739
8346426Smp153739 if (retval = krb5_kt_default(kpropd_context, &kt)) {
8356426Smp153739 com_err(progname, retval, gettext ("while resolving default "
8366426Smp153739 "keytab"));
8376426Smp153739 krb5_free_principal(kpropd_context, iprop_svc_principal);
8386426Smp153739 exit(1);
8396426Smp153739 }
8406426Smp153739
8416426Smp153739 if (retval = krb5_kt_get_entry(kpropd_context, kt, iprop_svc_principal,
8426426Smp153739 0, 0, &entry)) {
8436426Smp153739 com_err(progname, retval, gettext("while retrieving entry %s "
8446426Smp153739 "from %s"), iprop_svc_princstr,
8456426Smp153739 kt_name[0] ? kt_name : "default keytab");
8466426Smp153739 krb5_kt_close(kpropd_context,kt);
8476426Smp153739 krb5_free_principal(kpropd_context, iprop_svc_principal);
8486426Smp153739 exit(1);
8496426Smp153739 }
8506426Smp153739
8516426Smp153739 krb5_kt_close(kpropd_context,kt);
8520Sstevel@tonic-gate krb5_free_principal(kpropd_context, iprop_svc_principal);
8530Sstevel@tonic-gate
8546426Smp153739 if (!debug) {
8556426Smp153739 /* Solaris Kerberos: Indicate where further messages will be sent */
8566426Smp153739 fprintf(stderr, gettext("%s: Logging to SYSLOG\n"), progname);
8576426Smp153739 if (daemon(0, 0)) {
8586426Smp153739 com_err(progname, errno, gettext("while daemonizing"));
8596426Smp153739 exit(1);
8606426Smp153739 }
8616426Smp153739 rem_default_com_err_hook();
8626426Smp153739 }
8636426Smp153739
8640Sstevel@tonic-gate reinit:
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate * Authentication, initialize rpcsec_gss handle etc.
8670Sstevel@tonic-gate */
8680Sstevel@tonic-gate retval = kadm5_init_with_skey(iprop_svc_princstr, keytab_name,
8690Sstevel@tonic-gate master_svc_princstr,
8700Sstevel@tonic-gate ¶ms,
8710Sstevel@tonic-gate KADM5_STRUCT_VERSION,
8720Sstevel@tonic-gate KADM5_API_VERSION_2,
8734960Swillf NULL,
8740Sstevel@tonic-gate &server_handle);
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate if (retval) {
8770Sstevel@tonic-gate if (retval == KADM5_RPC_ERROR) {
8780Sstevel@tonic-gate reinit_cnt++;
8790Sstevel@tonic-gate if (server_handle)
8800Sstevel@tonic-gate kadm5_destroy((void *) server_handle);
8810Sstevel@tonic-gate server_handle = (void *)NULL;
8820Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL;
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate com_err(progname, retval, gettext(
8850Sstevel@tonic-gate "while attempting to connect"
8860Sstevel@tonic-gate " to master KDC ... retrying"));
8870Sstevel@tonic-gate backoff_time = backoff_from_master(&reinit_cnt);
8880Sstevel@tonic-gate (void) sleep(backoff_time);
8890Sstevel@tonic-gate goto reinit;
8900Sstevel@tonic-gate } else {
8916426Smp153739 /* Solaris Kerberos: Be more verbose */
8920Sstevel@tonic-gate com_err(progname, retval,
8936426Smp153739 gettext("while initializing %s interface for "
8946426Smp153739 "%s"), progname, iprop_svc_princstr);
8950Sstevel@tonic-gate if (retval == KADM5_BAD_CLIENT_PARAMS ||
8960Sstevel@tonic-gate retval == KADM5_BAD_SERVER_PARAMS)
8970Sstevel@tonic-gate usage();
8980Sstevel@tonic-gate exit(1);
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate * Reset re-initialization count to zero now.
9040Sstevel@tonic-gate */
9050Sstevel@tonic-gate reinit_cnt = backoff_time = 0;
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate * Reset the handle to the correct type for the RPC call
9090Sstevel@tonic-gate */
9100Sstevel@tonic-gate handle = server_handle;
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate * If we have reached this far, we have succesfully established
9140Sstevel@tonic-gate * a RPCSEC_GSS connection; we now start polling for updates
9150Sstevel@tonic-gate */
9160Sstevel@tonic-gate if (poll_time == NULL) {
9170Sstevel@tonic-gate if ((poll_time = (char *)strdup("2m")) == NULL) {
9186426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
9190Sstevel@tonic-gate com_err(progname, ENOMEM,
9206426Smp153739 gettext("while allocating poll_time"));
9210Sstevel@tonic-gate exit(1);
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate if (pollin == (unsigned int)0)
9260Sstevel@tonic-gate pollin = convert_polltime(poll_time);
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate for (;;) {
9290Sstevel@tonic-gate incr_ret = NULL;
9300Sstevel@tonic-gate full_ret = NULL;
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate /*
9330Sstevel@tonic-gate * Get the most recent ulog entry sno + ts, which
9340Sstevel@tonic-gate * we package in the request to the master KDC
9350Sstevel@tonic-gate */
9360Sstevel@tonic-gate mylast.last_sno = ulog->kdb_last_sno;
9370Sstevel@tonic-gate mylast.last_time = ulog->kdb_last_time;
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate * Loop continuously on an iprop_get_updates_1(),
9410Sstevel@tonic-gate * so that we can keep probing the master for updates
9420Sstevel@tonic-gate * or (if needed) do a full resync of the krb5 db.
9430Sstevel@tonic-gate */
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate incr_ret = iprop_get_updates_1(&mylast, handle->clnt);
9460Sstevel@tonic-gate if (incr_ret == (kdb_incr_result_t *)NULL) {
9470Sstevel@tonic-gate clnt_perror(handle->clnt,
9480Sstevel@tonic-gate "iprop_get_updates call failed");
9490Sstevel@tonic-gate if (server_handle)
9500Sstevel@tonic-gate kadm5_destroy((void *)server_handle);
9510Sstevel@tonic-gate server_handle = (void *)NULL;
9520Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL;
9530Sstevel@tonic-gate goto reinit;
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate switch (incr_ret->ret) {
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate case UPDATE_FULL_RESYNC_NEEDED:
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate * We dont do a full resync again, if the last
9610Sstevel@tonic-gate * X'fer was a resync and if the master sno is
9620Sstevel@tonic-gate * still "0", i.e. no updates so far.
9630Sstevel@tonic-gate */
9640Sstevel@tonic-gate if ((frdone == B_TRUE) && (incr_ret->lastentry.last_sno
9650Sstevel@tonic-gate == 0)) {
9660Sstevel@tonic-gate break;
9670Sstevel@tonic-gate } else {
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate full_ret = iprop_full_resync_1((void *)
9700Sstevel@tonic-gate &full_resync_arg, handle->clnt);
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate if (full_ret == (kdb_fullresync_result_t *)
9730Sstevel@tonic-gate NULL) {
9740Sstevel@tonic-gate clnt_perror(handle->clnt,
9750Sstevel@tonic-gate "iprop_full_resync call failed");
9760Sstevel@tonic-gate if (server_handle)
9770Sstevel@tonic-gate kadm5_destroy((void *)
9780Sstevel@tonic-gate server_handle);
9790Sstevel@tonic-gate server_handle = (void *)NULL;
9800Sstevel@tonic-gate handle = (kadm5_iprop_handle_t)NULL;
9810Sstevel@tonic-gate goto reinit;
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate switch (full_ret->ret) {
9860Sstevel@tonic-gate case UPDATE_OK:
9870Sstevel@tonic-gate backoff_cnt = 0;
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate * We now listen on the kprop port for
9900Sstevel@tonic-gate * the full dump
9910Sstevel@tonic-gate */
9920Sstevel@tonic-gate ret = do_standalone(log_ctx->iproprole);
9930Sstevel@tonic-gate if (debug)
9940Sstevel@tonic-gate if (ret)
9950Sstevel@tonic-gate fprintf(stderr,
9960Sstevel@tonic-gate gettext("Full resync "
9970Sstevel@tonic-gate "was unsuccessful\n"));
9980Sstevel@tonic-gate else
9990Sstevel@tonic-gate fprintf(stderr,
10000Sstevel@tonic-gate gettext("Full resync "
10010Sstevel@tonic-gate "was successful\n"));
1002*9033SPeter.Shoults@Sun.COM if (ret) {
1003*9033SPeter.Shoults@Sun.COM syslog(LOG_WARNING,
1004*9033SPeter.Shoults@Sun.COM gettext("kpropd: Full resync, "
1005*9033SPeter.Shoults@Sun.COM "invalid return."));
1006*9033SPeter.Shoults@Sun.COM /*
1007*9033SPeter.Shoults@Sun.COM * Start backing-off immediately after
1008*9033SPeter.Shoults@Sun.COM * failure.
1009*9033SPeter.Shoults@Sun.COM */
1010*9033SPeter.Shoults@Sun.COM backoff_cnt++;
1011*9033SPeter.Shoults@Sun.COM frdone = B_FALSE;
1012*9033SPeter.Shoults@Sun.COM } else
1013*9033SPeter.Shoults@Sun.COM frdone = B_TRUE;
10140Sstevel@tonic-gate break;
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate case UPDATE_BUSY:
10170Sstevel@tonic-gate /*
10180Sstevel@tonic-gate * Exponential backoff
10190Sstevel@tonic-gate */
10200Sstevel@tonic-gate backoff_cnt++;
10210Sstevel@tonic-gate break;
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate case UPDATE_FULL_RESYNC_NEEDED:
10240Sstevel@tonic-gate case UPDATE_NIL:
10250Sstevel@tonic-gate default:
10260Sstevel@tonic-gate backoff_cnt = 0;
10270Sstevel@tonic-gate frdone = B_FALSE;
10280Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync,"
10290Sstevel@tonic-gate " invalid return from master KDC."));
10300Sstevel@tonic-gate break;
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate case UPDATE_PERM_DENIED:
10330Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync,"
10340Sstevel@tonic-gate " permission denied."));
10350Sstevel@tonic-gate goto error;
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate case UPDATE_ERROR:
10380Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: Full resync,"
10390Sstevel@tonic-gate " error returned from master KDC."));
10400Sstevel@tonic-gate goto error;
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate break;
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate case UPDATE_OK:
10450Sstevel@tonic-gate backoff_cnt = 0;
10460Sstevel@tonic-gate frdone = B_FALSE;
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate * ulog_replay() will convert the ulog updates to db
10500Sstevel@tonic-gate * entries using the kdb conv api and will commit
10510Sstevel@tonic-gate * the entries to the slave kdc database
10520Sstevel@tonic-gate */
10530Sstevel@tonic-gate retval = ulog_replay(kpropd_context, incr_ret);
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate if (retval) {
10560Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: ulog_replay"
10570Sstevel@tonic-gate " failed, updates not registered."));
10580Sstevel@tonic-gate break;
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate if (debug)
10620Sstevel@tonic-gate fprintf(stderr, gettext("Update transfer "
10630Sstevel@tonic-gate "from master was OK\n"));
10640Sstevel@tonic-gate break;
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate case UPDATE_PERM_DENIED:
10670Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates,"
10680Sstevel@tonic-gate " permission denied."));
10690Sstevel@tonic-gate goto error;
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate case UPDATE_ERROR:
10720Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates, error "
10730Sstevel@tonic-gate "returned from master KDC."));
10740Sstevel@tonic-gate goto error;
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate case UPDATE_BUSY:
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate * Exponential backoff
10790Sstevel@tonic-gate */
10800Sstevel@tonic-gate backoff_cnt++;
10810Sstevel@tonic-gate break;
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate case UPDATE_NIL:
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate * Master-slave are in sync
10860Sstevel@tonic-gate */
10870Sstevel@tonic-gate if (debug)
10880Sstevel@tonic-gate fprintf(stderr, gettext("Master, slave KDC's "
10890Sstevel@tonic-gate "are in-sync, no updates\n"));
10900Sstevel@tonic-gate backoff_cnt = 0;
10910Sstevel@tonic-gate frdone = B_FALSE;
10920Sstevel@tonic-gate break;
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate default:
10950Sstevel@tonic-gate backoff_cnt = 0;
10960Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: get_updates,"
10970Sstevel@tonic-gate " invalid return from master KDC."));
10980Sstevel@tonic-gate break;
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate if (runonce == B_TRUE)
11020Sstevel@tonic-gate goto done;
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate * Sleep for the specified poll interval (Default is 2 mts),
11060Sstevel@tonic-gate * or do a binary exponential backoff if we get an
11070Sstevel@tonic-gate * UPDATE_BUSY signal
11080Sstevel@tonic-gate */
11090Sstevel@tonic-gate if (backoff_cnt > 0) {
11100Sstevel@tonic-gate backoff_time = backoff_from_master(&backoff_cnt);
11110Sstevel@tonic-gate if (debug)
11120Sstevel@tonic-gate fprintf(stderr, gettext("Busy signal received "
11130Sstevel@tonic-gate "from master, backoff for %d secs\n"),
11140Sstevel@tonic-gate backoff_time);
11150Sstevel@tonic-gate (void) sleep(backoff_time);
11160Sstevel@tonic-gate }
11170Sstevel@tonic-gate else
11180Sstevel@tonic-gate (void) sleep(pollin);
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate error:
11240Sstevel@tonic-gate if (debug)
11250Sstevel@tonic-gate fprintf(stderr, gettext("ERROR returned by master, bailing\n"));
11260Sstevel@tonic-gate syslog(LOG_ERR, gettext("kpropd: ERROR returned by master KDC,"
11270Sstevel@tonic-gate " bailing.\n"));
11280Sstevel@tonic-gate done:
11290Sstevel@tonic-gate if (poll_time)
11300Sstevel@tonic-gate free(poll_time);
11310Sstevel@tonic-gate if(iprop_svc_princstr)
11320Sstevel@tonic-gate free(iprop_svc_princstr);
11330Sstevel@tonic-gate if (master_svc_princstr)
11340Sstevel@tonic-gate free(master_svc_princstr);
11350Sstevel@tonic-gate if (retval = krb5_cc_close(kpropd_context, cc)) {
11360Sstevel@tonic-gate com_err(progname, retval,
11370Sstevel@tonic-gate gettext("while closing default ccache"));
11380Sstevel@tonic-gate exit(1);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate if (def_realm)
11410Sstevel@tonic-gate free(def_realm);
11420Sstevel@tonic-gate if (server_handle)
11430Sstevel@tonic-gate kadm5_destroy((void *)server_handle);
11440Sstevel@tonic-gate if (kpropd_context)
11450Sstevel@tonic-gate krb5_free_context(kpropd_context);
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate if (runonce == B_TRUE)
11480Sstevel@tonic-gate return (0);
11490Sstevel@tonic-gate else
11500Sstevel@tonic-gate exit(1);
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate * Do exponential backoff, since master KDC is BUSY or down
11560Sstevel@tonic-gate */
backoff_from_master(int * cnt)11570Sstevel@tonic-gate unsigned int backoff_from_master(int *cnt) {
11580Sstevel@tonic-gate unsigned int btime;
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate btime = (unsigned int)(2<<(*cnt));
11610Sstevel@tonic-gate if (btime > MAX_BACKOFF) {
11620Sstevel@tonic-gate btime = MAX_BACKOFF;
11630Sstevel@tonic-gate *cnt--;
11640Sstevel@tonic-gate }
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate return (btime);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate /*
11710Sstevel@tonic-gate * Routine to convert the `pollstr' string to seconds
11720Sstevel@tonic-gate */
convert_polltime(char * pollstr)11730Sstevel@tonic-gate int convert_polltime(char *pollstr) {
11740Sstevel@tonic-gate char *tokenptr = NULL;
11750Sstevel@tonic-gate int len, polltime;
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate len = polltime = 0;
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate if ((len = strcspn(pollstr, "s")) < strlen(pollstr)) {
11800Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char));
11810Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1);
11820Sstevel@tonic-gate polltime = atoi(tokenptr);
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate if ((len = strcspn(pollstr, "m")) < strlen(pollstr)) {
11860Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char));
11870Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1);
11880Sstevel@tonic-gate polltime = atoi(tokenptr) * 60;
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate if ((len = strcspn(pollstr, "h")) < strlen(pollstr)) {
11920Sstevel@tonic-gate tokenptr = malloc((len + 1) * sizeof(char));
11930Sstevel@tonic-gate (void) strlcpy(tokenptr, pollstr, len + 1);
11940Sstevel@tonic-gate polltime = atoi(tokenptr) * 3600;
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate if (tokenptr != NULL)
11980Sstevel@tonic-gate free(tokenptr);
11990Sstevel@tonic-gate /*
12000Sstevel@tonic-gate * If we have a bogus pollstr value, set polltime to the
12010Sstevel@tonic-gate * default of 2 mts (120 seconds).
12020Sstevel@tonic-gate */
12030Sstevel@tonic-gate if (polltime == 0)
12040Sstevel@tonic-gate polltime = 120;
12050Sstevel@tonic-gate return (polltime);
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate static void
kpropd_com_err_proc(whoami,code,fmt,args)12090Sstevel@tonic-gate kpropd_com_err_proc(whoami, code, fmt, args)
12100Sstevel@tonic-gate const char *whoami;
12110Sstevel@tonic-gate long code;
12120Sstevel@tonic-gate const char *fmt;
12130Sstevel@tonic-gate va_list args;
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate char error_buf[8096];
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate error_buf[0] = '\0';
12180Sstevel@tonic-gate if (fmt)
12190Sstevel@tonic-gate vsprintf(error_buf, fmt, args);
12200Sstevel@tonic-gate syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
12210Sstevel@tonic-gate code ? error_message(code) : "", code ? " " : "", error_buf);
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate
PRS(argc,argv)12240Sstevel@tonic-gate void PRS(argc,argv)
12250Sstevel@tonic-gate int argc;
12260Sstevel@tonic-gate char **argv;
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate register char *word, ch;
12290Sstevel@tonic-gate char *cp;
12300Sstevel@tonic-gate int c;
12310Sstevel@tonic-gate struct hostent *hp;
12320Sstevel@tonic-gate char my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ];
12330Sstevel@tonic-gate krb5_error_code retval;
12340Sstevel@tonic-gate static const char tmp[] = ".temp";
12350Sstevel@tonic-gate kadm5_config_params params;
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
12380Sstevel@tonic-gate
12390Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
12400Sstevel@tonic-gate #define TEXT_DOMAIN "KPROPD_TEST" /* Use this only if it weren't */
12410Sstevel@tonic-gate #endif
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate (void) memset((char *) ¶ms, 0, sizeof (params));
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate retval = krb5_init_context(&kpropd_context);
12480Sstevel@tonic-gate if (retval) {
12490Sstevel@tonic-gate com_err(argv[0], retval,
12500Sstevel@tonic-gate gettext("while initializing krb5"));
12510Sstevel@tonic-gate exit(1);
12520Sstevel@tonic-gate }
12536426Smp153739
12546426Smp153739 /* Solaris Kerberos: Sanitize progname */
12556426Smp153739 progname = basename(argv[0]);
12566426Smp153739
12570Sstevel@tonic-gate while ((c = getopt(argc, argv, "dtf:F:p:P:r:s:Sa:")) != EOF){
12580Sstevel@tonic-gate switch (c) {
12590Sstevel@tonic-gate case 'd':
12600Sstevel@tonic-gate debug++;
12610Sstevel@tonic-gate break;
12620Sstevel@tonic-gate case 't':
12630Sstevel@tonic-gate /*
12640Sstevel@tonic-gate * Undocumented option - for testing only.
12650Sstevel@tonic-gate *
12660Sstevel@tonic-gate * Option to run the kpropd server exactly
12670Sstevel@tonic-gate * once (this is true only if iprop is enabled).
12680Sstevel@tonic-gate */
12690Sstevel@tonic-gate runonce = B_TRUE;
12700Sstevel@tonic-gate break;
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate case 'f':
12730Sstevel@tonic-gate file = optarg;
12740Sstevel@tonic-gate if (!file)
12750Sstevel@tonic-gate usage();
12760Sstevel@tonic-gate break;
12770Sstevel@tonic-gate case 'F':
12780Sstevel@tonic-gate kerb_database = optarg;
12790Sstevel@tonic-gate if (!kerb_database)
12800Sstevel@tonic-gate usage();
12810Sstevel@tonic-gate break;
12820Sstevel@tonic-gate case 'p':
12830Sstevel@tonic-gate kdb5_util = optarg;
12840Sstevel@tonic-gate if (!kdb5_util)
12850Sstevel@tonic-gate usage();
12860Sstevel@tonic-gate break;
12870Sstevel@tonic-gate case 'P':
12880Sstevel@tonic-gate port = htons(atoi(optarg));
12890Sstevel@tonic-gate if (!port)
12900Sstevel@tonic-gate usage();
12910Sstevel@tonic-gate break;
12920Sstevel@tonic-gate case 'r':
12930Sstevel@tonic-gate realm = optarg;
12940Sstevel@tonic-gate if (!realm)
12950Sstevel@tonic-gate usage();
12960Sstevel@tonic-gate params.realm = realm;
12970Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM;
12980Sstevel@tonic-gate break;
12990Sstevel@tonic-gate case 's':
13000Sstevel@tonic-gate srvtab = optarg;
13010Sstevel@tonic-gate if (!srvtab)
13020Sstevel@tonic-gate usage();
13030Sstevel@tonic-gate break;
13040Sstevel@tonic-gate case 'S':
13050Sstevel@tonic-gate standalone++;
13060Sstevel@tonic-gate break;
13070Sstevel@tonic-gate case 'a':
13080Sstevel@tonic-gate acl_file_name = optarg;
13090Sstevel@tonic-gate if (!acl_file_name)
13100Sstevel@tonic-gate usage();
13110Sstevel@tonic-gate break;
13120Sstevel@tonic-gate case '?':
13130Sstevel@tonic-gate default:
13140Sstevel@tonic-gate usage();
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate /*
13190Sstevel@tonic-gate * If not in debug mode, switch com_err reporting to syslog
13200Sstevel@tonic-gate */
13210Sstevel@tonic-gate if (! debug) {
13220Sstevel@tonic-gate openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
13236426Smp153739 /*
13246426Smp153739 * Solaris Kerberos:
13256426Smp153739 * Don't replace default logging. Add a new logging channel.
13266426Smp153739 * Stop logging to stderr when daemonizing
13276426Smp153739 */
13286426Smp153739 add_com_err_hook(kpropd_com_err_proc);
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate /*
13310Sstevel@tonic-gate * Get my hostname, so we can construct my service name
13320Sstevel@tonic-gate */
13330Sstevel@tonic-gate retval = krb5_sname_to_principal(kpropd_context,
13340Sstevel@tonic-gate NULL, KPROP_SERVICE_NAME,
13350Sstevel@tonic-gate KRB5_NT_SRV_HST, &server);
13360Sstevel@tonic-gate if (retval) {
13376426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
13380Sstevel@tonic-gate com_err(progname, retval,
13396426Smp153739 gettext("while trying to construct my service name"));
13400Sstevel@tonic-gate exit(1);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate if (realm) {
13432881Smp153739 retval = krb5_set_principal_realm(kpropd_context, server, realm);
13442881Smp153739 if (retval) {
13452881Smp153739 com_err(progname, errno,
13462881Smp153739 gettext("while constructing my service realm"));
13472881Smp153739 exit(1);
13482881Smp153739 }
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate * Construct the name of the temporary file.
13520Sstevel@tonic-gate */
13530Sstevel@tonic-gate if ((temp_file_name = (char *) malloc(strlen(file) +
13540Sstevel@tonic-gate strlen(tmp) + 1)) == NULL) {
13550Sstevel@tonic-gate com_err(progname, ENOMEM,
13560Sstevel@tonic-gate gettext("while allocating filename for temp file"));
13570Sstevel@tonic-gate exit(1);
13580Sstevel@tonic-gate }
13590Sstevel@tonic-gate strcpy(temp_file_name, file);
13600Sstevel@tonic-gate strcat(temp_file_name, tmp);
13610Sstevel@tonic-gate
13627934SMark.Phalan@Sun.COM retval = kadm5_get_config_params(kpropd_context, 1, NULL, ¶ms,
13630Sstevel@tonic-gate ¶ms);
13640Sstevel@tonic-gate if (retval) {
13650Sstevel@tonic-gate com_err(progname, retval, gettext("while initializing"));
13660Sstevel@tonic-gate exit(1);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate if (params.iprop_enabled == TRUE) {
13690Sstevel@tonic-gate ulog_set_role(kpropd_context, IPROP_SLAVE);
13700Sstevel@tonic-gate poll_time = params.iprop_polltime;
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate if (ulog_map(kpropd_context, ¶ms, FKPROPD)) {
13736426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
13740Sstevel@tonic-gate com_err(progname, errno,
13756426Smp153739 gettext("while mapping log"));
13760Sstevel@tonic-gate exit(1);
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /*
13810Sstevel@tonic-gate * Grab the realm info and check if iprop is enabled.
13820Sstevel@tonic-gate */
13830Sstevel@tonic-gate if (def_realm == NULL) {
13840Sstevel@tonic-gate retval = krb5_get_default_realm(kpropd_context, &def_realm);
13850Sstevel@tonic-gate if (retval) {
13866426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
13870Sstevel@tonic-gate com_err(progname, retval,
13886426Smp153739 gettext("while retrieving default realm"));
13890Sstevel@tonic-gate exit(1);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate
13940Sstevel@tonic-gate /*
13950Sstevel@tonic-gate * Figure out who's calling on the other end of the connection....
13960Sstevel@tonic-gate */
13978714SMark.Phalan@Sun.COM /* Solaris Kerberos */
13980Sstevel@tonic-gate void
kerberos_authenticate(context,fd,clientp,etype,ss)13990Sstevel@tonic-gate kerberos_authenticate(context, fd, clientp, etype, ss)
14000Sstevel@tonic-gate krb5_context context;
14010Sstevel@tonic-gate int fd;
14020Sstevel@tonic-gate krb5_principal * clientp;
14030Sstevel@tonic-gate krb5_enctype * etype;
14048714SMark.Phalan@Sun.COM struct sockaddr_storage * ss;
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate krb5_error_code retval;
14070Sstevel@tonic-gate krb5_ticket * ticket;
14080Sstevel@tonic-gate struct sockaddr_storage r_ss;
14090Sstevel@tonic-gate int ss_length;
14100Sstevel@tonic-gate krb5_keytab keytab = NULL;
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate /*
14130Sstevel@tonic-gate * Set recv_addr and send_addr
14140Sstevel@tonic-gate */
14158714SMark.Phalan@Sun.COM /* Solaris Kerberos */
14168714SMark.Phalan@Sun.COM if (cvtkaddr(ss, &sender_addr) == NULL) {
14170Sstevel@tonic-gate com_err(progname, errno,
14180Sstevel@tonic-gate gettext("while converting socket address"));
14190Sstevel@tonic-gate exit(1);
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate
14220Sstevel@tonic-gate ss_length = sizeof (r_ss);
14230Sstevel@tonic-gate if (getsockname(fd, (struct sockaddr *) &r_ss, &ss_length)) {
14240Sstevel@tonic-gate com_err(progname, errno,
14250Sstevel@tonic-gate gettext("while getting local socket address"));
14260Sstevel@tonic-gate exit(1);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate if (cvtkaddr(&r_ss, &receiver_addr) == NULL) {
14300Sstevel@tonic-gate com_err(progname, errno,
14310Sstevel@tonic-gate gettext("while converting socket address"));
14320Sstevel@tonic-gate exit(1);
14330Sstevel@tonic-gate }
14340Sstevel@tonic-gate
14350Sstevel@tonic-gate if (debug) {
14360Sstevel@tonic-gate char *name;
14372881Smp153739
14382881Smp153739 retval = krb5_unparse_name(context, server, &name);
14392881Smp153739 if (retval) {
14406426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
14416426Smp153739 com_err(progname, retval, gettext("while unparsing server name"));
14420Sstevel@tonic-gate exit(1);
14430Sstevel@tonic-gate }
14440Sstevel@tonic-gate printf(gettext("krb5_recvauth(%d, %s, %s, ...)\n"), fd, kprop_version,
14450Sstevel@tonic-gate name);
14460Sstevel@tonic-gate free(name);
14470Sstevel@tonic-gate }
14480Sstevel@tonic-gate
14492881Smp153739 retval = krb5_auth_con_init(context, &auth_context);
14502881Smp153739 if (retval) {
14510Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_init: %s"),
14522881Smp153739 error_message(retval));
14530Sstevel@tonic-gate exit(1);
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate
14562881Smp153739 retval = krb5_auth_con_setflags(context, auth_context,
14572881Smp153739 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
14582881Smp153739 if (retval) {
14590Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_setflags: %s"),
14600Sstevel@tonic-gate error_message(retval));
14610Sstevel@tonic-gate exit(1);
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate
14642881Smp153739 retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr,
14652881Smp153739 &sender_addr);
14662881Smp153739 if (retval) {
14670Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_auth_con_setaddrs: %s"),
14680Sstevel@tonic-gate error_message(retval));
14690Sstevel@tonic-gate exit(1);
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate if (srvtab) {
14732881Smp153739 retval = krb5_kt_resolve(context, srvtab, &keytab);
14742881Smp153739 if (retval) {
14750Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_kt_resolve: %s"), error_message(retval));
14760Sstevel@tonic-gate exit(1);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate
14802881Smp153739 retval = krb5_recvauth(context, &auth_context, (void *) &fd,
14812881Smp153739 kprop_version, server, 0, keytab, &ticket);
14822881Smp153739 if (retval) {
14832881Smp153739 syslog(LOG_ERR, gettext("Error in krb5_recvauth: %s"), error_message(retval));
14840Sstevel@tonic-gate exit(1);
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate
14872881Smp153739 retval = krb5_copy_principal(context, ticket->enc_part2->client, clientp);
14882881Smp153739 if (retval) {
14890Sstevel@tonic-gate syslog(LOG_ERR, gettext("Error in krb5_copy_prinicpal: %s"),
14900Sstevel@tonic-gate error_message(retval));
14910Sstevel@tonic-gate exit(1);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate *etype = ticket->enc_part.enctype;
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate if (debug) {
14970Sstevel@tonic-gate char * name;
14980Sstevel@tonic-gate char etypebuf[100];
14990Sstevel@tonic-gate
15002881Smp153739 retval = krb5_unparse_name(context, *clientp, &name);
15012881Smp153739 if (retval) {
15026426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
15030Sstevel@tonic-gate com_err(progname, retval,
15046426Smp153739 gettext("while unparsing client name"));
15050Sstevel@tonic-gate exit(1);
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate
15082881Smp153739 retval = krb5_enctype_to_string(*etype, etypebuf, sizeof(etypebuf));
15092881Smp153739 if (retval) {
15106426Smp153739 /* Solaris Kerberos: Keep error messages consistent */
15116426Smp153739 com_err(progname, retval, gettext("while unparsing ticket etype"));
15120Sstevel@tonic-gate exit(1);
15130Sstevel@tonic-gate }
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate printf("authenticated client: %s (etype == %s)\n", name, etypebuf);
15160Sstevel@tonic-gate free(name);
15170Sstevel@tonic-gate }
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate krb5_free_ticket(context, ticket);
15200Sstevel@tonic-gate }
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate krb5_boolean
authorized_principal(context,p,auth_etype)15230Sstevel@tonic-gate authorized_principal(context, p, auth_etype)
15240Sstevel@tonic-gate krb5_context context;
15250Sstevel@tonic-gate krb5_principal p;
15260Sstevel@tonic-gate krb5_enctype auth_etype;
15270Sstevel@tonic-gate {
15280Sstevel@tonic-gate char *name, *ptr;
15290Sstevel@tonic-gate char buf[1024];
15300Sstevel@tonic-gate krb5_error_code retval;
15310Sstevel@tonic-gate FILE *acl_file;
15320Sstevel@tonic-gate int end;
15330Sstevel@tonic-gate krb5_enctype acl_etype;
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate retval = krb5_unparse_name(context, p, &name);
15360Sstevel@tonic-gate if (retval)
15370Sstevel@tonic-gate return FALSE;
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate acl_file = fopen(acl_file_name, "r");
15400Sstevel@tonic-gate if (!acl_file)
15410Sstevel@tonic-gate return FALSE;
15420Sstevel@tonic-gate
15430Sstevel@tonic-gate while (!feof(acl_file)) {
15440Sstevel@tonic-gate if (!fgets(buf, sizeof(buf), acl_file))
15450Sstevel@tonic-gate break;
15460Sstevel@tonic-gate end = strlen(buf) - 1;
15470Sstevel@tonic-gate if (buf[end] == '\n')
15480Sstevel@tonic-gate buf[end] = '\0';
15490Sstevel@tonic-gate if (!strncmp(name, buf, strlen(name))) {
15500Sstevel@tonic-gate ptr = buf+strlen(name);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /* if the next character is not whitespace or nul, then
15530Sstevel@tonic-gate the match is only partial. continue on to new lines. */
15542881Smp153739 if (*ptr && !isspace((int) *ptr))
15550Sstevel@tonic-gate continue;
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate /* otherwise, skip trailing whitespace */
15582881Smp153739 for (; *ptr && isspace((int) *ptr); ptr++) ;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate /* now, look for an etype string. if there isn't one,
15610Sstevel@tonic-gate return true. if there is an invalid string, continue.
15620Sstevel@tonic-gate If there is a valid string, return true only if it
15630Sstevel@tonic-gate matches the etype passed in, otherwise continue */
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate if ((*ptr) &&
15660Sstevel@tonic-gate ((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
15670Sstevel@tonic-gate (acl_etype != auth_etype)))
15680Sstevel@tonic-gate continue;
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate free(name);
15710Sstevel@tonic-gate fclose(acl_file);
15720Sstevel@tonic-gate return TRUE;
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate }
15750Sstevel@tonic-gate free(name);
15760Sstevel@tonic-gate fclose(acl_file);
15770Sstevel@tonic-gate return FALSE;
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate void
recv_database(context,fd,database_fd,confmsg)15810Sstevel@tonic-gate recv_database(context, fd, database_fd, confmsg)
15820Sstevel@tonic-gate krb5_context context;
15830Sstevel@tonic-gate int fd;
15840Sstevel@tonic-gate int database_fd;
15850Sstevel@tonic-gate krb5_data *confmsg;
15860Sstevel@tonic-gate {
15872881Smp153739 krb5_ui_4 database_size; /* This must be 4 bytes */
15880Sstevel@tonic-gate int received_size, n;
15890Sstevel@tonic-gate char buf[1024];
15900Sstevel@tonic-gate krb5_data inbuf, outbuf;
15910Sstevel@tonic-gate krb5_error_code retval;
15920Sstevel@tonic-gate
15930Sstevel@tonic-gate /*
15940Sstevel@tonic-gate * Receive and decode size from client
15950Sstevel@tonic-gate */
15962881Smp153739 retval = krb5_read_message(context, (void *) &fd, &inbuf);
15972881Smp153739 if (retval) {
15980Sstevel@tonic-gate send_error(context, fd, retval, gettext("while reading database size"));
15990Sstevel@tonic-gate com_err(progname, retval,
16000Sstevel@tonic-gate gettext("while reading size of database from client"));
16010Sstevel@tonic-gate exit(1);
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate if (krb5_is_krb_error(&inbuf))
16040Sstevel@tonic-gate recv_error(context, &inbuf);
16052881Smp153739 retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
16062881Smp153739 if (retval) {
16072881Smp153739 send_error(context, fd, retval, gettext(
16082881Smp153739 "while decoding database size"));
16090Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf);
16100Sstevel@tonic-gate com_err(progname, retval,
16110Sstevel@tonic-gate gettext("while decoding database size from client"));
16120Sstevel@tonic-gate exit(1);
16130Sstevel@tonic-gate }
16140Sstevel@tonic-gate memcpy((char *) &database_size, outbuf.data, sizeof(database_size));
16150Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf);
16160Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf);
16170Sstevel@tonic-gate database_size = ntohl(database_size);
16180Sstevel@tonic-gate
16192881Smp153739 /*
16202881Smp153739 * Initialize the initial vector.
16212881Smp153739 */
16222881Smp153739 retval = krb5_auth_con_initivector(context, auth_context);
16232881Smp153739 if (retval) {
16242881Smp153739 send_error(context, fd, retval, gettext(
16252881Smp153739 "failed while initializing i_vector"));
16262881Smp153739 com_err(progname, retval, gettext("while initializing i_vector"));
16272881Smp153739 exit(1);
16282881Smp153739 }
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate /*
16310Sstevel@tonic-gate * Now start receiving the database from the net
16320Sstevel@tonic-gate */
16330Sstevel@tonic-gate received_size = 0;
16340Sstevel@tonic-gate while (received_size < database_size) {
16352881Smp153739 retval = krb5_read_message(context, (void *) &fd, &inbuf);
16362881Smp153739 if (retval) {
16370Sstevel@tonic-gate snprintf(buf, sizeof (buf),
16380Sstevel@tonic-gate gettext("while reading database block starting at offset %d"),
16390Sstevel@tonic-gate received_size);
16400Sstevel@tonic-gate com_err(progname, retval, buf);
16410Sstevel@tonic-gate send_error(context, fd, retval, buf);
16420Sstevel@tonic-gate exit(1);
16430Sstevel@tonic-gate }
16440Sstevel@tonic-gate if (krb5_is_krb_error(&inbuf))
16450Sstevel@tonic-gate recv_error(context, &inbuf);
16462881Smp153739 retval = krb5_rd_priv(context, auth_context, &inbuf,
16472881Smp153739 &outbuf, NULL);
16482881Smp153739 if (retval) {
16490Sstevel@tonic-gate snprintf(buf, sizeof (buf),
16500Sstevel@tonic-gate gettext("while decoding database block starting at offset %d"),
16510Sstevel@tonic-gate received_size);
16520Sstevel@tonic-gate com_err(progname, retval, buf);
16530Sstevel@tonic-gate send_error(context, fd, retval, buf);
16540Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf);
16550Sstevel@tonic-gate exit(1);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate n = write(database_fd, outbuf.data, outbuf.length);
16580Sstevel@tonic-gate if (n < 0) {
16590Sstevel@tonic-gate snprintf(buf, sizeof (buf),
16600Sstevel@tonic-gate gettext(
16610Sstevel@tonic-gate "while writing database block starting at offset %d"),
16620Sstevel@tonic-gate received_size);
16630Sstevel@tonic-gate send_error(context, fd, errno, buf);
16640Sstevel@tonic-gate } else if (n != outbuf.length) {
16650Sstevel@tonic-gate snprintf(buf, sizeof (buf),
16660Sstevel@tonic-gate gettext(
16670Sstevel@tonic-gate "incomplete write while writing database block starting at\n"
16680Sstevel@tonic-gate "offset %d (%d written, %d expected)"),
16690Sstevel@tonic-gate received_size, n, outbuf.length);
16700Sstevel@tonic-gate send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
16710Sstevel@tonic-gate }
16720Sstevel@tonic-gate received_size += outbuf.length;
16730Sstevel@tonic-gate /* SUNWresync121: our krb5...contents sets length to 0 */
16740Sstevel@tonic-gate krb5_free_data_contents(context, &inbuf);
16750Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf);
16762881Smp153739
16770Sstevel@tonic-gate }
16780Sstevel@tonic-gate /*
16790Sstevel@tonic-gate * OK, we've seen the entire file. Did we get too many bytes?
16800Sstevel@tonic-gate */
16810Sstevel@tonic-gate if (received_size > database_size) {
16820Sstevel@tonic-gate snprintf(buf, sizeof (buf),
16830Sstevel@tonic-gate gettext("Received %d bytes, expected %d bytes for database file"),
16840Sstevel@tonic-gate received_size, database_size);
16850Sstevel@tonic-gate send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate /*
16880Sstevel@tonic-gate * Create message acknowledging number of bytes received, but
16890Sstevel@tonic-gate * don't send it until kdb5_util returns successfully.
16900Sstevel@tonic-gate */
16910Sstevel@tonic-gate database_size = htonl(database_size);
16920Sstevel@tonic-gate inbuf.data = (char *) &database_size;
16930Sstevel@tonic-gate inbuf.length = sizeof(database_size);
16942881Smp153739 retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
16952881Smp153739 if (retval) {
16960Sstevel@tonic-gate com_err(progname, retval,
16970Sstevel@tonic-gate gettext("while encoding # of receieved bytes"));
16980Sstevel@tonic-gate send_error(context, fd, retval,
16990Sstevel@tonic-gate gettext("while encoding # of received bytes"));
17000Sstevel@tonic-gate exit(1);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate void
send_error(context,fd,err_code,err_text)17060Sstevel@tonic-gate send_error(context, fd, err_code, err_text)
17070Sstevel@tonic-gate krb5_context context;
17080Sstevel@tonic-gate int fd;
17090Sstevel@tonic-gate krb5_error_code err_code;
17100Sstevel@tonic-gate char *err_text;
17110Sstevel@tonic-gate {
17120Sstevel@tonic-gate krb5_error error;
17130Sstevel@tonic-gate const char *text;
17140Sstevel@tonic-gate krb5_data outbuf;
17150Sstevel@tonic-gate char buf[1024];
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate memset((char *)&error, 0, sizeof(error));
17180Sstevel@tonic-gate krb5_us_timeofday(context, &error.stime, &error.susec);
17190Sstevel@tonic-gate error.server = server;
17200Sstevel@tonic-gate error.client = client;
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate if (err_text)
17230Sstevel@tonic-gate text = err_text;
17240Sstevel@tonic-gate else
17250Sstevel@tonic-gate text = error_message(err_code);
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate error.error = err_code - ERROR_TABLE_BASE_krb5;
17280Sstevel@tonic-gate if (error.error > 127) {
17290Sstevel@tonic-gate error.error = KRB_ERR_GENERIC;
17300Sstevel@tonic-gate if (err_text) {
17310Sstevel@tonic-gate sprintf(buf, "%s %s", error_message(err_code),
17320Sstevel@tonic-gate err_text);
17330Sstevel@tonic-gate text = buf;
17340Sstevel@tonic-gate }
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate error.text.length = strlen(text) + 1;
17372881Smp153739 error.text.data = malloc(error.text.length);
17382881Smp153739 if (error.text.data) {
17390Sstevel@tonic-gate strcpy(error.text.data, text);
17400Sstevel@tonic-gate if (!krb5_mk_error(context, &error, &outbuf)) {
17410Sstevel@tonic-gate (void) krb5_write_message(context, (void *)&fd,&outbuf);
17420Sstevel@tonic-gate krb5_free_data_contents(context, &outbuf);
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate free(error.text.data);
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate void
recv_error(context,inbuf)17490Sstevel@tonic-gate recv_error(context, inbuf)
17500Sstevel@tonic-gate krb5_context context;
17510Sstevel@tonic-gate krb5_data *inbuf;
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate krb5_error *error;
17540Sstevel@tonic-gate krb5_error_code retval;
17550Sstevel@tonic-gate
17562881Smp153739 retval = krb5_rd_error(context, inbuf, &error);
17572881Smp153739 if (retval) {
17580Sstevel@tonic-gate com_err(progname, retval,
17590Sstevel@tonic-gate gettext("while decoding error packet from client"));
17600Sstevel@tonic-gate exit(1);
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate if (error->error == KRB_ERR_GENERIC) {
17630Sstevel@tonic-gate if (error->text.data)
17640Sstevel@tonic-gate fprintf(stderr,
17650Sstevel@tonic-gate gettext("Generic remote error: %s\n"),
17660Sstevel@tonic-gate error->text.data);
17670Sstevel@tonic-gate } else if (error->error) {
17680Sstevel@tonic-gate com_err(progname, error->error + ERROR_TABLE_BASE_krb5,
1769*9033SPeter.Shoults@Sun.COM gettext("signaled from server"));
17700Sstevel@tonic-gate if (error->text.data)
17710Sstevel@tonic-gate fprintf(stderr,
17720Sstevel@tonic-gate gettext("Error text from client: %s\n"),
17730Sstevel@tonic-gate error->text.data);
17740Sstevel@tonic-gate }
17750Sstevel@tonic-gate krb5_free_error(context, error);
17760Sstevel@tonic-gate exit(1);
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate void
load_database(context,kdb_util,database_file_name)17802881Smp153739 load_database(context, kdb_util, database_file_name)
17810Sstevel@tonic-gate krb5_context context;
17822881Smp153739 char *kdb_util;
17830Sstevel@tonic-gate char *database_file_name;
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate static char *edit_av[10];
17862881Smp153739 int error_ret, save_stderr = -1;
17870Sstevel@tonic-gate int child_pid;
17880Sstevel@tonic-gate int count;
17892881Smp153739
17902881Smp153739 /* <sys/param.h> has been included, so BSD will be defined on
17912881Smp153739 BSD systems */
17922881Smp153739 #if BSD > 0 && BSD <= 43
17932881Smp153739 #ifndef WEXITSTATUS
17942881Smp153739 #define WEXITSTATUS(w) (w).w_retcode
17952881Smp153739 #endif
17962881Smp153739 union wait waitb;
17972881Smp153739 #else
17980Sstevel@tonic-gate int waitb;
17992881Smp153739 #endif
18000Sstevel@tonic-gate krb5_error_code retval;
18010Sstevel@tonic-gate kdb_log_context *log_ctx;
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate if (debug)
18042881Smp153739 printf(gettext("calling kdb_util to load database\n"));
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate log_ctx = context->kdblog_context;
18070Sstevel@tonic-gate
18082881Smp153739 edit_av[0] = kdb_util;
18090Sstevel@tonic-gate count = 1;
18100Sstevel@tonic-gate if (realm) {
18110Sstevel@tonic-gate edit_av[count++] = "-r";
18120Sstevel@tonic-gate edit_av[count++] = realm;
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate edit_av[count++] = "load";
18150Sstevel@tonic-gate if (kerb_database) {
18160Sstevel@tonic-gate edit_av[count++] = "-d";
18170Sstevel@tonic-gate edit_av[count++] = kerb_database;
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate
18200Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
18210Sstevel@tonic-gate edit_av[count++] = "-i";
18220Sstevel@tonic-gate }
18230Sstevel@tonic-gate edit_av[count++] = database_file_name;
18240Sstevel@tonic-gate edit_av[count++] = NULL;
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate switch(child_pid = fork()) {
18270Sstevel@tonic-gate case -1:
18280Sstevel@tonic-gate com_err(progname, errno, gettext("while trying to fork %s"),
18292881Smp153739 kdb_util);
18300Sstevel@tonic-gate exit(1);
18310Sstevel@tonic-gate /*NOTREACHED*/
18320Sstevel@tonic-gate case 0:
18330Sstevel@tonic-gate if (!debug) {
18340Sstevel@tonic-gate save_stderr = dup(2);
18350Sstevel@tonic-gate close(0);
18360Sstevel@tonic-gate close(1);
18370Sstevel@tonic-gate close(2);
18380Sstevel@tonic-gate open("/dev/null", O_RDWR);
18390Sstevel@tonic-gate dup(0);
18400Sstevel@tonic-gate dup(0);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate
18432881Smp153739 execv(kdb_util, edit_av);
18440Sstevel@tonic-gate retval = errno;
18450Sstevel@tonic-gate if (!debug)
18460Sstevel@tonic-gate dup2(save_stderr, 2);
18470Sstevel@tonic-gate com_err(progname, retval, gettext("while trying to exec %s"),
18482881Smp153739 kdb_util);
18490Sstevel@tonic-gate _exit(1);
18500Sstevel@tonic-gate /*NOTREACHED*/
18510Sstevel@tonic-gate default:
18520Sstevel@tonic-gate if (debug)
18530Sstevel@tonic-gate printf(gettext("Child PID is %d\n"), child_pid);
18540Sstevel@tonic-gate if (wait(&waitb) < 0) {
18550Sstevel@tonic-gate com_err(progname, errno, gettext("while waiting for %s"),
18562881Smp153739 kdb_util);
18570Sstevel@tonic-gate exit(1);
18580Sstevel@tonic-gate }
18590Sstevel@tonic-gate }
18600Sstevel@tonic-gate
18612881Smp153739 error_ret = WEXITSTATUS(waitb);
18622881Smp153739 if (error_ret) {
18630Sstevel@tonic-gate com_err(progname, 0,
18642881Smp153739 gettext("%s returned a bad exit status (%d)"),
18652881Smp153739 kdb_util, error_ret);
18660Sstevel@tonic-gate exit(1);
18670Sstevel@tonic-gate }
18680Sstevel@tonic-gate return;
18690Sstevel@tonic-gate }
1870