10Sstevel@tonic-gate /* 2*1446Smp153739 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 70Sstevel@tonic-gate 80Sstevel@tonic-gate /* 90Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 100Sstevel@tonic-gate * 110Sstevel@tonic-gate * Openvision retains the copyright to derivative works of 120Sstevel@tonic-gate * this source code. Do *NOT* create a derivative of this 130Sstevel@tonic-gate * source code before consulting with your legal department. 140Sstevel@tonic-gate * Do *NOT* integrate *ANY* of this source code into another 150Sstevel@tonic-gate * product before consulting with your legal department. 160Sstevel@tonic-gate * 170Sstevel@tonic-gate * For further information, read the top-level Openvision 180Sstevel@tonic-gate * copyright which is contained in the top-level MIT Kerberos 190Sstevel@tonic-gate * copyright. 200Sstevel@tonic-gate * 210Sstevel@tonic-gate * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 220Sstevel@tonic-gate * 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * SUNWresync121 XXX 320Sstevel@tonic-gate * Beware future resyncers, this file is much diff from MIT (1.0...) 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <stdio.h> 360Sstevel@tonic-gate #include <signal.h> 370Sstevel@tonic-gate #include <syslog.h> 380Sstevel@tonic-gate #include <sys/types.h> 390Sstevel@tonic-gate #include <sys/time.h> 400Sstevel@tonic-gate #include <sys/socket.h> 410Sstevel@tonic-gate #include <unistd.h> 420Sstevel@tonic-gate #include <netinet/in.h> 430Sstevel@tonic-gate #include <arpa/inet.h> /* inet_ntoa */ 440Sstevel@tonic-gate #include <netdb.h> 450Sstevel@tonic-gate #include <gssapi/gssapi.h> 460Sstevel@tonic-gate #include <rpc/rpc.h> 470Sstevel@tonic-gate #include <kadm5/admin.h> 480Sstevel@tonic-gate #include <kadm5/kadm_rpc.h> 490Sstevel@tonic-gate #include <kadm5/server_internal.h> 500Sstevel@tonic-gate #include <server_acl.h> 510Sstevel@tonic-gate #include <krb5/adm_proto.h> 520Sstevel@tonic-gate #include <string.h> 530Sstevel@tonic-gate #include <gssapi_krb5.h> 540Sstevel@tonic-gate #include <libintl.h> 550Sstevel@tonic-gate #include <locale.h> 560Sstevel@tonic-gate #include <sys/resource.h> 570Sstevel@tonic-gate #include <kdb/kdb_log.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <rpc/rpcsec_gss.h> 600Sstevel@tonic-gate 610Sstevel@tonic-gate #ifndef FD_SETSIZE 620Sstevel@tonic-gate #define FD_SETSIZE 256 630Sstevel@tonic-gate #endif 640Sstevel@tonic-gate 650Sstevel@tonic-gate #ifndef MAX 660Sstevel@tonic-gate #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 670Sstevel@tonic-gate #endif 680Sstevel@tonic-gate 690Sstevel@tonic-gate static int signal_request_exit = 0; 700Sstevel@tonic-gate static int schpw; 710Sstevel@tonic-gate kadm5_config_params chgpw_params; 720Sstevel@tonic-gate void kadm_svc_run(void); 730Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole); 740Sstevel@tonic-gate void sig_exit(int); 750Sstevel@tonic-gate void sig_pipe(int); 760Sstevel@tonic-gate 770Sstevel@tonic-gate #ifdef POSIX_SIGNALS 780Sstevel@tonic-gate static struct sigaction s_action; 790Sstevel@tonic-gate #endif /* POSIX_SIGNALS */ 800Sstevel@tonic-gate 810Sstevel@tonic-gate #define TIMEOUT 15 820Sstevel@tonic-gate 830Sstevel@tonic-gate typedef struct _auth_gssapi_name { 840Sstevel@tonic-gate char *name; 850Sstevel@tonic-gate gss_OID type; 860Sstevel@tonic-gate } auth_gssapi_name; 870Sstevel@tonic-gate 880Sstevel@tonic-gate gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL; 890Sstevel@tonic-gate void *global_server_handle; 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * This is a kludge, but the server needs these constants to be 930Sstevel@tonic-gate * compatible with old clients. They are defined in <kadm5/admin.h>, 940Sstevel@tonic-gate * but only if USE_KADM5_API_VERSION == 1. 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate #define OVSEC_KADM_ADMIN_SERVICE_P "ovsec_adm@admin" 970Sstevel@tonic-gate #define OVSEC_KADM_CHANGEPW_SERVICE_P "ovsec_adm@changepw" 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * This enables us to set the keytab that gss_acquire_cred uses, but 1010Sstevel@tonic-gate * it also restricts us to linking against the Kv5 GSS-API library. 1020Sstevel@tonic-gate * Since this is *k*admind, that shouldn't be a problem. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate extern char *krb5_overridekeyname; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate extern void krb5_iprop_prog_1(); 1070Sstevel@tonic-gate extern kadm5_ret_t kiprop_get_adm_host_srv_name( 1080Sstevel@tonic-gate krb5_context, 1090Sstevel@tonic-gate const char *, 1100Sstevel@tonic-gate char **); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate static krb5_context context; /* XXX yuck. the signal handlers need this */ 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate in_port_t l_port = 0; /* global local port num, for BSM audits */ 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate int nofork = 0; /* global; don't fork (debug mode) */ 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Function: usage 1210Sstevel@tonic-gate * 1220Sstevel@tonic-gate * Purpose: print out the server usage message 1230Sstevel@tonic-gate * 1240Sstevel@tonic-gate * Arguments: 1250Sstevel@tonic-gate * Requires: 1260Sstevel@tonic-gate * Effects: 1270Sstevel@tonic-gate * Modifies: 1280Sstevel@tonic-gate */ 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate void 1310Sstevel@tonic-gate usage() 1320Sstevel@tonic-gate { 1330Sstevel@tonic-gate fprintf(stderr, gettext("Usage: kadmind [-r realm] [-m] [-d] " 1340Sstevel@tonic-gate "[-p port-number]\n")); 1350Sstevel@tonic-gate exit(1); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * Function: display_status 1400Sstevel@tonic-gate * 1410Sstevel@tonic-gate * Purpose: displays GSS-API messages 1420Sstevel@tonic-gate * 1430Sstevel@tonic-gate * Arguments: 1440Sstevel@tonic-gate * 1450Sstevel@tonic-gate * msg a string to be displayed with the message 1460Sstevel@tonic-gate * maj_stat the GSS-API major status code 1470Sstevel@tonic-gate * min_stat the GSS-API minor status code 1480Sstevel@tonic-gate * 1490Sstevel@tonic-gate * Effects: 1500Sstevel@tonic-gate * 1510Sstevel@tonic-gate * The GSS-API messages associated with maj_stat and min_stat are 1520Sstevel@tonic-gate * displayed on stderr, each preceeded by "GSS-API error <msg>: " and 1530Sstevel@tonic-gate * followed by a newline. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate static void display_status_1(); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate void display_status(msg, maj_stat, min_stat) 1580Sstevel@tonic-gate char *msg; 1590Sstevel@tonic-gate OM_uint32 maj_stat; 1600Sstevel@tonic-gate OM_uint32 min_stat; 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate display_status_1(msg, maj_stat, GSS_C_GSS_CODE); 1630Sstevel@tonic-gate display_status_1(msg, min_stat, GSS_C_MECH_CODE); 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static void display_status_1(m, code, type) 1670Sstevel@tonic-gate char *m; 1680Sstevel@tonic-gate OM_uint32 code; 1690Sstevel@tonic-gate int type; 1700Sstevel@tonic-gate { 1710Sstevel@tonic-gate OM_uint32 maj_stat, min_stat; 1720Sstevel@tonic-gate gss_buffer_desc msg; 1730Sstevel@tonic-gate OM_uint32 msg_ctx; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate msg_ctx = 0; 1760Sstevel@tonic-gate while (1) { 1770Sstevel@tonic-gate maj_stat = gss_display_status(&min_stat, code, 1780Sstevel@tonic-gate type, GSS_C_NULL_OID, 1790Sstevel@tonic-gate &msg_ctx, &msg); 1800Sstevel@tonic-gate fprintf(stderr, "GSS-API error %s: %s\n", m, 1810Sstevel@tonic-gate (char *)msg.value); 1820Sstevel@tonic-gate (void) gss_release_buffer(&min_stat, &msg); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (!msg_ctx) 1850Sstevel@tonic-gate break; 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * Solaris Kerberos: the following prototypes are needed because these are 1920Sstevel@tonic-gate * private interfaces that do not have prototypes in any .h 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate extern struct hostent *res_getipnodebyaddr(const void *, size_t, int, int *); 1960Sstevel@tonic-gate extern void res_freehostent(struct hostent *); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate static void 1990Sstevel@tonic-gate freedomnames(char **npp) 2000Sstevel@tonic-gate { 2010Sstevel@tonic-gate char **tpp; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate if (npp) { 2040Sstevel@tonic-gate tpp = npp; 2050Sstevel@tonic-gate while (*tpp++) { 2060Sstevel@tonic-gate free(*(tpp-1)); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate free(npp); 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Construct a list of uniq FQDNs of all the net interfaces (except 2140Sstevel@tonic-gate * krb5.conf master dups) and return it in arg 'dnames'. 2150Sstevel@tonic-gate * 2160Sstevel@tonic-gate * On successful return (0), caller must call freedomnames() 2170Sstevel@tonic-gate * to free memory. 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate static int 2200Sstevel@tonic-gate getdomnames(krb5_context ctx, char *realm, char ***dnames) 2210Sstevel@tonic-gate { 2220Sstevel@tonic-gate krb5_address **addresses = NULL; 2230Sstevel@tonic-gate krb5_address *a = NULL; 2240Sstevel@tonic-gate struct hostent *hp = NULL; 2250Sstevel@tonic-gate int ret, i, result=0, error; 2260Sstevel@tonic-gate char **npp = NULL, **tpp=NULL; 2270Sstevel@tonic-gate int dup=0, n = 0; 2280Sstevel@tonic-gate char *cfhost = NULL; /* krb5 conf file master hostname */ 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate if (ret = kadm5_get_master(ctx, realm, &cfhost)) { 2310Sstevel@tonic-gate return (ret); 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate ret = krb5_os_localaddr(ctx, &addresses); 2350Sstevel@tonic-gate if (ret != 0) { 2360Sstevel@tonic-gate if (nofork) 2370Sstevel@tonic-gate (void) fprintf(stderr, 2380Sstevel@tonic-gate "kadmind: get localaddrs failed: %s", 2390Sstevel@tonic-gate error_message(ret)); 2400Sstevel@tonic-gate result = ret; 2410Sstevel@tonic-gate goto err; 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate for (i=0; addresses[i]; i++) { 2460Sstevel@tonic-gate a = addresses[i]; 2470Sstevel@tonic-gate hp = res_getipnodebyaddr(a->contents, a->length, 2480Sstevel@tonic-gate a->addrtype == ADDRTYPE_INET 2490Sstevel@tonic-gate ? AF_INET : AF_INET6, 2500Sstevel@tonic-gate &error); 2510Sstevel@tonic-gate if (hp != NULL) { 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* skip master host in krb5.conf */ 2540Sstevel@tonic-gate if (strcasecmp(cfhost, hp->h_name) == 0) { 2550Sstevel@tonic-gate res_freehostent(hp); 2560Sstevel@tonic-gate hp = NULL; 2570Sstevel@tonic-gate continue; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate dup = 0; 2610Sstevel@tonic-gate tpp = npp; 2620Sstevel@tonic-gate /* skip if hostname already exists in list */ 2630Sstevel@tonic-gate while (tpp && *tpp++) { 2640Sstevel@tonic-gate if (strcasecmp(*(tpp-1), hp->h_name) == 0) { 2650Sstevel@tonic-gate dup++; 2660Sstevel@tonic-gate break; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate if (dup) { 2710Sstevel@tonic-gate res_freehostent(hp); 2720Sstevel@tonic-gate hp = NULL; 2730Sstevel@tonic-gate continue; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate npp = realloc(npp, sizeof(char *) * (n + 2)); 2770Sstevel@tonic-gate if (!npp) { 2780Sstevel@tonic-gate result = ENOMEM; 2790Sstevel@tonic-gate goto err; 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate npp[n] = strdup(hp->h_name); 2820Sstevel@tonic-gate if (!npp[n]) { 2830Sstevel@tonic-gate result = ENOMEM; 2840Sstevel@tonic-gate goto err; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate npp[n+1] = NULL; 2870Sstevel@tonic-gate n++; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate res_freehostent(hp); 2900Sstevel@tonic-gate hp = NULL; 2910Sstevel@tonic-gate result = 0; 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate #ifdef DEBUG 2970Sstevel@tonic-gate printf("getdomnames: n=%d, i=%d, npp=%p\n", n, i, npp); 2980Sstevel@tonic-gate tpp = npp; 2990Sstevel@tonic-gate while (tpp && *tpp++) { 3000Sstevel@tonic-gate printf("tpp=%s\n", *(tpp-1)); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate #endif 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate goto out; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate err: 3070Sstevel@tonic-gate if (npp) { 3080Sstevel@tonic-gate freedomnames(npp); 3090Sstevel@tonic-gate npp = NULL; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate if (hp) { 3130Sstevel@tonic-gate res_freehostent(hp); 3140Sstevel@tonic-gate hp = NULL; 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate out: 3180Sstevel@tonic-gate if (cfhost) { 3190Sstevel@tonic-gate free (cfhost); 3200Sstevel@tonic-gate cfhost = NULL; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate if (addresses) { 3230Sstevel@tonic-gate krb5_free_addresses(ctx, addresses); 3240Sstevel@tonic-gate addresses = NULL; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate if (result == 0) 3280Sstevel@tonic-gate *dnames = npp; 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate return (result); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * Set the rpcsec_gss svc names for all net interfaces. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate static void 3370Sstevel@tonic-gate set_svc_domnames(char *svcname, char **dnames, 3380Sstevel@tonic-gate u_int program, u_int version) 3390Sstevel@tonic-gate { 3400Sstevel@tonic-gate bool_t ret; 3410Sstevel@tonic-gate char **tpp = dnames; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate if (!tpp) 3440Sstevel@tonic-gate return; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate while (*tpp++) { 3470Sstevel@tonic-gate /* MAX_NAME_LEN from rpc/rpcsec_gss.h */ 3480Sstevel@tonic-gate char name[MAXHOSTNAMELEN+MAX_NAME_LEN+2] = {0}; 3490Sstevel@tonic-gate (void) snprintf(name, sizeof(name), "%s@%s", 3500Sstevel@tonic-gate svcname, *(tpp-1)); 3510Sstevel@tonic-gate ret = rpc_gss_set_svc_name(name, 3520Sstevel@tonic-gate "kerberos_v5", 0, 3530Sstevel@tonic-gate program, version); 3540Sstevel@tonic-gate if (nofork && ret) 3550Sstevel@tonic-gate (void) fprintf(stderr, 3560Sstevel@tonic-gate "rpc_gss_set_svc_name success: %s\n", 3570Sstevel@tonic-gate name); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate int 3650Sstevel@tonic-gate main(int argc, char *argv[]) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate void kadm_1(struct svc_req *, SVCXPRT *); 3680Sstevel@tonic-gate SVCXPRT *transp; 3690Sstevel@tonic-gate extern char *optarg; 3700Sstevel@tonic-gate extern int optind, opterr; 3710Sstevel@tonic-gate int ret, rlen, oldnames = 0; 3720Sstevel@tonic-gate OM_uint32 OMret, major_status, minor_status; 3730Sstevel@tonic-gate char *whoami; 3740Sstevel@tonic-gate FILE *acl_file; 3750Sstevel@tonic-gate gss_buffer_desc in_buf; 3760Sstevel@tonic-gate struct servent *srv; 3770Sstevel@tonic-gate struct sockaddr_in addr; 3780Sstevel@tonic-gate struct sockaddr_in *sin; 3790Sstevel@tonic-gate int s; 3800Sstevel@tonic-gate int optchar; 3810Sstevel@tonic-gate struct netconfig *nconf; 3820Sstevel@tonic-gate void *handlep; 3830Sstevel@tonic-gate int fd; 3840Sstevel@tonic-gate struct t_info tinfo; 3850Sstevel@tonic-gate struct t_bind tbindstr, *tres; 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate struct t_optmgmt req, resp; 3880Sstevel@tonic-gate struct opthdr *opt; 3890Sstevel@tonic-gate char reqbuf[128]; 3900Sstevel@tonic-gate struct rlimit rl; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate char *kiprop_name = NULL; /* IProp svc name */ 3930Sstevel@tonic-gate kdb_log_context *log_ctx; 3940Sstevel@tonic-gate kadm5_server_handle_t handle; 3950Sstevel@tonic-gate krb5_context ctx; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate kadm5_config_params params; 3980Sstevel@tonic-gate auth_gssapi_name names[6]; 3990Sstevel@tonic-gate gss_buffer_desc gssbuf; 4000Sstevel@tonic-gate gss_OID nt_krb5_name_oid; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate char **dnames = NULL; 4030Sstevel@tonic-gate int retdn; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* This is OID value the Krb5_Name NameType */ 4060Sstevel@tonic-gate gssbuf.value = "{1 2 840 113554 1 2 2 1}"; 4070Sstevel@tonic-gate gssbuf.length = strlen(gssbuf.value); 4080Sstevel@tonic-gate major_status = gss_str_to_oid(&minor_status, &gssbuf, 4090Sstevel@tonic-gate &nt_krb5_name_oid); 4100Sstevel@tonic-gate if (major_status != GSS_S_COMPLETE) { 4110Sstevel@tonic-gate fprintf(stderr, 4120Sstevel@tonic-gate gettext("Couldn't create KRB5 Name NameType OID\n")); 4130Sstevel@tonic-gate display_status("str_to_oid", major_status, minor_status); 4140Sstevel@tonic-gate exit(1); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate names[0].name = names[1].name = names[2].name = 4180Sstevel@tonic-gate names[3].name = names[4].name = names[5].name =NULL; 4190Sstevel@tonic-gate names[0].type = names[1].type = names[2].type = 4200Sstevel@tonic-gate names[3].type = names[4].type = names[5].type = 4210Sstevel@tonic-gate (gss_OID) nt_krb5_name_oid; 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]); 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 4280Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 4290Sstevel@tonic-gate #endif 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate nofork = 0; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate memset((char *) ¶ms, 0, sizeof (params)); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate while ((optchar = getopt(argc, argv, "r:mdp:")) != EOF) { 4380Sstevel@tonic-gate switch (optchar) { 4390Sstevel@tonic-gate case 'r': 4400Sstevel@tonic-gate if (!optarg) 4410Sstevel@tonic-gate usage(); 4420Sstevel@tonic-gate params.realm = optarg; 4430Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM; 4440Sstevel@tonic-gate break; 4450Sstevel@tonic-gate case 'm': 4460Sstevel@tonic-gate params.mkey_from_kbd = 1; 4470Sstevel@tonic-gate params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; 4480Sstevel@tonic-gate break; 4490Sstevel@tonic-gate case 'd': 4500Sstevel@tonic-gate nofork = 1; 4510Sstevel@tonic-gate break; 4520Sstevel@tonic-gate case 'p': 4530Sstevel@tonic-gate if (!optarg) 4540Sstevel@tonic-gate usage(); 4550Sstevel@tonic-gate params.kadmind_port = atoi(optarg); 4560Sstevel@tonic-gate params.mask |= KADM5_CONFIG_KADMIND_PORT; 4570Sstevel@tonic-gate break; 4580Sstevel@tonic-gate case '?': 4590Sstevel@tonic-gate default: 4600Sstevel@tonic-gate usage(); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 4660Sstevel@tonic-gate rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, FD_SETSIZE); 4670Sstevel@tonic-gate setrlimit(RLIMIT_NOFILE, &rl); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (!nofork && (ret = daemon(0, 0))) { 4710Sstevel@tonic-gate ret = errno; 4720Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 4730Sstevel@tonic-gate gettext("Cannot detach from tty: %s"), 4740Sstevel@tonic-gate error_message(ret)); 4750Sstevel@tonic-gate fprintf(stderr, gettext("%s: Cannot detach from tty: %s\n"), 4760Sstevel@tonic-gate whoami, error_message(ret)); 4770Sstevel@tonic-gate krb5_klog_close(context); 4780Sstevel@tonic-gate exit(1); 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate if (ret = krb5_init_context(&context)) { 4820Sstevel@tonic-gate fprintf(stderr, 4830Sstevel@tonic-gate gettext("%s: %s while initializing context, aborting\n"), 4840Sstevel@tonic-gate whoami, error_message(ret)); 4850Sstevel@tonic-gate exit(1); 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate krb5_klog_init(context, "admin_server", whoami, 1); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * When using the Horowitz/IETF protocol for 4930Sstevel@tonic-gate * password changing, the default port is 464 4940Sstevel@tonic-gate * (officially recognized by IANA) 4950Sstevel@tonic-gate * 4960Sstevel@tonic-gate * DEFAULT_KPASSWD_PORT -> 464 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate chgpw_params.kpasswd_port = DEFAULT_KPASSWD_PORT; 4990Sstevel@tonic-gate chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PORT; 5000Sstevel@tonic-gate chgpw_params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2; 5010Sstevel@tonic-gate chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate if (ret = kadm5_get_config_params(context, NULL, NULL, &chgpw_params, 5040Sstevel@tonic-gate &chgpw_params)) { 5050Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing," 5060Sstevel@tonic-gate " aborting"), whoami, error_message(ret)); 5070Sstevel@tonic-gate fprintf(stderr, 5080Sstevel@tonic-gate gettext("%s: %s while initializing, aborting\n"), 5090Sstevel@tonic-gate whoami, error_message(ret)); 5100Sstevel@tonic-gate krb5_klog_close(context); 5110Sstevel@tonic-gate exit(1); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * We now setup the socket and bind() to port 464, so that 5160Sstevel@tonic-gate * kadmind can now listen to and process change-pwd requests 5170Sstevel@tonic-gate * from non-Solaris Kerberos V5 clients such as Microsoft, 5180Sstevel@tonic-gate * MIT, AIX, HP etc 5190Sstevel@tonic-gate */ 5200Sstevel@tonic-gate if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 5210Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext( "cannot create simple " 5220Sstevel@tonic-gate "chpw socket: %s"), error_message(errno)); 5230Sstevel@tonic-gate fprintf(stderr, gettext("Cannot create simple chpw " 5240Sstevel@tonic-gate "socket: %s"), error_message(errno)); 5250Sstevel@tonic-gate krb5_klog_close(context); 5260Sstevel@tonic-gate exit(1); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate memset(&addr, 0, sizeof(addr)); 5300Sstevel@tonic-gate addr.sin_family = AF_INET; 5310Sstevel@tonic-gate addr.sin_addr.s_addr = INADDR_ANY; 5320Sstevel@tonic-gate addr.sin_port = htons(chgpw_params.kpasswd_port); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 5350Sstevel@tonic-gate char portbuf[32]; 5360Sstevel@tonic-gate int oerrno = errno; 5370Sstevel@tonic-gate fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami); 5380Sstevel@tonic-gate fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno)); 5390Sstevel@tonic-gate errno = oerrno; 5400Sstevel@tonic-gate (void) snprintf(portbuf, sizeof (portbuf), "%d", 5410Sstevel@tonic-gate ntohs(addr.sin_port)); 5420Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("cannot bind simple " 5430Sstevel@tonic-gate "chpw socket: %s"), error_message(oerrno)); 5440Sstevel@tonic-gate if(oerrno == EADDRINUSE) { 5450Sstevel@tonic-gate char *w = strrchr(whoami, '/'); 5460Sstevel@tonic-gate if (w) { 5470Sstevel@tonic-gate w++; 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate else { 5500Sstevel@tonic-gate w = whoami; 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate fprintf(stderr, gettext( 5530Sstevel@tonic-gate "This probably means that another %s process\n" 5540Sstevel@tonic-gate "is already running, or that another program\n" 5550Sstevel@tonic-gate "is using the server port (number %d).\n" 5560Sstevel@tonic-gate "If another %s is already running, you should\n" 5570Sstevel@tonic-gate "kill it before restarting the server.\n"), 5580Sstevel@tonic-gate w, ntohs(addr.sin_port), w); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate krb5_klog_close(context); 5610Sstevel@tonic-gate exit(1); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate if (ret = kadm5_get_config_params(context, NULL, NULL, ¶ms, 5650Sstevel@tonic-gate ¶ms)) { 5660Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing," 5670Sstevel@tonic-gate " aborting"), whoami, error_message(ret)); 5680Sstevel@tonic-gate fprintf(stderr, 5690Sstevel@tonic-gate gettext("%s: %s while initializing, aborting\n"), 5700Sstevel@tonic-gate whoami, error_message(ret)); 5710Sstevel@tonic-gate krb5_klog_close(context); 5720Sstevel@tonic-gate exit(1); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE | \ 5750Sstevel@tonic-gate KADM5_CONFIG_ADMIN_KEYTAB) 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { 5780Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 5790Sstevel@tonic-gate gettext("%s: Missing required configuration values " 5800Sstevel@tonic-gate "while initializing, aborting"), whoami, 5810Sstevel@tonic-gate (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); 5820Sstevel@tonic-gate fprintf(stderr, 5830Sstevel@tonic-gate gettext("%s: Missing required configuration values " 5840Sstevel@tonic-gate "(%x) while initializing, aborting\n"), whoami, 5850Sstevel@tonic-gate (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); 5860Sstevel@tonic-gate krb5_klog_close(context); 5870Sstevel@tonic-gate exit(1); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate memset((char *) &addr, 0, sizeof (struct sockaddr_in)); 5900Sstevel@tonic-gate addr.sin_family = AF_INET; 5910Sstevel@tonic-gate addr.sin_addr.s_addr = INADDR_ANY; 5920Sstevel@tonic-gate l_port = addr.sin_port = htons(params.kadmind_port); 5930Sstevel@tonic-gate sin = &addr; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate if ((handlep = setnetconfig()) == (void *) NULL) { 5960Sstevel@tonic-gate (void) krb5_klog_syslog(LOG_ERR, 5970Sstevel@tonic-gate gettext("cannot get any transport information")); 5980Sstevel@tonic-gate krb5_klog_close(context); 5990Sstevel@tonic-gate exit(1); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate while (nconf = getnetconfig(handlep)) { 6020Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS_ORD) && 6030Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, NC_INET) == 0) && 6040Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0)) 6050Sstevel@tonic-gate break; 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (nconf == (struct netconfig *) NULL) { 6090Sstevel@tonic-gate (void) endnetconfig(handlep); 6100Sstevel@tonic-gate krb5_klog_close(context); 6110Sstevel@tonic-gate exit(1); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, &tinfo); 6140Sstevel@tonic-gate if (fd == -1) { 6150Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 6160Sstevel@tonic-gate gettext("unable to open connection for ADMIN server")); 6170Sstevel@tonic-gate krb5_klog_close(context); 6180Sstevel@tonic-gate exit(1); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate /* LINTED */ 6210Sstevel@tonic-gate opt = (struct opthdr *) reqbuf; 6220Sstevel@tonic-gate opt->level = SOL_SOCKET; 6230Sstevel@tonic-gate opt->name = SO_REUSEADDR; 6240Sstevel@tonic-gate opt->len = sizeof (int); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * The option value is "1". This will allow the server to restart 6280Sstevel@tonic-gate * whilst the previous process is cleaning up after itself in a 6290Sstevel@tonic-gate * FIN_WAIT_2 or TIME_WAIT state. If another process is started 6300Sstevel@tonic-gate * outside of smf(5) then bind will fail anyway, which is what we want. 6310Sstevel@tonic-gate */ 6320Sstevel@tonic-gate reqbuf[sizeof (struct opthdr)] = 1; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate req.flags = T_NEGOTIATE; 6350Sstevel@tonic-gate req.opt.len = sizeof (struct opthdr) + opt->len; 6360Sstevel@tonic-gate req.opt.buf = (char *) opt; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate resp.flags = 0; 6390Sstevel@tonic-gate resp.opt.buf = reqbuf; 6400Sstevel@tonic-gate resp.opt.maxlen = sizeof (reqbuf); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 6430Sstevel@tonic-gate t_error("t_optmgmt"); 6440Sstevel@tonic-gate exit(1); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate /* Transform addr to netbuf */ 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate tres = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); 6490Sstevel@tonic-gate if (tres == NULL) { 6500Sstevel@tonic-gate (void) t_close(fd); 6510Sstevel@tonic-gate (void) krb5_klog_syslog(LOG_ERR, 6520Sstevel@tonic-gate gettext("cannot allocate netbuf")); 6530Sstevel@tonic-gate krb5_klog_close(context); 6540Sstevel@tonic-gate exit(1); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate tbindstr.qlen = 8; 6570Sstevel@tonic-gate tbindstr.addr.buf = (char *) sin; 6580Sstevel@tonic-gate tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr); 6590Sstevel@tonic-gate sin = (struct sockaddr_in *) tbindstr.addr.buf; 6600Sstevel@tonic-gate /* SUNWresync121 XXX (void) memset(&addr, 0, sizeof(addr)); */ 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if (t_bind(fd, &tbindstr, tres) < 0) { 6630Sstevel@tonic-gate int oerrno = errno; 6640Sstevel@tonic-gate fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami); 6650Sstevel@tonic-gate fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno)); 6660Sstevel@tonic-gate errno = oerrno; 6670Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("Cannot bind socket: %s"), 6680Sstevel@tonic-gate error_message(errno)); 6690Sstevel@tonic-gate if (oerrno == EADDRINUSE) { 6700Sstevel@tonic-gate char *w = strrchr(whoami, '/'); 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate if (w) { 6730Sstevel@tonic-gate w++; 6740Sstevel@tonic-gate } else { 6750Sstevel@tonic-gate w = whoami; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate fprintf(stderr, gettext( 6780Sstevel@tonic-gate "This probably means that another %s " 6790Sstevel@tonic-gate "process is already\n" 6800Sstevel@tonic-gate "running, or that another program is using " 6810Sstevel@tonic-gate "the server port (number %d)\n" 6820Sstevel@tonic-gate "after being assigned it by the RPC " 6830Sstevel@tonic-gate "portmap deamon. If another\n" 6840Sstevel@tonic-gate "%s is already running, you should kill " 6850Sstevel@tonic-gate "it before\n" 6860Sstevel@tonic-gate "restarting the server. If, on the other hand, " 6870Sstevel@tonic-gate "another program is\n" 6880Sstevel@tonic-gate "using the server port, you should kill it " 6890Sstevel@tonic-gate "before running\n" 6900Sstevel@tonic-gate "%s, and ensure that the conflict does " 6910Sstevel@tonic-gate "not occur in the\n" 6920Sstevel@tonic-gate "future by making sure that %s is started " 6930Sstevel@tonic-gate "on reboot\n" 6940Sstevel@tonic-gate "before portmap.\n"), 6950Sstevel@tonic-gate w, ntohs(addr.sin_port), w, w, w); 6960Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 6970Sstevel@tonic-gate gettext("Check for already-running %s or for " 6980Sstevel@tonic-gate "another process using port %d"), w, 6990Sstevel@tonic-gate htons(addr.sin_port)); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate krb5_klog_close(context); 7020Sstevel@tonic-gate exit(1); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate transp = svc_tli_create(fd, nconf, NULL, 0, 0); 7050Sstevel@tonic-gate (void) t_free((char *) tres, T_BIND); 7060Sstevel@tonic-gate if (transp == NULL) { 7070Sstevel@tonic-gate fprintf(stderr, gettext("%s: Cannot create RPC service.\n"), 7080Sstevel@tonic-gate whoami); 7090Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("Cannot create RPC service: %m")); 7100Sstevel@tonic-gate krb5_klog_close(context); 7110Sstevel@tonic-gate exit(1); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate if (!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) { 7140Sstevel@tonic-gate fprintf(stderr, 7150Sstevel@tonic-gate gettext("%s: Cannot register RPC service.\n"), whoami); 7160Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 7170Sstevel@tonic-gate gettext("Cannot register RPC service, failing.")); 7180Sstevel@tonic-gate krb5_klog_close(context); 7190Sstevel@tonic-gate exit(1); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * XXX krb5_defkeyname is an internal library global and should go 7240Sstevel@tonic-gate * away 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate krb5_overridekeyname = params.admin_keytab; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate (void) kadm5_get_adm_host_srv_name(context, 7290Sstevel@tonic-gate params.realm, &names[0].name); 7300Sstevel@tonic-gate (void) kadm5_get_cpw_host_srv_name(context, 7310Sstevel@tonic-gate params.realm, &names[1].name); 7320Sstevel@tonic-gate names[2].name = KADM5_ADMIN_SERVICE_P; 7330Sstevel@tonic-gate names[3].name = KADM5_CHANGEPW_SERVICE_P; 7340Sstevel@tonic-gate names[4].name = OVSEC_KADM_ADMIN_SERVICE_P; 7350Sstevel@tonic-gate names[5].name = OVSEC_KADM_CHANGEPW_SERVICE_P; 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate if (names[0].name == NULL || names[1].name == NULL || 7380Sstevel@tonic-gate names[2].name == NULL || names[3].name == NULL || 7390Sstevel@tonic-gate names[4].name == NULL || names[5].name == NULL) { 7400Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 7410Sstevel@tonic-gate gettext("Cannot initialize GSS-API authentication, " 7420Sstevel@tonic-gate "failing.")); 7430Sstevel@tonic-gate fprintf(stderr, 7440Sstevel@tonic-gate gettext("%s: Cannot initialize " 7450Sstevel@tonic-gate "GSS-API authentication.\n"), 7460Sstevel@tonic-gate whoami); 7470Sstevel@tonic-gate krb5_klog_close(context); 7480Sstevel@tonic-gate exit(1); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate /* 7530Sstevel@tonic-gate * Try to acquire creds for the old OV services as well as the new 7540Sstevel@tonic-gate * names, but if that fails just fall back on the new names. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate if (rpc_gss_set_svc_name(names[5].name, 7580Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS) && 7590Sstevel@tonic-gate rpc_gss_set_svc_name(names[4].name, 7600Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS)) 7610Sstevel@tonic-gate oldnames++; 7620Sstevel@tonic-gate if (rpc_gss_set_svc_name(names[3].name, 7630Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS)) 7640Sstevel@tonic-gate oldnames++; 7650Sstevel@tonic-gate if (rpc_gss_set_svc_name(names[2].name, 7660Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS)) 7670Sstevel@tonic-gate oldnames++; 7680Sstevel@tonic-gate if (rpc_gss_set_svc_name(names[0].name, 7690Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS)) 7700Sstevel@tonic-gate oldnames++; 7710Sstevel@tonic-gate if (rpc_gss_set_svc_name(names[1].name, 7720Sstevel@tonic-gate "kerberos_v5", 0, KADM, KADMVERS)) 7730Sstevel@tonic-gate oldnames++; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate retdn = getdomnames(context, params.realm, &dnames); 7760Sstevel@tonic-gate if (retdn == 0 && dnames) { 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * Multi-homed KDCs sometimes may need to set svc names 7790Sstevel@tonic-gate * for multiple net interfaces so we set them for 7800Sstevel@tonic-gate * all interfaces just in case. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate set_svc_domnames(KADM5_ADMIN_HOST_SERVICE, 7830Sstevel@tonic-gate dnames, KADM, KADMVERS); 7840Sstevel@tonic-gate set_svc_domnames(KADM5_CHANGEPW_HOST_SERVICE, 7850Sstevel@tonic-gate dnames, KADM, KADMVERS); 7860Sstevel@tonic-gate } 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* if set_names succeeded, this will too */ 7890Sstevel@tonic-gate in_buf.value = names[1].name; 7900Sstevel@tonic-gate in_buf.length = strlen(names[1].name) + 1; 7910Sstevel@tonic-gate (void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid, 7920Sstevel@tonic-gate &gss_changepw_name); 7930Sstevel@tonic-gate if (oldnames) { 7940Sstevel@tonic-gate in_buf.value = names[3].name; 7950Sstevel@tonic-gate in_buf.length = strlen(names[3].name) + 1; 7960Sstevel@tonic-gate (void) gss_import_name(&OMret, &in_buf, 7970Sstevel@tonic-gate (gss_OID) nt_krb5_name_oid, 7980Sstevel@tonic-gate &gss_oldchangepw_name); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate if (ret = acl_init(context, 0, params.acl_file)) { 8010Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize acl file: %s"), 8020Sstevel@tonic-gate error_message(ret)); 8030Sstevel@tonic-gate fprintf(stderr, gettext("%s: Cannot initialize acl file: %s\n"), 8040Sstevel@tonic-gate whoami, error_message(ret)); 8050Sstevel@tonic-gate krb5_klog_close(context); 8060Sstevel@tonic-gate exit(1); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate if ((ret = kadm5_init("kadmind", NULL, 8090Sstevel@tonic-gate NULL, ¶ms, 8100Sstevel@tonic-gate KADM5_STRUCT_VERSION, 8110Sstevel@tonic-gate KADM5_API_VERSION_2, 8120Sstevel@tonic-gate &global_server_handle)) != KADM5_OK) { 8130Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 8140Sstevel@tonic-gate gettext("%s while initializing, aborting"), 8150Sstevel@tonic-gate error_message(ret)); 8160Sstevel@tonic-gate fprintf(stderr, 8170Sstevel@tonic-gate gettext("%s: %s while initializing, aborting\n"), 8180Sstevel@tonic-gate whoami, error_message(ret)); 8190Sstevel@tonic-gate krb5_klog_close(context); 8200Sstevel@tonic-gate exit(1); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate handle = global_server_handle; 8240Sstevel@tonic-gate ctx = handle->context; 8250Sstevel@tonic-gate if (params.iprop_enabled == TRUE) 8260Sstevel@tonic-gate ulog_set_role(ctx, IPROP_MASTER); 8270Sstevel@tonic-gate else 8280Sstevel@tonic-gate ulog_set_role(ctx, IPROP_NULL); 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate log_ctx = ctx->kdblog_context; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) { 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * IProp is enabled, so let's map in the update log 8350Sstevel@tonic-gate * and setup the service. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate if (ret = ulog_map(ctx, ¶ms, FKADMIND)) { 8380Sstevel@tonic-gate fprintf(stderr, 8390Sstevel@tonic-gate gettext("%s: %s while mapping update log " 8400Sstevel@tonic-gate "(`%s.ulog')\n"), whoami, error_message(ret), 8410Sstevel@tonic-gate params.dbname); 8420Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 8430Sstevel@tonic-gate gettext("%s while mapping update log " 8440Sstevel@tonic-gate "(`%s.ulog')"), error_message(ret), 8450Sstevel@tonic-gate params.dbname); 8460Sstevel@tonic-gate krb5_klog_close(ctx); 8470Sstevel@tonic-gate exit(1); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate if (nofork) 8520Sstevel@tonic-gate fprintf(stderr, 8530Sstevel@tonic-gate "%s: create IPROP svc (PROG=%d, VERS=%d)\n", 8540Sstevel@tonic-gate whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate if (!svc_create(krb5_iprop_prog_1, 8570Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS, 8580Sstevel@tonic-gate "circuit_v")) { 8590Sstevel@tonic-gate fprintf(stderr, 8600Sstevel@tonic-gate gettext("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"), 8610Sstevel@tonic-gate whoami, 8620Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS); 8630Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 8640Sstevel@tonic-gate gettext("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."), 8650Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS); 8660Sstevel@tonic-gate krb5_klog_close(ctx); 8670Sstevel@tonic-gate exit(1); 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate if (ret = kiprop_get_adm_host_srv_name(ctx, 8710Sstevel@tonic-gate params.realm, 8720Sstevel@tonic-gate &kiprop_name)) { 8730Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 8740Sstevel@tonic-gate gettext("%s while getting IProp svc name, failing"), 8750Sstevel@tonic-gate error_message(ret)); 8760Sstevel@tonic-gate fprintf(stderr, 8770Sstevel@tonic-gate gettext("%s: %s while getting IProp svc name, failing\n"), 8780Sstevel@tonic-gate whoami, error_message(ret)); 8790Sstevel@tonic-gate krb5_klog_close(ctx); 8800Sstevel@tonic-gate exit(1); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0, 8840Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS)) { 8850Sstevel@tonic-gate rpc_gss_error_t err; 8860Sstevel@tonic-gate (void) rpc_gss_get_error(&err); 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, 8890Sstevel@tonic-gate gettext("Unable to set RPCSEC_GSS service name (`%s'), failing."), 8900Sstevel@tonic-gate kiprop_name ? kiprop_name : "<null>"); 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate fprintf(stderr, 8930Sstevel@tonic-gate gettext("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"), 8940Sstevel@tonic-gate whoami, 8950Sstevel@tonic-gate kiprop_name ? kiprop_name : "<null>"); 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate if (nofork) { 8980Sstevel@tonic-gate fprintf(stderr, 8990Sstevel@tonic-gate "%s: set svc name (rpcsec err=%d, sys err=%d)\n", 9000Sstevel@tonic-gate whoami, 9010Sstevel@tonic-gate err.rpc_gss_error, 9020Sstevel@tonic-gate err.system_error); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate exit(1); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate free(kiprop_name); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (retdn == 0 && dnames) { 9100Sstevel@tonic-gate set_svc_domnames(KADM5_KIPROP_HOST_SERVICE, 9110Sstevel@tonic-gate dnames, 9120Sstevel@tonic-gate KRB5_IPROP_PROG, KRB5_IPROP_VERS); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 915*1446Smp153739 } else { 916*1446Smp153739 if (!oldnames) { 917*1446Smp153739 /* rpc_gss_set_svc_name failed for both kadmin/<fqdn> and 918*1446Smp153739 * changepw/<fqdn>. 919*1446Smp153739 */ 920*1446Smp153739 krb5_klog_syslog(LOG_ERR, 921*1446Smp153739 gettext("Unable to set RPCSEC_GSS service names " 922*1446Smp153739 "('%s, %s')"), 923*1446Smp153739 names[0].name, names[1].name); 924*1446Smp153739 fprintf(stderr, 925*1446Smp153739 gettext("%s: Unable to set RPCSEC_GSS service names " 926*1446Smp153739 "('%s, %s')\n"), 927*1446Smp153739 whoami, 928*1446Smp153739 names[0].name, names[1].name); 929*1446Smp153739 krb5_klog_close(context); 930*1446Smp153739 exit(1); 931*1446Smp153739 } 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate if (dnames) 9350Sstevel@tonic-gate freedomnames(dnames); 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate setup_signal_handlers(log_ctx->iproprole); 9380Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, gettext("starting")); 9390Sstevel@tonic-gate if (nofork) 9400Sstevel@tonic-gate fprintf(stderr, "%s: starting...\n", whoami); 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate /* 9440Sstevel@tonic-gate * We now call our own customized async event processing 9450Sstevel@tonic-gate * function kadm_svc_run(), as opposed to svc_run() earlier, 9460Sstevel@tonic-gate * since this enables kadmind to also listen-to/process 9470Sstevel@tonic-gate * non-RPCSEC_GSS based change-pwd requests apart from the 9480Sstevel@tonic-gate * regular, RPCSEC_GSS kpasswd requests from Solaris Krb5 clients. 9490Sstevel@tonic-gate */ 9500Sstevel@tonic-gate kadm_svc_run(); 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, gettext("finished, exiting")); 9530Sstevel@tonic-gate kadm5_destroy(global_server_handle); 9540Sstevel@tonic-gate t_close(fd); 9550Sstevel@tonic-gate krb5_klog_close(context); 9560Sstevel@tonic-gate exit(0); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * Function: kadm_svc_run 9620Sstevel@tonic-gate * 9630Sstevel@tonic-gate * Purpose: modified version of sunrpc svc_run. 9640Sstevel@tonic-gate * which closes the database every TIMEOUT seconds. 9650Sstevel@tonic-gate * 9660Sstevel@tonic-gate * Arguments: 9670Sstevel@tonic-gate * Requires: 9680Sstevel@tonic-gate * Effects: 9690Sstevel@tonic-gate * Modifies: 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate void 9720Sstevel@tonic-gate kadm_svc_run(void) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate struct pollfd *rfd = 0; 9750Sstevel@tonic-gate struct timeval timeout; 9760Sstevel@tonic-gate int pollret; 9770Sstevel@tonic-gate int nfds = 0; 9780Sstevel@tonic-gate int i; 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate while(signal_request_exit == 0) { 9810Sstevel@tonic-gate timeout.tv_sec = TIMEOUT; 9820Sstevel@tonic-gate timeout.tv_usec = 0; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate if (nfds != svc_max_pollfd) { 9850Sstevel@tonic-gate rfd = realloc(rfd, sizeof (pollfd_t) * svc_max_pollfd); 9860Sstevel@tonic-gate nfds = svc_max_pollfd; 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate (void) memcpy(rfd, svc_pollfd, 9900Sstevel@tonic-gate sizeof (pollfd_t) * svc_max_pollfd); 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate for (i = 0; i < nfds; i++) { 9930Sstevel@tonic-gate if (rfd[i].fd == -1) { 9940Sstevel@tonic-gate rfd[i].fd = schpw; 9950Sstevel@tonic-gate rfd[i].events = POLLIN; 9960Sstevel@tonic-gate break; 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate switch(pollret = poll(rfd, nfds, 10010Sstevel@tonic-gate __rpc_timeval_to_msec(&timeout))) { 10020Sstevel@tonic-gate case -1: 10030Sstevel@tonic-gate if(errno == EINTR) 10040Sstevel@tonic-gate continue; 10050Sstevel@tonic-gate perror("poll"); 10060Sstevel@tonic-gate return; 10070Sstevel@tonic-gate case 0: 10080Sstevel@tonic-gate continue; 10090Sstevel@tonic-gate default: 10100Sstevel@tonic-gate for (i = 0; i < nfds; i++) { 10110Sstevel@tonic-gate if (rfd[i].revents & POLLIN) { 10120Sstevel@tonic-gate if (rfd[i].fd == schpw) 10130Sstevel@tonic-gate handle_chpw(context, schpw, 10140Sstevel@tonic-gate global_server_handle, 10150Sstevel@tonic-gate &chgpw_params); 10160Sstevel@tonic-gate else 10170Sstevel@tonic-gate svc_getreq_poll(rfd, pollret); 10180Sstevel@tonic-gate break; 10190Sstevel@tonic-gate } else { 10200Sstevel@tonic-gate if (i == (nfds - 1)) 10210Sstevel@tonic-gate perror("poll"); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate break; 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * Function: setup_signal_handlers 10320Sstevel@tonic-gate * 10330Sstevel@tonic-gate * Purpose: Setup signal handling functions with System V's signal(). 10340Sstevel@tonic-gate */ 10350Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole) { 10360Sstevel@tonic-gate signal(SIGINT, sig_exit); 10370Sstevel@tonic-gate signal(SIGTERM, sig_exit); 10380Sstevel@tonic-gate signal(SIGQUIT, sig_exit); 10390Sstevel@tonic-gate signal(SIGPIPE, sig_pipe); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate /* 10420Sstevel@tonic-gate * IProp will fork for a full-resync, we don't want to 10430Sstevel@tonic-gate * wait on it and we don't want the living dead procs either. 10440Sstevel@tonic-gate */ 10450Sstevel@tonic-gate if (iproprole == IPROP_MASTER) 10460Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_IGN); 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate return; 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate /* 10530Sstevel@tonic-gate * Function: sig_exit 10540Sstevel@tonic-gate * 10550Sstevel@tonic-gate * Purpose: sets flags saying the server got a signal and that it 10560Sstevel@tonic-gate * should exit when convenient. 10570Sstevel@tonic-gate * 10580Sstevel@tonic-gate * Effects: 10590Sstevel@tonic-gate * Modifies signal_request_exit which ideally makes the server exit 10600Sstevel@tonic-gate * at some point. 10610Sstevel@tonic-gate * 10620Sstevel@tonic-gate * Modifies: 10630Sstevel@tonic-gate * Signal_request_exit 10640Sstevel@tonic-gate */ 10650Sstevel@tonic-gate void sig_exit(int signum) 10660Sstevel@tonic-gate { 10670Sstevel@tonic-gate krb5_klog_syslog(LOG_NOTICE, gettext("Got signal to request exit")); 10680Sstevel@tonic-gate signal_request_exit = 1; 10690Sstevel@tonic-gate return; 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate /* 10740Sstevel@tonic-gate * Function: sig_pipe 10750Sstevel@tonic-gate * 10760Sstevel@tonic-gate * Purpose: SIGPIPE handler 10770Sstevel@tonic-gate * 10780Sstevel@tonic-gate * Effects: krb5_klog_syslog a message that a SIGPIPE occurred and returns, 10790Sstevel@tonic-gate * thus causing the read() or write() to fail and, presumable, the RPC 10800Sstevel@tonic-gate * to recover. Otherwise, the process aborts. 10810Sstevel@tonic-gate */ 10820Sstevel@tonic-gate void 10830Sstevel@tonic-gate sig_pipe(int unused) 10840Sstevel@tonic-gate { 10850Sstevel@tonic-gate krb5_klog_syslog(LOG_NOTICE, gettext("Warning: Received a SIGPIPE; " 10860Sstevel@tonic-gate "probably a client aborted. Continuing.")); 10870Sstevel@tonic-gate } 1088