#include <stdio.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#ifdef _AIX
#include <sys/select.h>
#endif
#include <sys/time.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <gssrpc/rpc.h>
#include <gssapi/gssapi.h>
#include "gssapiP_krb5.h"
#include <gssrpc/auth_gssapi.h>
#include <kadm5/admin.h>
#include <kadm5/kadm_rpc.h>
#include <kadm5/server_acl.h>
#include <adm_proto.h>
#include "kdb_kt.h"
#include <string.h>
#include "kadm5/server_internal.h"
#include "misc.h"
#ifdef PURIFY
#include "purify.h"
int signal_pure_report = 0;
int signal_pure_clear = 0;
void request_pure_report(int);
void request_pure_clear(int);
#endif
#if defined(NEED_DAEMON_PROTO)
extern int daemon(int, int);
#endif
volatile int signal_request_exit = 0;
volatile int signal_request_hup = 0;
void setup_signal_handlers(void);
void request_exit(int);
void request_hup(int);
void reset_db(void);
void sig_pipe(int);
void kadm_svc_run(kadm5_config_params *params);
#ifdef POSIX_SIGNALS
static struct sigaction s_action;
#endif
#define TIMEOUT 15
gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
gss_name_t gss_kadmin_name = NULL;
void *global_server_handle;
#define OVSEC_KADM_ADMIN_SERVICE "ovsec_adm/admin"
#define OVSEC_KADM_CHANGEPW_SERVICE "ovsec_adm/changepw"
extern krb5_keyblock master_keyblock;
char *build_princ_name(char *name, char *realm);
void log_badauth(OM_uint32 major, OM_uint32 minor,
struct sockaddr_in *addr, char *data);
void log_badverf(gss_name_t client_name, gss_name_t server_name,
struct svc_req *rqst, struct rpc_msg *msg,
char *data);
void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char
*error, char *data);
void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
int rec);
int schpw;
void do_schpw(int s, kadm5_config_params *params);
#ifdef USE_PASSWORD_SERVER
void kadm5_set_use_password_server (void);
#endif
static void usage()
{
fprintf(stderr, "Usage: kadmind [-x db_args]* [-r realm] [-m] [-nofork] "
#ifdef USE_PASSWORD_SERVER
"[-passwordserver] "
#endif
"[-port port-number]\n"
"\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
"\t\t\tLook at each database documentation for supported arguments\n"
);
exit(1);
}
static void display_status_1(char *, OM_uint32, int);
static void display_status(msg, maj_stat, min_stat)
char *msg;
OM_uint32 maj_stat;
OM_uint32 min_stat;
{
display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
display_status_1(msg, min_stat, GSS_C_MECH_CODE);
}
static void display_status_1(m, code, type)
char *m;
OM_uint32 code;
int type;
{
OM_uint32 maj_stat, min_stat;
gss_buffer_desc msg;
OM_uint32 msg_ctx;
msg_ctx = 0;
while (1) {
maj_stat = gss_display_status(&min_stat, code,
type, GSS_C_NULL_OID,
&msg_ctx, &msg);
fprintf(stderr, "GSS-API error %s: %s\n", m,
(char *)msg.value);
(void) gss_release_buffer(&min_stat, &msg);
if (!msg_ctx)
break;
}
}
static krb5_context context;
static krb5_context hctx;
int main(int argc, char *argv[])
{
register SVCXPRT *transp;
extern char *optarg;
extern int optind, opterr;
int ret, nofork, oldnames = 0;
OM_uint32 OMret, major_status, minor_status;
char *whoami;
gss_buffer_desc in_buf;
struct sockaddr_in addr;
int s;
auth_gssapi_name names[4];
gss_buffer_desc gssbuf;
gss_OID nt_krb5_name_oid;
kadm5_config_params params;
char **db_args = NULL;
int db_args_size = 0;
char *errmsg;
setvbuf(stderr, NULL, _IONBF, 0);
gssbuf.value = "{1 2 840 113554 1 2 2 1}";
gssbuf.length = strlen(gssbuf.value);
major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid);
if (major_status != GSS_S_COMPLETE) {
fprintf(stderr, "Couldn't create KRB5 Name NameType OID\n");
display_status("str_to_oid", major_status, minor_status);
exit(1);
}
names[0].name = names[1].name = names[2].name = names[3].name = NULL;
names[0].type = names[1].type = names[2].type = names[3].type =
nt_krb5_name_oid;
#ifdef PURIFY
purify_start_batch();
#endif
whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
nofork = 0;
memset((char *) ¶ms, 0, sizeof(params));
argc--; argv++;
while (argc) {
if (strcmp(*argv, "-x") == 0) {
argc--; argv++;
if (!argc)
usage();
db_args_size++;
{
char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1));
if( temp == NULL )
{
fprintf(stderr,"%s: cannot initialize. Not enough memory\n",
whoami);
exit(1);
}
db_args = temp;
}
db_args[db_args_size-1] = *argv;
db_args[db_args_size] = NULL;
}else if (strcmp(*argv, "-r") == 0) {
argc--; argv++;
if (!argc)
usage();
params.realm = *argv;
params.mask |= KADM5_CONFIG_REALM;
argc--; argv++;
continue;
} else if (strcmp(*argv, "-m") == 0) {
params.mkey_from_kbd = 1;
params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
} else if (strcmp(*argv, "-nofork") == 0) {
nofork = 1;
#ifdef USE_PASSWORD_SERVER
} else if (strcmp(*argv, "-passwordserver") == 0) {
kadm5_set_use_password_server ();
#endif
} else if(strcmp(*argv, "-port") == 0) {
argc--; argv++;
if(!argc)
usage();
params.kadmind_port = atoi(*argv);
params.mask |= KADM5_CONFIG_KADMIND_PORT;
} else
break;
argc--; argv++;
}
if (argc != 0)
usage();
if ((ret = kadm5_init_krb5_context(&context))) {
fprintf(stderr, "%s: %s while initializing context, aborting\n",
whoami, error_message(ret));
exit(1);
}
krb5_klog_init(context, "admin_server", whoami, 1);
if((ret = kadm5_init("kadmind", NULL,
NULL, ¶ms,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
db_args,
&global_server_handle)) != KADM5_OK) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "%s while initializing, aborting",
e_txt);
fprintf(stderr, "%s: %s while initializing, aborting\n",
whoami, e_txt);
krb5_klog_close(context);
exit(1);
}
if( db_args )
{
free(db_args), db_args=NULL;
}
if ((ret = kadm5_get_config_params(context, 1, ¶ms,
¶ms))) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "%s: %s while initializing, aborting",
whoami, e_txt);
fprintf(stderr, "%s: %s while initializing, aborting\n",
whoami, e_txt);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE)
if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
krb5_klog_syslog(LOG_ERR, "%s: Missing required configuration values "
"while initializing, aborting", whoami,
(params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
fprintf(stderr, "%s: Missing required configuration values "
"(%lx) while initializing, aborting\n", whoami,
(params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
krb5_klog_close(context);
kadm5_destroy(global_server_handle);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(params.kadmind_port);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s",
e_txt);
fprintf(stderr, "Cannot create TCP socket: %s",
e_txt);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR,
"cannot create simple chpw socket: %s",
e_txt);
fprintf(stderr, "Cannot create simple chpw socket: %s",
e_txt);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
#ifdef SO_REUSEADDR
{
int allowed;
allowed = 1;
if (setsockopt(s,
SOL_SOCKET,
SO_REUSEADDR,
(char *) &allowed,
sizeof(allowed)) < 0) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s",
e_txt);
fprintf(stderr, "Cannot set SO_REUSEADDR: %s", e_txt);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if (setsockopt(schpw, SOL_SOCKET, SO_REUSEADDR,
(char *) &allowed, sizeof(allowed)) < 0) {
const char *e_txt = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "main",
"cannot set SO_REUSEADDR on simple chpw socket: %s",
e_txt);
fprintf(stderr,
"Cannot set SO_REUSEADDR on simple chpw socket: %s",
e_txt);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
}
}
#endif
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(params.kadmind_port);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
int oerrno = errno;
const char *e_txt = krb5_get_error_message (context, errno);
fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
fprintf(stderr, "bind: %s\n", e_txt);
errno = oerrno;
krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %s", e_txt);
if(oerrno == EADDRINUSE) {
char *w = strrchr(whoami, '/');
if (w) {
w++;
}
else {
w = whoami;
}
fprintf(stderr,
"This probably means that another %s process is already\n"
"running, or that another program is using the server port (number %d)\n"
"after being assigned it by the RPC portmap daemon. If another\n"
"%s is already running, you should kill it before\n"
"restarting the server. If, on the other hand, another program is\n"
"using the server port, you should kill it before running\n"
"%s, and ensure that the conflict does not occur in the\n"
"future by making sure that %s is started on reboot\n"
"before portmap.\n", w, ntohs(addr.sin_port), w, w, w);
krb5_klog_syslog(LOG_ERR, "Check for already-running %s or for "
"another process using port %d", w,
htons(addr.sin_port));
}
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(params.kpasswd_port);
if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
char portbuf[32];
int oerrno = errno;
const char *e_txt = krb5_get_error_message (context, errno);
fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
fprintf(stderr, "bind: %s\n", e_txt);
errno = oerrno;
sprintf(portbuf, "%d", ntohs(addr.sin_port));
krb5_klog_syslog(LOG_ERR, "cannot bind simple chpw socket: %s",
e_txt);
if(oerrno == EADDRINUSE) {
char *w = strrchr(whoami, '/');
if (w) {
w++;
}
else {
w = whoami;
}
fprintf(stderr,
"This probably means that another %s process is already\n"
"running, or that another program is using the server port (number %d).\n"
"If another %s is already running, you should kill it before\n"
"restarting the server.\n",
w, ntohs(addr.sin_port), w);
}
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
transp = svctcp_create(s, 0, 0);
if(transp == NULL) {
fprintf(stderr, "%s: Cannot create RPC service.\n", whoami);
krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m");
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
fprintf(stderr, "%s: Cannot register RPC service.\n", whoami);
krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, failing.");
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
names[2].name = build_princ_name(OVSEC_KADM_ADMIN_SERVICE, params.realm);
names[3].name = build_princ_name(OVSEC_KADM_CHANGEPW_SERVICE,
params.realm);
if (names[0].name == NULL || names[1].name == NULL ||
names[2].name == NULL || names[3].name == NULL) {
krb5_klog_syslog(LOG_ERR,
"Cannot build GSS-API authentication names, "
"failing.");
fprintf(stderr, "%s: Cannot build GSS-API authentication names.\n",
whoami);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
hctx = ((kadm5_server_handle_t)global_server_handle)->context;
ret = krb5_ktkdb_set_context(hctx);
if (ret) {
krb5_klog_syslog(LOG_ERR, "Can't set kdb keytab's internal context.");
goto kterr;
}
ret = krb5_db_set_mkey(hctx, &master_keyblock);
if (ret) {
krb5_klog_syslog(LOG_ERR, "Can't set master key for kdb keytab.");
goto kterr;
}
ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
if (ret) {
krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab.");
goto kterr;
}
ret = krb5_gss_register_acceptor_identity("KDB:");
if (ret) {
krb5_klog_syslog(LOG_ERR, "Can't register acceptor keytab.");
goto kterr;
}
kterr:
if (ret) {
krb5_klog_syslog(LOG_ERR, "%s", krb5_get_error_message (context, ret));
fprintf(stderr, "%s: Can't set up keytab for RPC.\n", whoami);
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if (svcauth_gssapi_set_names(names, 4) == TRUE)
oldnames++;
if (!oldnames && svcauth_gssapi_set_names(names, 2) == FALSE) {
krb5_klog_syslog(LOG_ERR,
"Cannot set GSS-API authentication names (keytab not present?), "
"failing.");
fprintf(stderr, "%s: Cannot set GSS-API authentication names.\n",
whoami);
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
in_buf.value = names[1].name;
in_buf.length = strlen(names[1].name) + 1;
(void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
&gss_changepw_name);
if (oldnames) {
in_buf.value = names[3].name;
in_buf.length = strlen(names[3].name) + 1;
(void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
&gss_oldchangepw_name);
}
svcauth_gssapi_set_log_badauth_func(log_badauth, NULL);
svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
svcauth_gss_set_log_badauth_func(log_badauth, NULL);
svcauth_gss_set_log_badverf_func(log_badverf, NULL);
svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);
if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE) {
fprintf(stderr, "%s: Cannot initialize RPCSEC_GSS service name.\n",
whoami);
exit(1);
}
if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) {
errmsg = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "Cannot initialize acl file: %s",
errmsg);
fprintf(stderr, "%s: Cannot initialize acl file: %s\n",
whoami, errmsg);
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if (!nofork && (ret = daemon(0, 0))) {
ret = errno;
errmsg = krb5_get_error_message (context, ret);
krb5_klog_syslog(LOG_ERR, "Cannot detach from tty: %s", errmsg);
fprintf(stderr, "%s: Cannot detach from tty: %s\n",
whoami, errmsg);
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
krb5_klog_syslog(LOG_INFO, "Seeding random number generator");
ret = krb5_c_random_os_entropy(context, 1, NULL);
if (ret) {
krb5_klog_syslog(LOG_ERR, "Error getting random seed: %s, aborting",
krb5_get_error_message(context, ret));
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
setup_signal_handlers();
krb5_klog_syslog(LOG_INFO, "starting");
kadm_svc_run(¶ms);
krb5_klog_syslog(LOG_INFO, "finished, exiting");
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
close(s);
kadm5int_acl_finish(context, 0);
if(gss_changepw_name) {
(void) gss_release_name(&OMret, &gss_changepw_name);
}
if(gss_oldchangepw_name) {
(void) gss_release_name(&OMret, &gss_oldchangepw_name);
}
for(s = 0 ; s < 4; s++) {
if (names[s].name) {
free(names[s].name);
}
}
krb5_klog_close(context);
krb5_free_context(context);
exit(2);
}
void setup_signal_handlers(void) {
#ifdef POSIX_SIGNALS
(void) sigemptyset(&s_action.sa_mask);
s_action.sa_handler = request_exit;
(void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
(void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
(void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
s_action.sa_handler = request_hup;
(void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
s_action.sa_handler = sig_pipe;
(void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
#ifdef PURIFY
s_action.sa_handler = request_pure_report;
(void) sigaction(SIGUSR1, &s_action, (struct sigaction *) NULL);
s_action.sa_handler = request_pure_clear;
(void) sigaction(SIGUSR2, &s_action, (struct sigaction *) NULL);
#endif
#else
signal(SIGINT, request_exit);
signal(SIGTERM, request_exit);
signal(SIGQUIT, request_exit);
signal(SIGHUP, request_hup);
signal(SIGPIPE, sig_pipe);
#ifdef PURIFY
signal(SIGUSR1, request_pure_report);
signal(SIGUSR2, request_pure_clear);
#endif
#endif
}
void kadm_svc_run(params)
kadm5_config_params *params;
{
fd_set rfd;
struct timeval timeout;
while(signal_request_exit == 0) {
if (signal_request_hup) {
reset_db();
krb5_klog_reopen(context);
signal_request_hup = 0;
}
#ifdef PURIFY
if (signal_pure_report)
{
purify_new_reports();
signal_pure_report = 0;
}
if (signal_pure_clear)
{
purify_clear_new_reports();
signal_pure_clear = 0;
}
#endif
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
rfd = svc_fdset;
FD_SET(schpw, &rfd);
#define max(a, b) (((a) > (b)) ? (a) : (b))
switch(select(max(schpw, svc_maxfd) + 1,
(fd_set *) &rfd, NULL, NULL, &timeout)) {
case -1:
if(errno == EINTR)
continue;
perror("select");
return;
case 0:
reset_db();
break;
default:
if (FD_ISSET(schpw, &rfd))
do_schpw(schpw, params);
else
svc_getreqset(&rfd);
}
}
}
#ifdef PURIFY
void request_pure_report(int signum)
{
krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report");
signal_pure_report = 1;
return;
}
void request_pure_clear(int signum)
{
krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report and clear the old Purify info");
signal_pure_report = 1;
signal_pure_clear = 1;
return;
}
#endif
void request_hup(int signum)
{
signal_request_hup = 1;
return;
}
void reset_db(void)
{
#ifdef notdef
kadm5_ret_t ret;
char *errmsg;
if (ret = kadm5_flush(global_server_handle)) {
krb5_klog_syslog(LOG_ERR, "FATAL ERROR! %s while flushing databases. "
"Databases may be corrupt! Aborting.",
krb5_get_error_message (context, ret));
krb5_klog_close(context);
exit(3);
}
#endif
return;
}
void request_exit(int signum)
{
krb5_klog_syslog(LOG_DEBUG, "Got signal to request exit");
signal_request_exit = 1;
return;
}
void sig_pipe(int unused)
{
krb5_klog_syslog(LOG_NOTICE, "Warning: Received a SIGPIPE; probably a "
"client aborted. Continuing.");
return;
}
char *build_princ_name(char *name, char *realm)
{
char *fullname;
fullname = (char *) malloc(strlen(name) + 1 +
(realm ? strlen(realm) + 1 : 0));
if (fullname == NULL)
return NULL;
if (realm)
sprintf(fullname, "%s@%s", name, realm);
else
strcpy(fullname, name);
return fullname;
}
void log_badverf(gss_name_t client_name, gss_name_t server_name,
struct svc_req *rqst, struct rpc_msg *msg, char
*data)
{
struct procnames {
rpcproc_t proc;
const char *proc_name;
};
static const struct procnames proc_names[] = {
{1, "CREATE_PRINCIPAL"},
{2, "DELETE_PRINCIPAL"},
{3, "MODIFY_PRINCIPAL"},
{4, "RENAME_PRINCIPAL"},
{5, "GET_PRINCIPAL"},
{6, "CHPASS_PRINCIPAL"},
{7, "CHRAND_PRINCIPAL"},
{8, "CREATE_POLICY"},
{9, "DELETE_POLICY"},
{10, "MODIFY_POLICY"},
{11, "GET_POLICY"},
{12, "GET_PRIVS"},
{13, "INIT"},
{14, "GET_PRINCS"},
{15, "GET_POLS"},
{16, "SETKEY_PRINCIPAL"},
{17, "SETV4KEY_PRINCIPAL"},
{18, "CREATE_PRINCIPAL3"},
{19, "CHPASS_PRINCIPAL3"},
{20, "CHRAND_PRINCIPAL3"},
{21, "SETKEY_PRINCIPAL3"}
};
#define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames))
OM_uint32 minor;
gss_buffer_desc client, server;
gss_OID gss_type;
char *a;
rpcproc_t proc;
int i;
const char *procname;
size_t clen, slen;
char *cdots, *sdots;
client.length = 0;
client.value = NULL;
server.length = 0;
server.value = NULL;
(void) gss_display_name(&minor, client_name, &client, &gss_type);
(void) gss_display_name(&minor, server_name, &server, &gss_type);
if (client.value == NULL) {
client.value = "(null)";
clen = sizeof("(null)") -1;
} else {
clen = client.length;
}
trunc_name(&clen, &cdots);
if (server.value == NULL) {
server.value = "(null)";
slen = sizeof("(null)") - 1;
} else {
slen = server.length;
}
trunc_name(&slen, &sdots);
a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
proc = msg->rm_call.cb_proc;
procname = NULL;
for (i = 0; i < NPROCNAMES; i++) {
if (proc_names[i].proc == proc) {
procname = proc_names[i].proc_name;
break;
}
}
if (procname != NULL)
krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %s, "
"claimed client = %.*s%s, server = %.*s%s, addr = %s",
procname, clen, client.value, cdots,
slen, server.value, sdots, a);
else
krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %d, "
"claimed client = %.*s%s, server = %.*s%s, addr = %s",
proc, clen, client.value, cdots,
slen, server.value, sdots, a);
(void) gss_release_buffer(&minor, &client);
(void) gss_release_buffer(&minor, &server);
}
void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
char *error, char *data)
{
char *a;
a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
krb5_klog_syslog(LOG_NOTICE, "Miscellaneous RPC error: %s, %s", a, error);
}
void log_badauth(OM_uint32 major, OM_uint32 minor,
struct sockaddr_in *addr, char *data)
{
char *a;
a = inet_ntoa(addr->sin_addr);
krb5_klog_syslog(LOG_NOTICE, "Authentication attempt failed: %s, GSS-API "
"error strings are:", a);
log_badauth_display_status(" ", major, minor);
krb5_klog_syslog(LOG_NOTICE, " GSS-API error strings complete.");
}
void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor)
{
log_badauth_display_status_1(msg, major, GSS_C_GSS_CODE, 0);
log_badauth_display_status_1(msg, minor, GSS_C_MECH_CODE, 0);
}
void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
int rec)
{
OM_uint32 gssstat, minor_stat;
gss_buffer_desc msg;
OM_uint32 msg_ctx;
msg_ctx = 0;
while (1) {
gssstat = gss_display_status(&minor_stat, code,
type, GSS_C_NULL_OID,
&msg_ctx, &msg);
if (gssstat != GSS_S_COMPLETE) {
if (!rec) {
log_badauth_display_status_1(m,gssstat,GSS_C_GSS_CODE,1);
log_badauth_display_status_1(m, minor_stat,
GSS_C_MECH_CODE, 1);
} else
krb5_klog_syslog(LOG_ERR, "GSS-API authentication error %s: "
"recursive failure!", msg);
return;
}
krb5_klog_syslog(LOG_NOTICE, "%s %s", m, (char *)msg.value);
(void) gss_release_buffer(&minor_stat, &msg);
if (!msg_ctx)
break;
}
}
void do_schpw(int s1, kadm5_config_params *params)
{
krb5_error_code ret;
char req[1500];
int len;
struct sockaddr_in from;
socklen_t fromlen;
krb5_keytab kt;
krb5_data reqdata, repdata;
int s2;
fromlen = sizeof(from);
if ((len = recvfrom(s1, req, sizeof(req), 0, (struct sockaddr *)&from,
&fromlen)) < 0) {
krb5_klog_syslog(LOG_ERR, "chpw: Couldn't receive request: %s",
krb5_get_error_message (context, errno));
return;
}
if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) {
krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab %s",
krb5_get_error_message (context, ret));
return;
}
reqdata.length = len;
reqdata.data = req;
if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
const char *errmsg = krb5_get_error_message (context, errno);
krb5_klog_syslog(LOG_ERR, "cannot create connecting socket: %s",
errmsg);
fprintf(stderr, "Cannot create connecting socket: %s",
errmsg);
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
krb5_klog_close(context);
exit(1);
}
if (connect(s2, (struct sockaddr *) &from, sizeof(from)) < 0) {
krb5_klog_syslog(LOG_ERR, "chpw: Couldn't connect to client: %s",
krb5_get_error_message (context, errno));
goto cleanup;
}
if ((ret = process_chpw_request(context, global_server_handle,
params->realm, s2, kt, &from,
&reqdata, &repdata))) {
krb5_klog_syslog(LOG_ERR, "chpw: Error processing request: %s",
krb5_get_error_message (context, ret));
}
close(s2);
if (repdata.length == 0) {
goto cleanup;
}
len = sendto(s1, repdata.data, (int) repdata.length, 0,
(struct sockaddr *) &from, sizeof(from));
if (len < (int) repdata.length) {
krb5_xfree(repdata.data);
krb5_klog_syslog(LOG_ERR, "chpw: Error sending reply: %s",
krb5_get_error_message (context, errno));
goto cleanup;
}
krb5_xfree(repdata.data);
cleanup:
krb5_kt_close(context, kt);
return;
}