#define NEED_SOCKETS
#include "k5-int.h"
#include "adm_proto.h"
static void kadm_copyin_int32 (char *, krb5_int32 *);
static void kadm_copyout_int32 (krb5_int32, char *);
static void
kadm_copyin_int32(cp, ip)
char *cp;
krb5_int32 *ip;
{
*ip = (((krb5_int32) ((unsigned char) cp[0]) << 24) +
((krb5_int32) ((unsigned char) cp[1]) << 16) +
((krb5_int32) ((unsigned char) cp[2]) << 8) +
((krb5_int32) ((unsigned char) cp[3])));
}
static void
kadm_copyout_int32(outint, cp)
krb5_int32 outint;
char *cp;
{
cp[0] = (char) ((outint >> 24) & 0xff);
cp[1] = (char) ((outint >> 16) & 0xff);
cp[2] = (char) ((outint >> 8) & 0xff);
cp[3] = (char) (outint & 0xff);
}
void KRB5_CALLCONV
krb5_free_adm_data(kcontext, ncomp, datap)
krb5_context kcontext;
krb5_int32 ncomp;
krb5_data *datap;
{
int i;
if (datap) {
for (i=0; i<ncomp; i++)
if (datap[i].data && (datap[i].length > 0))
krb5_xfree(datap[i].data);
krb5_xfree(datap);
}
}
krb5_error_code KRB5_CALLCONV
krb5_send_adm_cmd(kcontext, sock, ctx, nargs, arglist)
krb5_context kcontext;
krb5_pointer sock;
krb5_auth_context ctx;
krb5_int32 nargs;
krb5_data *arglist;
{
size_t writebufsize;
int i;
char *writebuf;
krb5_error_code ret;
krb5_int32 ac_flags;
ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags);
if (ret)
return(ret);
if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
(KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
return(KRB5KRB_AP_ERR_MSG_TYPE);
}
ret = 0;
writebufsize = sizeof(krb5_int32);
for (i=0; i<nargs; i++) {
writebufsize += sizeof(krb5_int32);
writebufsize += arglist[i].length;
}
writebuf = (char *) malloc(writebufsize);
if (writebuf != NULL) {
char *curr;
krb5_data write_data, out_data;
krb5_replay_data replay_data;
curr = writebuf;
kadm_copyout_int32(nargs, curr);
curr += sizeof(krb5_int32);
for (i=0; i<nargs; i++) {
kadm_copyout_int32(arglist[i].length, curr);
curr += sizeof(krb5_int32);
memcpy(curr, arglist[i].data, arglist[i].length);
curr += arglist[i].length;
}
write_data.length = writebufsize;
write_data.data = writebuf;
ret = krb5_mk_priv(kcontext, ctx, &write_data,
&out_data, &replay_data);
if (!ret) {
ret = krb5_write_message(kcontext, sock, &out_data);
krb5_free_data_contents(kcontext, &out_data);
if (ret)
goto cleanup;
}
cleanup:
memset(writebuf, 0, writebufsize);
free(writebuf);
}
else {
ret = ENOMEM;
}
return(ret);
}
krb5_error_code
krb5_send_adm_reply(kcontext, sock, ctx, cmd_stat, ncomps, complist)
krb5_context kcontext;
krb5_pointer sock;
krb5_auth_context ctx;
krb5_int32 cmd_stat;
krb5_int32 ncomps;
krb5_data *complist;
{
size_t writebufsize;
int i;
char *writebuf;
krb5_error_code ret;
krb5_int32 ac_flags;
ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags);
if (ret)
return(ret);
if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
(KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
return(KRB5KRB_AP_ERR_MSG_TYPE);
}
ret = 0;
writebufsize = 2 * sizeof(krb5_int32);
for (i=0; i<ncomps; i++) {
writebufsize += sizeof(krb5_int32);
writebufsize += complist[i].length;
}
writebuf = (char *) malloc(writebufsize);
if (writebuf != NULL) {
char *curr;
krb5_data write_data, out_data;
krb5_replay_data replay_data;
curr = writebuf;
kadm_copyout_int32(cmd_stat, curr);
curr += sizeof(krb5_int32);
kadm_copyout_int32(ncomps, curr);
curr += sizeof(krb5_int32);
for (i=0; i<ncomps; i++) {
kadm_copyout_int32(complist[i].length, curr);
curr += sizeof(krb5_int32);
memcpy(curr, complist[i].data, complist[i].length);
curr += complist[i].length;
}
write_data.length = writebufsize;
write_data.data = writebuf;
ret = krb5_mk_priv(kcontext, ctx, &write_data, &out_data,
&replay_data);
if (!ret) {
ret = krb5_write_message(kcontext, sock, &out_data);
krb5_free_data_contents(kcontext, &out_data);
if (ret)
goto cleanup;
}
cleanup:
memset(writebuf, 0, writebufsize);
free(writebuf);
}
else {
ret = ENOMEM;
}
return(ret);
}
krb5_error_code
krb5_read_adm_cmd(kcontext, sock, ctx, nargs, arglist)
krb5_context kcontext;
krb5_pointer sock;
krb5_auth_context ctx;
krb5_int32 *nargs;
krb5_data **arglist;
{
krb5_data read_data;
krb5_error_code ret;
krb5_data msg_data;
krb5_replay_data replay_data;
krb5_int32 ac_flags;
krb5_int32 len32;
ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags);
if (ret)
return(ret);
if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
(KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
return(KRB5KRB_AP_ERR_MSG_TYPE);
}
if (!(ret = krb5_read_message(kcontext, sock, &read_data))) {
if (!(ret = krb5_rd_priv(kcontext,
ctx,
&read_data,
&msg_data,
&replay_data))) {
char *curr;
int replyok;
int i;
replyok = 0;
if (msg_data.length >= sizeof(krb5_int32)) {
curr = msg_data.data;
kadm_copyin_int32(curr, nargs);
curr += sizeof(krb5_int32);
if (*nargs > 0) {
*arglist = (krb5_data *)
malloc((size_t) (*nargs) * sizeof(krb5_data));
if (*arglist != NULL) {
krb5_data *xarglist;
xarglist = *arglist;
memset((char *) (xarglist), 0,
(size_t) (*nargs) * sizeof(krb5_data));
replyok = 1;
for (i=0; i<*nargs; i++) {
if (curr + sizeof(krb5_int32) - msg_data.data <=
msg_data.length) {
kadm_copyin_int32(curr, &len32);
xarglist[i].length = (int) len32;
curr += sizeof(krb5_int32);
if ((curr + xarglist[i].length -
msg_data.data <= msg_data.length) &&
(xarglist[i].data = (char *)
malloc(xarglist[i].length+1))) {
memcpy(xarglist[i].data,
curr,
xarglist[i].length);
curr += xarglist[i].length;
xarglist[i].data[xarglist[i].length]
= '\0';
}
else {
replyok = 0;
break;
}
}
else {
replyok = 0;
break;
}
}
if (!replyok)
krb5_free_adm_data(kcontext, *nargs, *arglist);
}
}
else {
if (*nargs == 0) {
*arglist = (krb5_data *) NULL;
replyok = 1;
}
}
}
if (!replyok) {
ret = KRB5KRB_AP_ERR_MSG_TYPE;
}
memset(msg_data.data, 0, msg_data.length);
krb5_xfree(msg_data.data);
}
krb5_xfree(read_data.data);
}
return(ret);
}
krb5_error_code KRB5_CALLCONV
krb5_read_adm_reply(kcontext, sock, ctx, cmd_stat, ncomps, complist)
krb5_context kcontext;
krb5_pointer sock;
krb5_auth_context ctx;
krb5_int32 *cmd_stat;
krb5_int32 *ncomps;
krb5_data **complist;
{
krb5_data read_data;
krb5_error_code ret;
krb5_data msg_data;
krb5_replay_data replay_data;
krb5_int32 ac_flags;
krb5_int32 len32;
ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags);
if (ret)
return(ret);
if ((ac_flags & (KRB5_AUTH_CONTEXT_RET_SEQUENCE|
KRB5_AUTH_CONTEXT_DO_SEQUENCE)) !=
(KRB5_AUTH_CONTEXT_RET_SEQUENCE|KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
return(KRB5KRB_AP_ERR_MSG_TYPE);
}
if (!(ret = krb5_read_message(kcontext, sock, &read_data))) {
if (!(ret = krb5_rd_priv(kcontext,
ctx,
&read_data,
&msg_data,
&replay_data))) {
char *curr;
int replyok;
int i;
replyok = 0;
if (msg_data.length >= (2*sizeof(krb5_int32))) {
curr = msg_data.data;
kadm_copyin_int32(curr, cmd_stat);
curr += sizeof(krb5_int32);
kadm_copyin_int32(curr, ncomps);
curr += sizeof(krb5_int32);
if (*ncomps > 0) {
*complist = (krb5_data *)
malloc((size_t) ((*ncomps) * sizeof(krb5_data)));
if (*complist) {
krb5_data *xcomplist;
xcomplist = *complist;
memset((char *) (xcomplist), 0,
(size_t) ((*ncomps) * sizeof(krb5_data)));
replyok = 1;
for (i=0; i<*ncomps; i++) {
if (curr + sizeof(krb5_int32) - msg_data.data <=
msg_data.length) {
kadm_copyin_int32(curr, &len32);
xcomplist[i].length = (int) len32;
curr += sizeof(krb5_int32);
if ((curr + xcomplist[i].length -
msg_data.data <= msg_data.length) &&
(xcomplist[i].data = (char *)
malloc(xcomplist[i].length+1))) {
memcpy(xcomplist[i].data,
curr,
xcomplist[i].length);
curr += xcomplist[i].length;
xcomplist[i].data[xcomplist[i].length]
= '\0';
}
else {
replyok = 0;
break;
}
}
else {
replyok = 0;
break;
}
}
if (!replyok)
krb5_free_adm_data(kcontext, *ncomps, *complist);
}
}
else {
if (*ncomps == 0) {
*complist = (krb5_data *) NULL;
replyok = 1;
}
}
}
if (!replyok) {
ret = KRB5KRB_AP_ERR_MSG_TYPE;
}
memset(msg_data.data, 0, msg_data.length);
krb5_xfree(msg_data.data);
}
krb5_xfree(read_data.data);
}
return(ret);
}