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