/* * lib/kadm/adm_rw.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * Routines to engage in the administrative (password changing) protocol. */ #define NEED_SOCKETS #include "k5-int.h" #include "adm_proto.h" /* * Local prototypes (needed or else the PC will pass fail). */ static void kadm_copyin_int32 PROTOTYPE((char *, krb5_int32 *)); static void kadm_copyout_int32 PROTOTYPE((krb5_int32, char *)); /* * Routines to [de]serialize integers. * * kadm_copyin_int32 - Move a 32-bit integer fron network byte order to * host byte order. * kadm_copyout_int32 - Move a 32-bit integer from host byte order to * network byte order. */ 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); } /* * krb5_free_adm_data() - Free data blocks allocated by read_adm... routines. */ void INTERFACE krb5_free_adm_data(kcontext, ncomp, datap) krb5_context kcontext; krb5_int32 ncomp; krb5_data *datap; { int i; if (datap) { for (i=0; i 0)) krb5_xfree(datap[i].data); krb5_xfree(datap); } } /* * krb5_send_adm_cmd() - Send an administrative command. * * Send a list of data in a KRB_PRIV message. Data takes the format: * nargs (4 octets in network order) * arg size 1 (4 octets in network order) * arg data 1 ("arg size 1" octets) * . * . * . */ krb5_error_code INTERFACE krb5_send_adm_cmd(kcontext, sock, ctx, nargs, arglist) krb5_context kcontext; /* Context handle (In ) */ krb5_pointer sock; /* Socket to write to (In ) */ krb5_auth_context ctx; /* Auth context (In ) */ krb5_int32 nargs; /* Number of arguments (In ) */ krb5_data *arglist; /* Components to write (In ) */ { int writebufsize; int i; char *writebuf; krb5_error_code ret; krb5_int32 ac_flags; /* * First check that our auth context has the right flags in it. */ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags)) 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)) { /* XXX - need a better error */ return(KRB5KRB_AP_ERR_MSG_TYPE); } ret = 0; /* Calculate write buffer size */ writebufsize = sizeof(krb5_int32); for (i=0; i= sizeof(krb5_int32)) { curr = msg_data.data; kadm_copyin_int32(curr, nargs); curr += sizeof(krb5_int32); /* Are there any components to copy? */ if (*nargs > 0) { /* Get the memory for the list */ if (*arglist = (krb5_data *) malloc((size_t) (*nargs) * sizeof(krb5_data))) { krb5_data *xarglist; xarglist = *arglist; memset((char *) (xarglist), 0, (size_t) (*nargs) * sizeof(krb5_data)); replyok = 1; /* Copy out each list entry */ for (i=0; i<*nargs; i++) { /* First get the length of the reply component */ 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); /* Then get the memory for the actual data */ if ((curr + xarglist[i].length - msg_data.data <= msg_data.length) && (xarglist[i].data = (char *) malloc(xarglist[i].length+1))) { /* Then copy it out */ memcpy(xarglist[i].data, curr, xarglist[i].length); curr += xarglist[i].length; /* Null terminate for convenience */ xarglist[i].data[xarglist[i].length] = '\0'; } else { /* Not enough remaining data. */ replyok = 0; break; } } else { /* Not enough remaining data */ 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; /* syntax error */ } memset(msg_data.data, 0, msg_data.length); krb5_xfree(msg_data.data); } krb5_xfree(read_data.data); } return(ret); } /* * krb5_read_adm_reply() - Read an administrative protocol response. * * Expect to read them out in the same format as send_adm_reply shoots them * in. * * It is the caller's responsibility to free the memory allocated for * the read in component list. */ krb5_error_code INTERFACE krb5_read_adm_reply(kcontext, sock, ctx, cmd_stat, ncomps, complist) krb5_context kcontext; /* Context handle (In ) */ krb5_pointer sock; /* Socket to read from (In ) */ krb5_auth_context ctx; /* Auth context (In ) */ krb5_int32 *cmd_stat; /* Command status (Out) */ krb5_int32 *ncomps; /* # of reply components(Out) */ krb5_data **complist; /* List of components (Out) */ { krb5_data read_data; krb5_error_code ret; krb5_data msg_data; krb5_replay_data replay_data; krb5_int32 ac_flags; krb5_int32 len32; /* * First check that our auth context has the right flags in it. */ if (ret = krb5_auth_con_getflags(kcontext, ctx, &ac_flags)) 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)) { /* XXX - need a better error */ 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; /* We'd better have at least two reply components */ 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); /* Are there any components to copy? */ if (*ncomps > 0) { /* Get the memory for the list */ if (*complist = (krb5_data *) malloc((size_t) ((*ncomps) * sizeof(krb5_data)))) { krb5_data *xcomplist; xcomplist = *complist; memset((char *) (xcomplist), 0, (size_t) ((*ncomps) * sizeof(krb5_data))); replyok = 1; /* Copy out each list entry */ for (i=0; i<*ncomps; i++) { /* First get the length of the reply component */ 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); /* Then get the memory for the actual data */ if ((curr + xcomplist[i].length - msg_data.data <= msg_data.length) && (xcomplist[i].data = (char *) malloc(xcomplist[i].length+1))) { /* Then copy it out */ memcpy(xcomplist[i].data, curr, xcomplist[i].length); curr += xcomplist[i].length; /* Null terminate for convenience */ xcomplist[i].data[xcomplist[i].length] = '\0'; } else { /* Not enough remaining data. */ replyok = 0; break; } } else { /* Not enough remaining data */ 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; /* syntax error */ } memset(msg_data.data, 0, msg_data.length); krb5_xfree(msg_data.data); } krb5_xfree(read_data.data); } return(ret); }