summaryrefslogtreecommitdiffstats
path: root/src/kadmin/server/adm_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/server/adm_server.c')
-rw-r--r--src/kadmin/server/adm_server.c480
1 files changed, 480 insertions, 0 deletions
diff --git a/src/kadmin/server/adm_server.c b/src/kadmin/server/adm_server.c
new file mode 100644
index 000000000..c61a8dad4
--- /dev/null
+++ b/src/kadmin/server/adm_server.c
@@ -0,0 +1,480 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Top-level loop of the Kerberos Version 5 Administration server
+ */
+
+/*
+ * 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_server_c[] =
+"$Header$";
+#endif /* lint */
+
+/*
+ adm_server.c
+ this holds the main loop and initialization and cleanup code for the server
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <string.h>
+#include <com_err.h>
+
+#include <signal.h>
+#ifndef sigmask
+#define sigmask(m) (1 <<((m)-1))
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#ifndef __STDC__
+#include <varargs.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/mit-des.h>
+#include <krb5/kdb_dbm.h>
+
+#include <krb5/adm_defs.h>
+#include "adm_server.h"
+#include "adm_extern.h"
+
+global_client_server_info client_server_info;
+
+#ifdef SANDIA
+int classification; /* default = Unclassified */
+#endif
+
+krb5_flags NEW_ATTRIBUTES;
+
+cleanexit(val)
+ int val;
+{
+ (void) krb5_db_fini();
+ exit(val);
+}
+
+krb5_error_code
+closedown_db()
+{
+ krb5_error_code retval;
+
+ /* clean up master key stuff */
+ retval = krb5_finish_key(&master_encblock);
+
+ memset((char *)&master_encblock, 0, sizeof(master_encblock));
+ memset((char *)tgs_key.contents, 0, tgs_key.length);
+
+ /* close database */
+ if (retval) {
+ (void) krb5_db_fini();
+ return(retval);
+ } else
+ return(krb5_db_fini());
+}
+
+void
+usage(name)
+char *name;
+{
+ fprintf(stderr, "Usage: %s\t[-a aclfile] [-d dbname] [-k masterkeytype]",
+ name);
+ fprintf(stderr, "\n\t[-h] [-m] [-M masterkeyname] [-r realm]\n");
+ return;
+}
+
+krb5_error_code
+process_args(argc, argv)
+int argc;
+char **argv;
+{
+ krb5_error_code retval;
+ int c;
+ krb5_boolean manual = FALSE;
+ int keytypedone = 0;
+ char *db_realm = 0;
+ char *mkey_name = 0;
+ char *local_realm;
+ krb5_enctype etype;
+
+#ifdef SANDIA
+ char input_string[80];
+ FILE *startup_file;
+#endif
+
+ extern char *optarg;
+
+#ifdef SANDIA
+ classification = 0;
+
+ if ((startup_file =
+ fopen(DEFAULT_KDCPARM_NAME, "r")) == (FILE *) 0) {
+ syslog(LOG_ERR,
+ "Cannot open parameter file (%s) - Using default parameters",
+ DEFAULT_KDCPARM_NAME);
+ syslog(LOG_ERR, "Only Unclassified Principals will be allowed");
+ } else {
+ for ( ;; ) {
+ if ((fgets(input_string, sizeof(input_string), startup_file)) == NULL)
+ break;
+ kadmin_parse_and_set(input_string);
+ }
+ fclose(startup_file);
+ }
+#endif
+ while ((c = getopt(argc, argv, "hmMa:d:k:r:")) != EOF) {
+ switch(c) {
+ case 'a': /* new acl directory */
+ acl_file_name = optarg;
+ break;
+
+ case 'd':
+ /* put code to deal with alt database place */
+ dbm_db_name = optarg;
+ if (retval = krb5_dbm_db_set_name(dbm_db_name)) {
+ fprintf(stderr, "opening database %s: %s",
+ dbm_db_name, error_message(retval));
+ exit(1);
+ }
+ break;
+
+ case 'k': /* keytype for master key */
+ master_keyblock.keytype = atoi(optarg);
+ keytypedone++;
+ break;
+
+ case 'm': /* manual type-in of master key */
+ manual = TRUE;
+ break;
+
+ case 'M': /* master key name in DB */
+ mkey_name = optarg;
+ break;
+
+ case 'r':
+ db_realm = optarg;
+ break;
+
+ case 'h': /* get help on using adm_server */
+ default:
+ usage(argv[0]);
+ exit(1); /* Failure - Exit */
+ }
+
+ }
+
+ if (!db_realm) {
+ /* no realm specified, use default realm */
+ if (retval = krb5_get_default_realm(&local_realm)) {
+ com_err(argv[0], retval,
+ "while attempting to retrieve default realm");
+ exit(1);
+ }
+ db_realm = local_realm;
+ }
+
+ if (!mkey_name) {
+ mkey_name = KRB5_KDB_M_NAME;
+ }
+
+ if (!keytypedone) {
+ master_keyblock.keytype = KEYTYPE_DES;
+ }
+
+ /* assemble & parse the master key name */
+ if (retval = krb5_db_setup_mkey_name(mkey_name,
+ db_realm,
+ (char **) 0,
+ &master_princ)) {
+ com_err(argv[0], retval, "while setting up master key name");
+ exit(1);
+ }
+
+ master_encblock.crypto_entry = &mit_des_cryptosystem_entry;
+
+ if (retval = krb5_db_fetch_mkey(
+ master_princ,
+ &master_encblock,
+ manual,
+ FALSE, /* only read it once, if at all */
+ 0, /* No salt supplied */
+ &master_keyblock)) {
+ com_err(argv[0], retval, "while fetching master key");
+ exit(1);
+ }
+
+ /* initialize random key generators */
+ for (etype = 0; etype <= krb5_max_cryptosystem; etype++) {
+ if (krb5_csarray[etype]) {
+ if (retval = (*krb5_csarray[etype]->system->
+ init_random_key)(&master_keyblock,
+ &krb5_csarray[etype]->random_sequence)) {
+ com_err(argv[0], retval,
+ "while setting up random key generator for etype %d--etype disabled",
+ etype);
+ krb5_csarray[etype] = 0;
+ }
+ }
+ }
+
+ return(0);
+}
+
+krb5_error_code
+init_db(dbname, masterkeyname, masterkeyblock)
+char *dbname;
+krb5_principal masterkeyname;
+krb5_keyblock *masterkeyblock;
+
+{
+ krb5_error_code retval;
+
+ krb5_db_entry server_entry;
+ krb5_boolean more;
+ int number_of_entries;
+ char tgs_name[255];
+
+ /* set db name if appropriate */
+ if (dbname && (retval = krb5_db_set_name(dbname)))
+ return(retval);
+
+ /* initialize database */
+ if (retval = krb5_db_init())
+ return(retval);
+
+ if (retval = krb5_db_verify_master_key(masterkeyname,
+ masterkeyblock,
+ &master_encblock)) {
+ master_encblock.crypto_entry = 0;
+ return(retval);
+ }
+
+ /* do any necessary key pre-processing */
+ if (retval = krb5_process_key(&master_encblock, masterkeyblock)) {
+ master_encblock.crypto_entry = 0;
+ (void) krb5_db_fini();
+ return(retval);
+ }
+
+/*
+ fetch the TGS key, and hold onto it; this is an efficiency hack
+ the master key name here is from the master_princ global,
+ so we can safely share its substructure
+ */
+ strcpy(tgs_name, TGTNAME);
+ strcat(tgs_name, "/");
+ strcat(tgs_name, masterkeyname->realm.data);
+ krb5_parse_name(tgs_name, &tgs_server);
+
+ tgs_server->type = KRB5_NT_SRV_INST;
+
+ number_of_entries = 1;
+ if (retval = krb5_db_get_principal(
+ tgs_server,
+ &server_entry,
+ &number_of_entries,
+ &more)) {
+ return(retval);
+ }
+
+ if (more) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ (void) krb5_finish_key(&master_encblock);
+ memset((char *)&master_encblock, 0, sizeof(master_encblock));
+ (void) krb5_db_fini();
+ return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+ } else if (number_of_entries != 1) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ (void) krb5_finish_key(&master_encblock);
+ memset((char *)&master_encblock, 0, sizeof(master_encblock));
+ (void) krb5_db_fini();
+ return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
+ }
+
+/*
+ convert server.key into a real key
+ (it may be encrypted in the database)
+ */
+ if (retval = KDB_CONVERT_KEY_OUTOF_DB(&server_entry.key, &tgs_key)) {
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ (void) krb5_finish_key(&master_encblock);
+ memset((char *)&master_encblock, 0, sizeof(master_encblock));
+ (void) krb5_db_fini();
+ return(retval);
+ }
+
+ tgs_kvno = server_entry.kvno;
+ krb5_db_free_principal(&server_entry, number_of_entries);
+ return(0);
+}
+
+krb5_sigtype
+request_exit()
+{
+ signal_requests_exit = 1;
+ return;
+}
+
+void
+setup_signal_handlers()
+{
+ krb5_sigtype request_exit();
+
+ (void)signal(SIGINT, request_exit);
+ (void)signal(SIGHUP, request_exit);
+ (void)signal(SIGTERM, request_exit);
+ return;
+}
+
+static void
+kdc_com_err_proc(whoami, code, format, pvar)
+ const char *whoami;
+ long code;
+ const char *format;
+ va_list pvar;
+{
+#ifndef __STDC__
+ extern int vfprintf();
+#endif
+
+ if (whoami) {
+ fputs(whoami, stderr);
+ fputs(": ", stderr);
+ }
+
+ if (code) {
+ fputs(error_message(code), stderr);
+ fputs(" ", stderr);
+ }
+
+ if (format) {
+ vfprintf (stderr, format, pvar);
+ }
+
+ putc('\n', stderr);
+ /* should do this only on a tty in raw mode */
+ putc('\r', stderr);
+ fflush(stderr);
+
+ if (format) {
+ /* now need to frob the format a bit... */
+ if (code) {
+ char *nfmt;
+ nfmt = (char *) malloc(
+ strlen(format)+strlen(error_message(code))+2);
+ strcpy(nfmt, error_message(code));
+ strcat(nfmt, " ");
+ strcat(nfmt, format);
+ vsyslog(LOG_ERR, nfmt, pvar);
+ } else {
+ vsyslog(LOG_ERR, format, pvar);
+ }
+ } else {
+ if (code) {
+ syslog(LOG_ERR, "%s", error_message(code));
+ }
+ }
+ return;
+}
+
+void
+setup_com_err()
+{
+ initialize_krb5_error_table();
+ initialize_kdb5_error_table();
+ initialize_isod_error_table();
+
+ (void) set_com_err_hook(kdc_com_err_proc);
+ return;
+}
+
+/*
+** Main does the logical thing, it sets up the database and RPC interface,
+** as well as handling the creation and maintenance of the syslog file...
+*/
+main(argc, argv) /* adm_server main routine */
+int argc;
+char **argv;
+{
+ krb5_error_code retval;
+ int errout = 0;
+
+ adm5_ver_len = ADM5_VERSIZE;
+
+ /* Get the Name of this program (adm_server) for Error Messages */
+ if (strrchr(argv[0], '/'))
+ argv[0] = (char *)strrchr(argv[0], '/') + 1;
+
+ setup_com_err();
+
+ /* Use Syslog for Messages */
+#ifndef LOG_AUTH /* 4.2 syslog */
+#define LOG_AUTH 0
+ openlog(argv[0], LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6);
+#else
+ openlog(argv[0], LOG_AUTH|LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6);
+#endif /* LOG_AUTH */
+
+ process_args(argc, argv); /* includes reading master key */
+
+ setup_signal_handlers();
+
+ if (retval = init_db(dbm_db_name,
+ master_princ,
+ &master_keyblock)) {
+ com_err(argv[0], retval, "while initializing database");
+ exit(1);
+ }
+
+ if (retval = setup_network(argv[0])) {
+ exit(1);
+ }
+
+ syslog(LOG_AUTH | LOG_INFO, "Admin Server Commencing Operation");
+
+ if (retval = adm5_listen_and_process(argv[0])){
+ krb5_free_principal(client_server_info.server);
+ com_err(argv[0], retval, "while processing network requests");
+ errout++;
+ }
+
+ free(client_server_info.name_of_service);
+ krb5_free_principal(client_server_info.server);
+
+shutdown:
+ if (errout = closedown_network(argv[0])) {
+ com_err(argv[0], retval, "while shutting down network");
+ retval = retval + errout;
+ }
+
+ if (errout = closedown_db()) {
+ com_err(argv[0], retval, "while closing database");
+ retval = retval + errout;
+ }
+
+ syslog(LOG_AUTH | LOG_INFO, "Admin Server Shutting Down");
+
+ printf("Admin Server (kadmind) has completed operation.\n");
+
+ exit(retval);
+}