summaryrefslogtreecommitdiffstats
path: root/src/kadmin/server/adm_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/server/adm_process.c')
-rw-r--r--src/kadmin/server/adm_process.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/src/kadmin/server/adm_process.c b/src/kadmin/server/adm_process.c
new file mode 100644
index 000000000..0e3d0d478
--- /dev/null
+++ b/src/kadmin/server/adm_process.c
@@ -0,0 +1,454 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/*
+ * Sandia National Laboratories also makes no representations about the
+ * suitability of the modifications, or additions to this software for
+ * any purpose. It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_process[] =
+"$Header$";
+#endif /* lint */
+
+/*
+ adm_process.c
+*/
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+
+struct cpw_keyproc_arg {
+ krb5_keyblock *key;
+};
+
+static krb5_error_code
+cpw_keyproc(DECLARG(krb5_pointer, keyprocarg),
+ DECLARG(krb5_principal, server),
+ DECLARG(krb5_kvno, key_vno),
+ DECLARG(krb5_keyblock **, key))
+OLDDECLARG(krb5_pointer, keyprocarg)
+OLDDECLARG(krb5_principal, server)
+OLDDECLARG(krb5_kvno, key_vno)
+OLDDECLARG(krb5_keyblock **, key)
+{
+ krb5_error_code retval;
+ krb5_db_entry cpw_entry;
+ krb5_principal cpw_krb;
+ krb5_keyblock *realkey;
+
+ struct cpw_keyproc_arg *arg;
+
+ krb5_boolean more;
+
+ int nprincs = 1;
+
+ arg = ( struct cpw_keyproc_arg *) keyprocarg;
+
+ if (arg->key) {
+ *key = arg->key;
+ } else {
+ if (retval = krb5_parse_name(client_server_info.name_of_service,
+ &cpw_krb)) {
+ syslog(LOG_ERR,
+ "cpw_keyproc %d while attempting to parse \"%s\"",
+ client_server_info.name_of_service, retval);
+ return(0);
+ }
+
+ if (retval = krb5_db_get_principal(cpw_krb, &cpw_entry,
+ &nprincs, &more)) {
+ syslog(LOG_ERR,
+ "cpw_keyproc %d while extracting %s entry",
+ client_server_info.name_of_service, retval);
+ return(0);
+ }
+
+ if (!nprincs) return(0);
+
+ if ((realkey = (krb5_keyblock *) calloc (1,
+ sizeof(krb5_keyblock))) == (krb5_keyblock * ) 0) {
+ krb5_db_free_principal(&cpw_entry, nprincs);
+ syslog(LOG_ERR, "cpw_keyproc: No Memory for server key");
+ close(client_server_info.client_socket);
+ return(0);
+ }
+
+ /* Extract the real kadmin/<realm> keyblock */
+ if (retval = krb5_kdb_decrypt_key(
+ &master_encblock,
+ &cpw_entry.key,
+ realkey)) {
+ krb5_db_free_principal(&cpw_entry, nprincs);
+ free(realkey);
+ syslog(LOG_ERR,
+ "cpw_keyproc: Cannot extract %s from master key",
+ client_server_info.name_of_service);
+ exit(0);
+ }
+
+ *key = realkey;
+ }
+
+ return(0);
+}
+
+krb5_error_code
+process_client(prog)
+char *prog;
+{
+ krb5_error_code retval;
+
+ struct cpw_keyproc_arg cpw_key;
+
+ int on = 1;
+ krb5_db_entry server_entry;
+
+ krb5_ticket *client_creds;
+ krb5_authenticator *client_auth_data;
+ char retbuf[512];
+
+ krb5_data final_msg;
+ char completion_msg[520];
+ kadmin_requests request_type;
+
+ int number_of_entries;
+ krb5_boolean more;
+ int namelen;
+
+ char *req_type = "";
+ int otype;
+
+ u_short data_len;
+ krb5_data outbuf;
+ krb5_data inbuf, msg_data;
+ extern int errno;
+
+ krb5_timestamp adm_time;
+
+ outbuf.data = retbuf;
+ if (setsockopt(client_server_info.client_socket,
+ SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) {
+ syslog(LOG_ERR, "adm_process: setsockopt keepalive: %d", errno);
+ }
+
+ /* V4 kpasswd Protocol Hack */
+ /* Read Length of Data */
+ retval = krb5_net_read(client_server_info.client_socket,
+ (char *) &data_len, 2);
+ if (retval < 0) {
+ syslog(LOG_ERR, "kadmind error: net_read Length Failure");
+ (void) sprintf(retbuf, "kadmind error during net_read for Length\n");
+ exit(0);
+ }
+
+ if (retval = krb5_db_init()) { /* Open as client */
+ syslog(LOG_ERR, "adm_process: Can't Open Database");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+/* Get Server Credentials for Mutual Authentication and Private
+ * Messages Note: Here client is the kadmin/<realm> server
+ */
+ number_of_entries = 1;
+ if ((retval = krb5_db_get_principal(client_server_info.server,
+ &server_entry,
+ &number_of_entries,
+ &more))) {
+ syslog(LOG_ERR,
+ "kadmind error: krb5_db_get_principal error: %d", retval);
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ if (more) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ syslog(LOG_ERR, "kadmind error: kadmin/<realm> service not unique");
+ exit(1);
+ }
+
+ if (number_of_entries != 1) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ syslog(LOG_ERR, "kadmind error: kadmin/<realm> service UNKNOWN");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ if ((cpw_key.key = (krb5_keyblock *) calloc (1,
+ sizeof(krb5_keyblock))) == (krb5_keyblock *) 0) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ syslog(LOG_ERR,
+ "kadmind error: No Memory for server key");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ /* Extract the real kadmin/<realm> keyblock */
+ if (retval = krb5_kdb_decrypt_key(
+ &master_encblock,
+ &server_entry.key,
+ (krb5_keyblock *) cpw_key.key)) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ free(cpw_key.key);
+ syslog(LOG_ERR,
+ "kadmind error: Cannot extract kadmin/<realm> from master key");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+/*
+ * To verify authenticity, we need to know the address of the
+ * client.
+ */
+
+ namelen = sizeof(client_server_info.client_addr);
+ if (getpeername(client_server_info.client_socket,
+ (struct sockaddr *) &client_server_info.client_addr,
+ &namelen) < 0) {
+ syslog(LOG_ERR, "kadmind error: Unable to Obtain Client Name.");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ /* we use mutual authentication */
+ client_server_info.client_addr.addrtype =
+ client_server_info.client_name.sin_family;
+ client_server_info.client_addr.length = SIZEOF_INADDR;
+ client_server_info.client_addr.contents =
+ (krb5_octet *) &client_server_info.client_name.sin_addr;
+
+ client_server_info.server_addr.addrtype =
+ client_server_info.server_name.sin_family;
+ client_server_info.server_addr.length = SIZEOF_INADDR;
+ client_server_info.server_addr.contents =
+ (krb5_octet *) &client_server_info.server_name.sin_addr;
+
+ krb5_init_ets();
+
+ syslog(LOG_AUTH | LOG_INFO,
+ "Request for Administrative Service Received from %s - Authenticating.",
+ inet_ntoa( client_server_info.client_name.sin_addr ));
+
+ if ((retval = krb5_recvauth(
+ (krb5_pointer) &client_server_info.client_socket,
+ ADM5_CPW_VERSION,
+ client_server_info.server,
+ &client_server_info.client_addr,
+ 0,
+ cpw_keyproc,
+ (krb5_pointer) &cpw_key,
+ 0,
+ &send_seqno,
+ &client_server_info.client,
+ &client_creds,
+ &client_auth_data
+ ))) {
+ syslog(LOG_ERR, "kadmind error: %s during recvauth\n",
+ error_message(retval));
+ (void) sprintf(retbuf, "kadmind error during recvauth: %s\n",
+ error_message(retval));
+ } else {
+ /* Check if ticket was issued using password (and not tgt)
+ within the last 5 minutes */
+
+ if (!(client_creds->enc_part2->flags & TKT_FLG_INITIAL)) {
+ syslog(LOG_ERR,
+ "Client ticket not initial");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ if (retval = krb5_timeofday(&adm_time)) {
+ syslog(LOG_ERR,
+ "Can't get time of day");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ if ((client_creds->enc_part2->times.authtime - adm_time) > 60*5) {
+ syslog(LOG_ERR,
+ "Client ticket not recent");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ recv_seqno = client_auth_data->seq_number;
+
+ if ((client_server_info.name_of_client =
+ (char *) calloc (1, 3 * 255)) == (char *) 0) {
+ syslog(LOG_ERR, "kadmind error: No Memory for name_of_client");
+ close(client_server_info.client_socket);
+ exit(0);
+ }
+
+ if ((retval = krb5_unparse_name(client_server_info.client,
+ &client_server_info.name_of_client))) {
+ syslog(LOG_ERR, "kadmind error: unparse failed.",
+ error_message(retval));
+ goto finish;
+ }
+
+ syslog(LOG_AUTH | LOG_INFO,
+ "Request for Administrative Service Received from %s at %s.",
+ client_server_info.name_of_client,
+ inet_ntoa( client_server_info.client_name.sin_addr ));
+
+ /* compose the reply */
+ outbuf.data[0] = KADMIND;
+ outbuf.data[1] = KADMSAG;
+ outbuf.length = 2;
+ }
+
+ /* write back the response */
+ if ((retval = krb5_write_message(&client_server_info.client_socket,
+ &outbuf))){
+ syslog(LOG_ERR, "kadmind error: Write Message Failure: %s",
+ error_message(retval));
+ retval = 1;
+ goto finish;
+ }
+
+ /* Ok Now let's get the first private message and respond */
+ if (retval = krb5_read_message(&client_server_info.client_socket,
+ &inbuf)){
+ syslog(LOG_ERR, "kadmind error: read First Message Failure: %s",
+ error_message(retval));
+ retval = 1;
+ goto finish;
+ }
+
+ if ((retval = krb5_rd_priv(&inbuf,
+ client_creds->enc_part2->session,
+ &client_server_info.client_addr,
+ &client_server_info.server_addr,
+ client_auth_data->seq_number,
+ KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+ 0,
+ 0,
+ &msg_data))) {
+ syslog(LOG_ERR, "kadmind error: rd_priv:%s\n", error_message(retval));
+ goto finish;
+ }
+ free(inbuf.data);
+
+ request_type.appl_code = msg_data.data[0];
+ request_type.oper_code = msg_data.data[1];
+
+ free(msg_data.data);
+
+ switch (request_type.appl_code) {
+ case KPASSWD:
+ req_type = "kpasswd";
+ if (retval = adm5_kpasswd("process_client", &request_type,
+ client_creds, retbuf, &otype)) {
+ goto finish;
+ }
+ break;
+
+ case KADMIN:
+ req_type = "kadmin";
+ if (retval = adm5_kadmin("process_client", client_auth_data,
+ client_creds, retbuf, &otype)) {
+ goto finish;
+ }
+ retbuf[0] = KADMIN;
+ retbuf[2] = KADMGOOD;
+ retbuf[3] = '\0';
+ otype = 0;
+ break;
+
+ default:
+ retbuf[0] = KUNKNOWNAPPL;
+ retbuf[1] = '\0';
+ sprintf(completion_msg, "%s from %s (%02x) FAILED",
+ "Unknown Application Type!",
+ inet_ntoa(client_server_info.client_name.sin_addr),
+ request_type.appl_code);
+ /* Service Not Supported */
+ retval = 255;
+ syslog(LOG_AUTH | LOG_INFO, completion_msg);
+ goto finish;
+ } /* switch(request_type.appl_code) */
+
+ if ((final_msg.data = (char *) calloc(1,10)) == (char *) 0) {
+ syslog(LOG_ERR | LOG_INFO, "no Memory while allocating final_msg.data");
+ return ENOMEM;
+ }
+ final_msg.data = retbuf;
+ final_msg.length = strlen(retbuf) + 1;
+
+ /* Send Completion Message */
+ if (retval = krb5_mk_priv(&final_msg,
+ ETYPE_DES_CBC_CRC,
+ client_creds->enc_part2->session,
+ &client_server_info.server_addr,
+ &client_server_info.client_addr,
+ send_seqno,
+ KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+ 0,
+ 0,
+ &msg_data)) {
+ syslog(LOG_ERR, "kadmind error Error Performing Final mk_priv");
+ free(final_msg.data);
+ goto finish;
+ }
+ free(final_msg.data);
+
+ /* Send Final Reply to Client */
+ if (retval = krb5_write_message(&client_server_info.client_socket,
+ &msg_data)){
+ syslog(LOG_ERR, "Error Performing Final Write: %s",
+ error_message(retval));
+ retval = 1;
+ goto finish;
+ }
+ free(msg_data.data);
+
+finish:
+
+ if (retval) {
+ free (client_server_info.name_of_client);
+ close(client_server_info.client_socket);
+ exit(1);
+ }
+
+ sprintf(completion_msg,
+ "%s %s for %s at %s - Completed Successfully",
+ req_type,
+ oper_type[otype],
+ client_server_info.name_of_client,
+ inet_ntoa( client_server_info.client_name.sin_addr ));
+ syslog(LOG_AUTH | LOG_INFO, completion_msg);
+ free (client_server_info.name_of_client);
+ close(client_server_info.client_socket);
+ return 0;
+}