#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include "autoconf.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#define DEFINE_SOCKADDR
#include "port-sockets.h"
#include "krb.h"
#include "krbports.h"
#include "kadm.h"
#include "kadm_err.h"
#include "prot.h"
#if defined(_WIN32)
#define SIGNAL(s, f) 0
#else
#define SIGNAL(s, f) signal(s, f)
#endif
static void clear_secrets(des_cblock sess_key, Key_schedule sess_sched);
#ifdef SIGPIPE
static krb5_sigtype (*opipe)();
#endif
int
kadm_init_link(char *principal, char *instance, char *realm,
Kadm_Client *client_parm, int changepw)
{
struct servent *sep;
u_short sep_port;
struct hostent *hop;
char adm_hostname[MAXHOSTNAMELEN];
char *scol = 0;
(void) strcpy(client_parm->sname, principal);
(void) strcpy(client_parm->sinst, instance);
(void) strcpy(client_parm->krbrlm, realm);
client_parm->admin_fd = -1;
client_parm->default_port = 1;
if (changepw) {
#if 0
if (krb_get_kpasswdhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
#endif
if (krb_get_admhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
return KADM_NO_HOST;
} else {
if (krb_get_admhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
return KADM_NO_HOST;
}
scol = strchr(adm_hostname,':');
if (scol) *scol = 0;
if ((hop = gethostbyname(adm_hostname)) == NULL)
return KADM_UNK_HOST;
if (scol) {
sep_port = htons(atoi(scol+1));
client_parm->default_port = 0;
} else if ((sep = getservbyname(KADM_SNAME, "tcp")) != NULL)
sep_port = sep->s_port;
else
sep_port = htons(KADM_PORT);
memset(&client_parm->admin_addr, 0, sizeof(client_parm->admin_addr));
client_parm->admin_addr.sin_family = hop->h_addrtype;
memcpy(&client_parm->admin_addr.sin_addr, hop->h_addr, hop->h_length);
client_parm->admin_addr.sin_port = sep_port;
return KADM_SUCCESS;
}
int
kadm_cli_send(Kadm_Client *client_parm,
u_char *st_dat,
size_t st_siz,
u_char **ret_dat,
size_t *ret_siz)
{
#define RET_N_FREE(r) {clear_secrets(sess_key, sess_sched); free((char *)act_st); free((char *)priv_pak); return r;}
#define RET_N_FREE2(r) {free((char *)*ret_dat); *ret_dat = 0; *ret_siz = 0; clear_secrets(sess_key, sess_sched); return(r);}
int act_len;
KRB_INT32 retdat;
KTEXT_ST authent;
u_char *act_st;
u_char *priv_pak;
long priv_len;
u_long cksum;
MSG_DAT mdat;
u_char *return_dat;
u_char *p;
KRB_UINT32 uretdat;
des_cblock sess_key;
Key_schedule sess_sched;
act_st = malloc(KADM_VERSIZE);
strncpy((char *)act_st, KADM_VERSTR, KADM_VERSIZE);
act_len = KADM_VERSIZE;
if ((retdat = kadm_cli_keyd(client_parm, sess_key, sess_sched)) != KADM_SUCCESS) {
free(act_st);
return retdat;
}
priv_pak = malloc(st_siz + 200);
if ((priv_len = krb_mk_priv(st_dat, priv_pak, (u_long)st_siz,
sess_sched, (C_Block *)sess_key,
&client_parm->my_addr,
&client_parm->admin_addr)) < 0)
RET_N_FREE(KADM_NO_ENCRYPT);
act_len += vts_long((KRB_UINT32)priv_len, &act_st, (int)act_len);
#ifdef NOENCRYPTION
cksum = 0;
#else
cksum = quad_cksum(priv_pak, NULL, priv_len, 0, &sess_key);
#endif
if ((retdat = krb_mk_req_creds(&authent, &client_parm->creds, (long)cksum)) != 0) {
RET_N_FREE(retdat);
}
act_st = realloc(act_st, (unsigned) (act_len + authent.length
+ priv_len));
if (!act_st) {
clear_secrets(sess_key, sess_sched);
free(priv_pak);
return KADM_NOMEM;
}
memcpy(act_st + act_len, authent.dat, authent.length);
memcpy(act_st + act_len + authent.length, priv_pak, priv_len);
free(priv_pak);
if ((retdat = kadm_cli_out(client_parm, act_st,
act_len + authent.length + priv_len,
ret_dat, ret_siz)) != KADM_SUCCESS)
RET_N_FREE(retdat);
free(act_st);
if ((*ret_siz >= KADM_VERSIZE) &&
!strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE))
{
if (*ret_siz < KADM_VERSIZE + 4)
RET_N_FREE2(KADM_BAD_VER);
p = *ret_dat + KADM_VERSIZE;
KRB4_GET32BE(uretdat, p);
retdat = (KRB_INT32)uretdat;
RET_N_FREE2(retdat);
}
if ((retdat = krb_rd_priv(*ret_dat, (u_long)*ret_siz, sess_sched,
(C_Block *)sess_key, &client_parm->admin_addr,
&client_parm->my_addr, &mdat)) != 0)
RET_N_FREE2(retdat);
if (mdat.app_length < KADM_VERSIZE + 4)
RET_N_FREE2(KADM_BAD_VER);
if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE))
RET_N_FREE2(KADM_BAD_VER);
p = mdat.app_data + KADM_VERSIZE;
KRB4_GET32BE(uretdat, p);
retdat = (KRB_INT32)uretdat;
if ((mdat.app_length - KADM_VERSIZE - 4) != 0) {
if (!(return_dat =
malloc((unsigned)(mdat.app_length - KADM_VERSIZE - 4))))
RET_N_FREE2(KADM_NOMEM);
memcpy(return_dat, p, mdat.app_length - KADM_VERSIZE - 4);
} else {
if (!(return_dat = malloc((unsigned) 1)))
RET_N_FREE2(KADM_NOMEM);
*return_dat = '\0';
}
free(*ret_dat);
clear_secrets(sess_key, sess_sched);
*ret_dat = return_dat;
*ret_siz = mdat.app_length - KADM_VERSIZE - 4;
return retdat;
}
int kadm_cli_conn(Kadm_Client *client_parm)
{
#if 0
int on = 1;
#endif
if ((client_parm->admin_fd =
socket(client_parm->admin_addr.sin_family, SOCK_STREAM,0)) < 0)
return KADM_NO_SOCK;
if (SOCKET_CONNECT(client_parm->admin_fd,
(struct sockaddr *) & client_parm->admin_addr,
sizeof(client_parm->admin_addr))) {
(void) SOCKET_CLOSE(client_parm->admin_fd);
client_parm->admin_fd = -1;
if (client_parm->admin_addr.sin_port != htons(KADM_PORT)
&& client_parm->default_port) {
client_parm->admin_addr.sin_port = htons(KADM_PORT);
return kadm_cli_conn(client_parm);
}
return KADM_NO_CONN;
}
#ifdef SIGPIPE
opipe = SIGNAL(SIGPIPE, SIG_IGN);
#endif
client_parm->my_addr_len = sizeof(client_parm->my_addr);
if (SOCKET_GETSOCKNAME(client_parm->admin_fd,
(struct sockaddr *) & client_parm->my_addr,
&client_parm->my_addr_len) < 0) {
(void) SOCKET_CLOSE(client_parm->admin_fd);
client_parm->admin_fd = -1;
#ifdef SIGPIPE
(void) SIGNAL(SIGPIPE, opipe);
#endif
return KADM_NO_HERE;
}
#if 0
if (setsockopt(client_parm.admin_fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
sizeof(on)) < 0) {
(void) closesocket(client_parm.admin_fd);
client_parm.admin_fd = -1;
#ifdef SIGPIPE
(void) SIGNAL(SIGPIPE, opipe);
#endif
return KADM_NO_CONN;
}
#endif
return KADM_SUCCESS;
}
void kadm_cli_disconn(Kadm_Client *client_parm)
{
(void) SOCKET_CLOSE(client_parm->admin_fd);
#ifdef SIGPIPE
(void) SIGNAL(SIGPIPE, opipe);
#endif
return;
}
int kadm_cli_out(Kadm_Client *client_parm, u_char *dat, int dat_len,
u_char **ret_dat, size_t *ret_siz)
{
u_short dlen;
int retval;
unsigned char buf[2], *p;
dlen = (u_short)dat_len;
if (dlen > 0x7fff)
return KADM_NO_ROOM;
p = buf;
KRB4_PUT16BE(p, dlen);
if (krb_net_write(client_parm->admin_fd, (char *)buf, 2) < 0)
return SOCKET_ERRNO;
if (krb_net_write(client_parm->admin_fd, (char *)dat, (int)dat_len) < 0)
return SOCKET_ERRNO;
retval = krb_net_read(client_parm->admin_fd, (char *)buf, 2);
if (retval != 2) {
if (retval < 0)
return SOCKET_ERRNO;
else
return EPIPE;
}
p = buf;
KRB4_GET16BE(dlen, p);
if (dlen > INT_MAX)
return KADM_NO_ROOM;
*ret_dat = malloc(dlen);
if (!*ret_dat)
return KADM_NOMEM;
retval = krb_net_read(client_parm->admin_fd, (char *)*ret_dat, (int)dlen);
if (retval != dlen) {
if (retval < 0)
return SOCKET_ERRNO;
else
return EPIPE;
}
*ret_siz = dlen;
return KADM_SUCCESS;
}
static void
clear_secrets(des_cblock sess_key, Key_schedule sess_sched)
{
memset(sess_key, 0, sizeof(sess_key));
memset(sess_sched, 0, sizeof(sess_sched));
return;
}
int kadm_cli_keyd(Kadm_Client *client_parm,
des_cblock s_k, des_key_schedule s_s)
{
int stat;
memcpy(s_k, client_parm->creds.session, sizeof(des_cblock));
stat = key_sched(s_k, s_s);
if (stat)
return stat;
return KADM_SUCCESS;
}