--- /dev/null
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+LDFLAGS = -g
+
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+SSLIB=$(BUILDTOP)/util/ss/libss.a
+DBMLIB=
+KDBLIB=$(TOPLIBD)/libkdb5.a
+
+all::
+
+KLIB = $(KDBLIB) $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+DEPKLIB = $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+
+SRCS = \
+ $(srcdir)/srv_main.c $(srcdir)/srv_key.c \
+ $(srcdir)/srv_acl.c $(srcdir)/srv_output.c $(srcdir)/srv_net.c \
+ $(srcdir)/proto_serv.c $(srcdir)/passwd.c
+
+OBJS = \
+ srv_main.o srv_key.o srv_acl.o srv_output.o srv_net.o \
+ proto_serv.o passwd.o
+
+
+all:: kadmind5
+
+kadmind5: $(KDBDEPLIB) $(OBJS) $(DEPKLIB)
+ $(CC) $(CFLAGS) -o kadmind5 $(OBJS) $(KLIB) $(LIBS)
+
+install::
+ $(INSTALL_PROGRAM) kadmind5 ${DESTDIR}$(CLIENT_BINDIR)/kadmind5
+ $(INSTALL_DATA) $(srcdir)/kadmind5.M ${DESTDIR}$(CLIENT_MANDIR)/kadmind.8
+
+clean::
+ $(RM) kadmind5
+
--- /dev/null
+AC_INIT(srv_main.c)
+WITH_CCOPTS
+CONFIG_RULES
+AC_SET_BUILDTOP
+AC_PROG_INSTALL
+WITH_NETLIB
+AC_FUNC_CHECK(waitpid,AC_DEFINE(HAVE_WAITPID))
+CHECK_WAIT_TYPE
+ET_RULES
+KRB_INCLUDE
+WITH_KRB5ROOT
+V5_AC_OUTPUT_MAKEFILE
--- /dev/null
+/*
+ * kadmin/v5server/kadm5_defs.h
+ *
+ * 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.
+ *
+ */
+
+/*
+ * kadmind5
+ * Version 5 administrative daemon.
+ */
+#ifndef KADM5_DEFS_H__
+#define KADM5_DEFS_H__
+
+/*
+ * Debug definitions.
+ */
+#define DEBUG_SPROC 1
+#define DEBUG_OPERATION 2
+#define DEBUG_HOST 4
+#define DEBUG_REALM 8
+#define DEBUG_REQUESTS 16
+#define DEBUG_ACL 32
+#define DEBUG_PROTO 64
+#define DEBUG_CALLS 128
+#ifdef DEBUG
+#define DPRINT(l1, cl, al) if ((cl & l1) != 0) printf al
+#else /* DEBUG */
+#define DPRINT(l1, cl, al)
+#endif /* DEBUG */
+#define DLOG(l1, cl, msg) if ((cl & l1) != 0) \
+ com_err(programname, 0, msg)
+
+/*
+ * Access control bits.
+ */
+#define ACL_ADD_PRINCIPAL 1
+#define ACL_DELETE_PRINCIPAL 2
+#define ACL_MODIFY_PRINCIPAL 4
+#define ACL_CHANGEPW 8
+#define ACL_CHANGE_OWN_PW 16
+#define ACL_INQUIRE 32
+
+#define ACL_PRINCIPAL_MASK (ACL_ADD_PRINCIPAL|ACL_DELETE_PRINCIPAL|\
+ ACL_MODIFY_PRINCIPAL)
+#define ACL_PASSWD_MASK (ACL_CHANGEPW|ACL_CHANGE_OWN_PW)
+#define ACL_ALL_MASK (ACL_ADD_PRINCIPAL | \
+ ACL_DELETE_PRINCIPAL | \
+ ACL_MODIFY_PRINCIPAL | \
+ ACL_CHANGEPW | \
+ ACL_CHANGE_OWN_PW | \
+ ACL_INQUIRE)
+/*
+ * Inter-module function prototypes
+ */
+
+/* srv_key.c */
+krb5_error_code key_init
+ PROTOTYPE((krb5_context,
+ int,
+ int,
+ int,
+ char *,
+ int,
+ char *,
+ char *));
+void key_finish
+ PROTOTYPE((krb5_context,
+ int));
+krb5_error_code key_string_to_keys
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_data *,
+ krb5_int32,
+ krb5_int32,
+ krb5_keyblock *,
+ krb5_keyblock *));
+krb5_error_code key_encrypt_keys
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_keyblock *,
+ krb5_keyblock *,
+ krb5_encrypted_keyblock *,
+ krb5_encrypted_keyblock *));
+krb5_error_code key_decrypt_keys
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_encrypted_keyblock *,
+ krb5_encrypted_keyblock *,
+ krb5_keyblock *,
+ krb5_keyblock *));
+krb5_boolean key_pwd_is_weak
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_data *,
+ krb5_int32,
+ krb5_int32));
+
+/* srv_acl.c */
+krb5_error_code acl_init
+ PROTOTYPE((krb5_context,
+ int,
+ char *));
+void acl_finish
+ PROTOTYPE((krb5_context,
+ int));
+krb5_boolean acl_op_permitted
+ PROTOTYPE((krb5_context,
+ krb5_principal,
+ krb5_int32));
+
+/* srv_output.c */
+krb5_error_code output_init
+ PROTOTYPE((krb5_context,
+ int,
+ char *,
+ krb5_boolean));
+void output_finish
+ PROTOTYPE((krb5_context,
+ int));
+krb5_boolean output_lang_supported
+ PROTOTYPE((char *));
+char *output_krb5_errmsg
+ PROTOTYPE((char *,
+ krb5_boolean,
+ krb5_int32));
+char *output_adm_error
+ PROTOTYPE((char *,
+ krb5_boolean,
+ krb5_int32,
+ krb5_int32,
+ krb5_int32,
+ krb5_data *));
+
+/* srv_net.c */
+krb5_error_code net_init
+ PROTOTYPE((krb5_context,
+ int));
+void net_finish
+ PROTOTYPE((krb5_context,
+ int));
+krb5_error_code net_dispatch
+ PROTOTYPE((krb5_context));
+krb5_principal net_server_princ();
+
+/* proto_serv.c */
+krb5_error_code proto_init
+ PROTOTYPE((krb5_context,
+ int,
+ int));
+void proto_finish
+ PROTOTYPE((krb5_context,
+ int));
+krb5_error_code proto_serv
+ PROTOTYPE((krb5_context,
+ krb5_int32,
+ int,
+ void *,
+ void *));
+
+/* passwd.c */
+krb5_int32 passwd_check
+ PROTOTYPE((krb5_context,
+ int,
+ krb5_auth_context *,
+ krb5_ticket *,
+ krb5_data *,
+ krb5_int32 *));
+krb5_int32 passwd_change
+ PROTOTYPE((krb5_context,
+ int,
+ krb5_auth_context *,
+ krb5_ticket *,
+ krb5_data *,
+ krb5_data *,
+ krb5_int32 *));
+
+#endif /* KADM5_DEFS_H__ */
--- /dev/null
+.\" $Source$
+.\" $Author$
+.\" $Id$
+.\"
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" 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.
+.\"
+.\"
+.TH KADMIND5 1 "Kerberos Version 5.0" "MIT Project Athena"
+.SH NAME
+kadmind5 \- network daemon for Kerberos version 5 database information
+.SH SYNOPSIS
+.B kadmind5
+[
+.B \-i
+] [
+.B \-a
+aclfile
+] [
+.B \-d
+dbname
+] [
+.B \-e
+enctype
+] [
+.B \-k
+mkeytype
+] [
+.B \-l
+langlist
+] [
+.B \-m
+1|0
+] [
+.B \-t
+timeout
+] [
+.B \-D
+debugmask
+] [
+.B \-M
+mkeyname
+]
+.SH DESCRIPTION
+.I kadmind5
+is the network database server for the Kerberos version 5
+password-changing and administration tools.
+
+.SH FLAGS
+.PP
+.B Database, Key and Realm flags
+.IP \-r
+.B realm
+specifies the realm that this server is to administer. The default is
+the local realm.
+.IP \-d
+.B dbname
+specifies the location of the database.
+.IP \-M
+.B mkeyname
+specifies the name of the master key.
+.IP \-k
+.B mkeytype
+specifies the master key type.
+.IP \-i
+Indicates that the master key name is to be entered interactively.
+.IP \-e
+.B enctype
+specifies the encryption type which is to be used.
+.PP
+.B ACL flag
+.IP \-a
+.B aclfile
+specifies the location of the ACL file. This file controls remote
+principals' abilities to perform administrative functions. See the
+ACL FILE section below for the format of this file.
+.PP
+.B Connection flag
+.IP \-t
+Indicates that the server is to terminate a connection if it remains
+inactive for
+.B timeout
+seconds.
+.PP
+.B Debugging flag
+.IP \-D
+Enables certain debugging features and messages selected by
+.B debugmask.
+.PP
+.B Protocol Message flags
+.IP \-l
+.B langlist
+specifies the list of supported language names [not implemented].
+.IP \-m
+Enables (
+.B 1
+) or disables (
+.B 0
+) MIME encoding support [not implemented].
+
+.SH ACL FILE
+.PP
+The ACL file controls which principals can or cannot perform which
+administrative functions. This file can contain comment lines, null
+lines or lines which contain ACL entries. Comment lines start with
+the sharp sign (
+.B \#
+) and continue until the end of the line. Lines containing ACL
+entries have the format of
+.B principal
+.I whitespace
+.B operation-mask.
+Ordering is important. The first matching entry is the one which will
+control access for a particular principal.
+.PP
+.IP principal
+may specify a partially or fully qualified Kerberos version 5
+principal name. Each component of the name may be wildcarded using
+the asterick (
+.B *
+) character.
+.IP operation-mask
+Specifies what operations may or may not be peformed by a principal
+matching a particular entry. This is a string of one or more of the
+following list of characters or their upper-case counterparts. If the
+character is upper-case, then the operation is disallowed. If the
+character is lower-case, then the operation is permitted.
+.TP i
+.I a
+[Dis]allows the addition of principals from the database.
+.TP i
+.I d
+[Dis]allows the deletion of principals from the database.
+.TP i
+.I m
+[Dis]allows the modification of principals in the database.
+.TP i
+.I c
+[Dis]allows the changing of passwords for principals in the database.
+.TP i
+.I o
+[Dis]allows the changing of the principal's own password in the
+database.
+.TP i
+.I i
+[Dis]allows inquiries to the database.
+.TP i
+.I p
+Short for
+.I adm.
+.TP i
+.I w
+Short for
+.I pw.
+.TP i
+.I x or *
+Short for
+.I admcoi.
+.PP
+Some examples of valid entries here are:
+.TP 2i
+.I user/instance@realm po
+A standard fully qualified name. The
+.B operation-mask
+only applies to this principal and specifies that [s]he may add,
+delete or modify principals and change his/her own password, but not
+anybody elses.
+.TP 2i
+.I user/*@realm aw
+A wildcarded name. The
+.B operation-mask
+applies to all principals in realm "realm" whose first component is
+"user" and specifies that [s]he may add principals and change anybody
+else's password or change his/her own.
+.TP 2i
+.I * o
+A catchall entry. The
+.B operation-mask
+applies to all principals and indicates that they may change their own
+passwords.
+
+.SH FILES
+.TP 2i
+/krb5/principal.*
+the default location of the database.
+.TP 2i
+/etc/krb5_adm.acl
+the default location of the ACL file.
+.SH SEE ALSO
+kpasswd(1), kadmin5(8)
+.SH BUGS
+
--- /dev/null
+/*
+ * kadmin/v5server/passwd.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.
+ *
+ */
+
+/*
+ * passwd.c - handle server password-related functions.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+#include "adm.h"
+
+/*
+ * These defines turn on various checking in passwd_check_npass_ok.
+ */
+#define KPWD_CHECK_LENGTH 1
+#define KPWD_CHECK_WEAKNESS 1
+
+#define KPWD_MIN_PWD_LENGTH 8
+
+extern char *programname;
+static const char *pwd_bad_old_pwd = "incorrect old password for %s";
+static const char *pwd_perm_denied = "ACL entry prevents password change for %s";
+static const char *pwd_changed_pwd = "changed password for %s";
+\f
+/*
+ * passwd_check_princ() - Check if the principal specified in the ticket is ok
+ */
+static krb5_error_code
+passwd_check_princ(kcontext, debug_level, ticket,
+ princp, namep, db_entp, db_numentp, db_morep)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_ticket *ticket;
+ krb5_principal *princp;
+ char **namep;
+ krb5_db_entry *db_entp;
+ int *db_numentp;
+ krb5_boolean *db_morep;
+{
+ krb5_error_code kret;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_check_princ()\n"));
+ *princp = (krb5_principal) NULL;
+ *namep = (char *) NULL;
+
+ /* Copy principal out of ticket */
+ if (kret = krb5_copy_principal(kcontext,
+ ticket->enc_part2->client,
+ princp))
+ goto cleanup;
+
+ /* Flatten name */
+ if (kret = krb5_unparse_name(kcontext, *princp, namep))
+ goto cleanup;
+
+ /* Get database entry */
+ if (kret = krb5_db_get_principal(kcontext,
+ *princp,
+ db_entp,
+ db_numentp,
+ db_morep))
+ goto cleanup;
+
+ if (*db_numentp == 0)
+ kret = KRB5_KDB_NOENTRY;
+
+ cleanup:
+ if (kret) {
+ if (*namep) {
+ krb5_xfree(*namep);
+ *namep = (char *) NULL;
+ }
+ if (*princp) {
+ krb5_free_principal(kcontext, *princp);
+ *princp = (krb5_principal) NULL;
+ }
+ }
+
+ DPRINT(DEBUG_CALLS, debug_level, ("X passwd_check_princ() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * passwd_check_opass_ok() - Check of specified old password is good.
+ */
+static krb5_boolean
+passwd_check_opass_ok(kcontext, debug_level, princ, dbentp, pwdata)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_principal princ;
+ krb5_db_entry *dbentp;
+ krb5_data *pwdata;
+{
+ krb5_boolean pwret;
+ krb5_keyblock pkey, akey;
+ krb5_keyblock pkey1, akey1;
+ krb5_error_code kret;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_check_opass_ok()\n"));
+ pwret = 1;
+
+ /* Initialize */
+ memset((char *) &pkey, 0, sizeof(pkey));
+ memset((char *) &akey, 0, sizeof(akey));
+ memset((char *) &pkey1, 0, sizeof(pkey));
+ memset((char *) &akey1, 0, sizeof(akey));
+
+ /* Make key(s) using alleged old password */
+ kret = key_string_to_keys(kcontext,
+ princ,
+ pwdata,
+ dbentp->salt_type,
+ dbentp->alt_salt_type,
+ &pkey,
+ &akey);
+
+ /* Now decrypt database entries */
+ if (!kret)
+ kret = key_decrypt_keys(kcontext, princ,
+ &dbentp->key, &dbentp->alt_key,
+ &pkey1, &akey1);
+ if (kret)
+ goto cleanup;
+
+ /*
+ * Compare decrypted keys. If they differ, then we're wrong!
+ */
+ if ((pkey1.length && (pkey.length != pkey1.length)) ||
+ (akey1.length && (akey.length != akey1.length)) ||
+ (pkey1.length && memcmp(pkey1.contents,
+ pkey.contents,
+ pkey.length)) ||
+ (akey1.length && memcmp(akey1.contents,
+ akey.contents,
+ akey.length)))
+ pwret = 0;
+
+ cleanup:
+ if (kret)
+ pwret = 0;
+ if (akey1.contents) {
+ memset((char *) akey1.contents, 0, akey1.length);
+ krb5_xfree(akey1.contents);
+ }
+ if (pkey1.contents) {
+ memset((char *) pkey1.contents, 0, pkey1.length);
+ krb5_xfree(pkey1.contents);
+ }
+ if (akey.contents) {
+ memset((char *) akey.contents, 0, akey.length);
+ krb5_xfree(akey.contents);
+ }
+ if (pkey.contents) {
+ memset((char *) pkey.contents, 0, pkey.length);
+ krb5_xfree(pkey.contents);
+ }
+ DPRINT(DEBUG_CALLS, debug_level,
+ ("X passwd_check_opass_ok() = %d\n", pwret));
+ return(pwret);
+}
+\f
+/*
+ * passwd_check_npass_ok() - Check if new password is ok.
+ */
+static krb5_boolean
+passwd_check_npass_ok(kcontext, debug_level, princ, dbentp, pwdata, supp)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_principal princ;
+ krb5_db_entry *dbentp;
+ krb5_data *pwdata;
+ krb5_int32 *supp;
+{
+ krb5_boolean pwret;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_check_npass_ok()\n"));
+ pwret = 1;
+
+ /*
+ * Check whether a new password is good.
+ */
+#if KPWD_CHECK_LENGTH
+ /* Check length */
+ if (pwdata->length < KPWD_MIN_PWD_LENGTH) {
+ pwret = 0;
+ *supp = KRB5_ADM_PWD_TOO_SHORT;
+ DPRINT(DEBUG_CALLS, debug_level,
+ ("* passwd_check_npass_ok() - TOO SHORT\n"));
+ }
+#endif /* KPWD_CHECK_LENGTH */
+
+#if KPWD_CHECK_WEAKNESS
+ /* Check weakness of keys generated by password */
+ if (key_pwd_is_weak(kcontext,
+ princ,
+ pwdata,
+ dbentp->salt_type,
+ dbentp->alt_salt_type)) {
+ pwret = 0;
+ *supp = KRB5_ADM_PWD_WEAK;
+ DPRINT(DEBUG_CALLS, debug_level,
+ ("* passwd_check_npass_ok() - WEAK\n"));
+ }
+#endif /* KPWD_CHECK_WEAKNESS */
+
+ DPRINT(DEBUG_CALLS, debug_level,
+ ("X passwd_check_npass_ok() = %d\n", pwret));
+ return(pwret);
+}
+\f
+/*
+ * passwd_set_npass() - Set new password
+ */
+static krb5_error_code
+passwd_set_npass(kcontext, debug_level, princ, dbentp, pwdata)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_principal princ;
+ krb5_db_entry *dbentp;
+ krb5_data *pwdata;
+{
+ krb5_keyblock pkey, akey;
+ krb5_error_code kret;
+ krb5_db_entry entry2write;
+ int nwrite;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_set_npass()\n"));
+
+ /* Initialize */
+ memset((char *) &pkey, 0, sizeof(pkey));
+ memset((char *) &akey, 0, sizeof(akey));
+ memset((char *) &entry2write, 0, sizeof(krb5_db_entry));
+
+ /* Make key(s) using the new password */
+ if (kret = key_string_to_keys(kcontext,
+ princ,
+ pwdata,
+ dbentp->salt_type,
+ dbentp->alt_salt_type,
+ &pkey,
+ &akey))
+ goto cleanup;
+
+ /* Now get a new database entry */
+ memcpy((char *) &entry2write, (char *) dbentp, sizeof(krb5_db_entry));
+ memset((char *) &entry2write.key, 0, sizeof(krb5_encrypted_keyblock));
+ memset((char *) &entry2write.alt_key, 0, sizeof(krb5_encrypted_keyblock));
+
+ /* Encrypt the new keys to the database entry. */
+ if (kret = key_encrypt_keys(kcontext,
+ princ,
+ &pkey,
+ &akey,
+ &entry2write.key,
+ &entry2write.alt_key))
+ goto cleanup;
+
+ /* Set the time */
+ if (kret = krb5_timeofday(kcontext, &entry2write.mod_date))
+ goto cleanup;
+
+ /* Salt? */
+
+ /* Now write the entry */
+ nwrite = 1;
+ if (kret = krb5_db_put_principal(kcontext, &entry2write, &nwrite))
+ goto cleanup;
+
+ if (nwrite != 1)
+ kret = KRB_ERR_GENERIC;
+
+ cleanup:
+ if (entry2write.key.contents) {
+ memset((char *) &entry2write.key, 0, sizeof(krb5_encrypted_keyblock));
+ krb5_xfree(entry2write.key.contents);
+ }
+ if (entry2write.alt_key.contents) {
+ memset((char *) &entry2write.alt_key, 0,
+ sizeof(krb5_encrypted_keyblock));
+ krb5_xfree(entry2write.alt_key.contents);
+ }
+ if (akey.contents) {
+ memset((char *) akey.contents, 0, akey.length);
+ krb5_xfree(akey.contents);
+ }
+ if (pkey.contents) {
+ memset((char *) pkey.contents, 0, pkey.length);
+ krb5_xfree(pkey.contents);
+ }
+ DPRINT(DEBUG_CALLS, debug_level,
+ ("X passwd_set_npass() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * passwd_check() - Check if a password is ok.
+ */
+krb5_int32
+passwd_check(kcontext, debug_level, auth_context, ticket, pwdata, supp)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_auth_context *auth_context;
+ krb5_ticket *ticket;
+ krb5_data *pwdata;
+ krb5_int32 *supp;
+{
+ krb5_int32 pwret;
+ krb5_error_code kret;
+ krb5_principal client;
+ char *canon_name;
+ krb5_db_entry tmp_entry;
+ int tmp_nents;
+ int tmp_more;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_check()\n"));
+ pwret = KRB5_ADM_SUCCESS;
+ client = (krb5_principal) NULL;
+ canon_name = (char *) NULL;
+
+ /*
+ * Check out our principal
+ */
+ tmp_nents = 1;
+ if (kret = passwd_check_princ(kcontext,
+ debug_level,
+ ticket,
+ &client,
+ &canon_name,
+ &tmp_entry,
+ &tmp_nents,
+ &tmp_more)) {
+ *supp = KRB5_ADM_BAD_PRINC;
+ goto cleanup;
+ }
+
+ DPRINT(DEBUG_REQUESTS, debug_level,
+ ("> Checking password for client \"%s\"\n", canon_name));
+
+ /*
+ * And check out our password.
+ */
+ if (!passwd_check_npass_ok(kcontext,
+ debug_level,
+ client,
+ &tmp_entry,
+ pwdata,
+ supp))
+ pwret = KRB5_ADM_PW_UNACCEPT;
+
+ cleanup:
+ if (kret) {
+ pwret = KRB5_ADM_PW_UNACCEPT;
+ }
+ if (tmp_nents > 0)
+ krb5_db_free_principal(kcontext, &tmp_entry, tmp_nents);
+ if (canon_name)
+ krb5_xfree(canon_name);
+ if (client)
+ krb5_free_principal(kcontext, client);
+
+ done:
+ DPRINT(DEBUG_CALLS, debug_level, ("X passwd_check() = %d\n", pwret));
+ return(pwret);
+}
+\f
+/*
+ * passwd_change() - Change a password.
+ */
+krb5_int32
+passwd_change(kcontext, debug_level, auth_context, ticket,
+ olddata, newdata, supp)
+ krb5_context kcontext;
+ int debug_level;
+ krb5_auth_context *auth_context;
+ krb5_ticket *ticket;
+ krb5_data *olddata;
+ krb5_data *newdata;
+ krb5_int32 *supp;
+{
+ krb5_int32 pwret;
+ krb5_error_code kret;
+ krb5_principal client;
+ char *canon_name;
+ krb5_db_entry tmp_entry;
+ int tmp_nents;
+ int tmp_more;
+
+ DPRINT(DEBUG_CALLS, debug_level, ("* passwd_change()\n"));
+ pwret = KRB5_ADM_SUCCESS;
+ client = (krb5_principal) NULL;
+ canon_name = (char *) NULL;
+
+ /* Make sure the ticket is initial, otherwise don't trust it */
+ if ((ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) {
+ pwret = KRB5_ADM_NOT_IN_TKT;
+ goto done;
+ }
+
+ /*
+ * Check out our principal
+ */
+ tmp_nents = 1;
+ if (kret = passwd_check_princ(kcontext,
+ debug_level,
+ ticket,
+ &client,
+ &canon_name,
+ &tmp_entry,
+ &tmp_nents,
+ &tmp_more)) {
+ *supp = KRB5_ADM_BAD_PRINC;
+ goto cleanup;
+ }
+
+ /*
+ * Check if we're restricted by an ACL from changing our own password.
+ */
+ if (!acl_op_permitted(kcontext, client, ACL_CHANGE_OWN_PW)) {
+ com_err(programname, 0, pwd_perm_denied, canon_name);
+ pwret = KRB5_ADM_CANT_CHANGE;
+ *supp = KRB5_ADM_NOT_ALLOWED;
+ goto cleanup;
+ }
+
+ DPRINT(DEBUG_REQUESTS, debug_level,
+ ("> Changing password for client \"%s\"\n", canon_name));
+
+ /*
+ * Check out our old password.
+ */
+ if (!passwd_check_opass_ok(kcontext,
+ debug_level,
+ client,
+ &tmp_entry,
+ olddata)) {
+ com_err(programname, 0, pwd_bad_old_pwd, canon_name);
+ pwret = KRB5_ADM_BAD_PW;
+ goto cleanup;
+ }
+
+ /*
+ * Check out the new password.
+ */
+ if (!passwd_check_npass_ok(kcontext,
+ debug_level,
+ client,
+ &tmp_entry,
+ newdata,
+ supp)) {
+ pwret = KRB5_ADM_PW_UNACCEPT;
+ goto cleanup;
+ }
+
+ /* Now set the new entry */
+ kret = passwd_set_npass(kcontext,
+ debug_level,
+ client,
+ &tmp_entry,
+ newdata);
+ if (!kret) {
+ com_err(programname, 0, pwd_changed_pwd, canon_name);
+ }
+
+ cleanup:
+ if (kret) {
+ pwret = KRB5_ADM_CANT_CHANGE;
+ }
+ if (tmp_nents > 0)
+ krb5_db_free_principal(kcontext, &tmp_entry, tmp_nents);
+ if (canon_name)
+ krb5_xfree(canon_name);
+ if (client)
+ krb5_free_principal(kcontext, client);
+
+ done:
+ DPRINT(DEBUG_CALLS, debug_level, ("X passwd_change() = %d\n", pwret));
+ return(pwret);
+}
--- /dev/null
+/*
+ * kadmin/v5server/proto_serv.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.
+ *
+ */
+
+/*
+ * proto_serv.c - Engage in protocol. This module reflects the connection
+ * protocol as implemented in lib/krb5/os/adm_conn.c. Any changes
+ * in one module must be reflected in the other.
+ */
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+#include "adm.h"
+
+static const char *proto_addrs_msg = "%d: cannot get memory for addresses";
+static const char *proto_rcache_msg = "%d: cannot get replay cache";
+static const char *proto_ap_req_msg = "%d: error reading AP_REQ message";
+static const char *proto_auth_con_msg = "%d: cannot get authorization context";
+static const char *proto_rd_req_msg = "%d: cannot decode AP_REQ message";
+static const char *proto_mk_rep_msg = "%d: cannot generate AP_REP message";
+static const char *proto_wr_rep_msg = "%d: cannot write AP_REP message";
+static const char *proto_conn_abort_msg = "%d: connection destroyed by client";
+static const char *proto_seq_err_msg = "%d: protocol sequence violation";
+static const char *proto_rd_cmd_msg = "%d: cannot read administrative protocol command";
+static const char *proto_wr_reply_msg = "%d: cannot write administrative protocol reply";
+static const char *proto_fmt_reply_msg = "%d: cannot format administrative protocol reply";
+extern char *programname;
+
+static int proto_proto_timeout = -1;
+static int proto_debug_level = 0;
+static jmp_buf timeout_jmp;
+
+static krb5_sigtype
+proto_alarmclock()
+{
+ longjmp(timeout_jmp, 1);
+ /* NOTREACHED */
+}
+
+krb5_error_code
+proto_init(kcontext, debug_level, timeo)
+ krb5_context kcontext;
+ int debug_level;
+ int timeo;
+{
+ krb5_error_code kret;
+
+ proto_debug_level = debug_level;
+ DPRINT(DEBUG_CALLS, proto_debug_level,
+ ("* proto_init(timeo=%d)\n", timeo));
+ kret = 0;
+ proto_proto_timeout = timeo;
+ DPRINT(DEBUG_CALLS, proto_debug_level, ("X proto_init() = %d\n", kret));
+ return(kret);
+}
+
+void
+proto_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, proto_debug_level, ("* proto_finish()\n"));
+ DPRINT(DEBUG_CALLS, proto_debug_level, ("X proto_finish()\n"));
+}
+
+krb5_error_code
+proto_serv(kcontext, my_id, cl_sock, sv_p, cl_p)
+ krb5_context kcontext;
+ krb5_int32 my_id;
+ int cl_sock;
+ void *sv_p;
+ void *cl_p;
+{
+ krb5_error_code kret;
+ struct sockaddr_in *cl_addr;
+ struct sockaddr_in *sv_addr;
+
+ krb5_data in_data;
+ krb5_data out_data;
+ krb5_rcache rcache;
+ krb5_auth_context *auth_context;
+ krb5_flags ap_options;
+ krb5_ticket *ticket;
+ krb5_address *local;
+ krb5_address *remote;
+
+ char *curr_lang = (char *) NULL;
+ krb5_boolean mime_setting = 0;
+
+ krb5_int32 num_args;
+ krb5_data *arglist;
+
+ cl_addr = (struct sockaddr_in *) cl_p;
+ sv_addr = (struct sockaddr_in *) sv_p;
+ DPRINT(DEBUG_CALLS, proto_debug_level,
+ ("* proto_serv(id=%d, sock=%d, local=%x, remote=%x)\n",
+ my_id, cl_sock,
+ ntohl(sv_addr->sin_addr.s_addr),
+ ntohl(cl_addr->sin_addr.s_addr)));
+
+ /* Initialize */
+ memset((char *) &in_data, 0, sizeof(in_data));
+ memset((char *) &out_data, 0, sizeof(out_data));
+ num_args = 0;
+ local = (krb5_address *) NULL;
+ remote = (krb5_address *) NULL;
+ ticket = (krb5_ticket *) NULL;
+
+ /* Get memory for addresses */
+ local = (krb5_address *) malloc(sizeof(krb5_address));
+ remote = (krb5_address *) malloc(sizeof(krb5_address));
+ if (!local || !remote) {
+ kret = ENOMEM;
+ com_err(programname, kret, proto_addrs_msg, my_id);
+ goto cleanup;
+ }
+
+ local->contents = (krb5_octet *) malloc(sizeof(struct in_addr));
+ remote->contents = (krb5_octet *) malloc(sizeof(struct in_addr));
+ if (!local->contents || !remote->contents) {
+ kret = ENOMEM;
+ com_err(programname, kret, proto_addrs_msg, my_id);
+ goto cleanup;
+ }
+
+ /*
+ * First setup the replay cache.
+ */
+ if (kret = krb5_get_server_rcache(kcontext,
+ krb5_princ_component(kcontext,
+ net_server_princ(),
+ 0),
+ &rcache)) {
+ com_err(programname, kret, proto_rcache_msg, my_id);
+ goto cleanup;
+ }
+
+ /* Initialize the auth context */
+ if (kret = krb5_auth_con_init(kcontext, &auth_context)) {
+ com_err(programname, kret, proto_auth_con_msg, my_id);
+ goto cleanup;
+ }
+
+ krb5_auth_con_setrcache(kcontext, auth_context, rcache);
+
+ /*
+ * Set up addresses.
+ */
+ local->addrtype = remote->addrtype = ADDRTYPE_INET;
+ local->length = remote->length = sizeof(struct in_addr);
+ memcpy((char *) local->contents,
+ (char *) &sv_addr->sin_addr,
+ sizeof(struct in_addr));
+ memcpy((char *) remote->contents,
+ (char *) &cl_addr->sin_addr,
+ sizeof(struct in_addr));
+ krb5_auth_con_setflags(kcontext, auth_context,
+ KRB5_AUTH_CONTEXT_RET_SEQUENCE|
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ krb5_auth_con_setaddrs(kcontext, auth_context, local, remote);
+
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:read message(local=%x, remote=%x)\n",
+ my_id,
+ ntohl(sv_addr->sin_addr.s_addr),
+ ntohl(cl_addr->sin_addr.s_addr)));
+ /* Now, read in the AP_REQ message and decode it. */
+ if (kret = krb5_read_message(kcontext,
+ (krb5_pointer) &cl_sock,
+ &in_data)) {
+ com_err(programname, kret, proto_ap_req_msg, my_id);
+ goto cleanup;
+ }
+
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:parse message(%d bytes)\n", my_id, in_data.length));
+ /* Parse the AP_REQ message */
+ if (kret = krb5_rd_req(kcontext,
+ &auth_context,
+ &in_data,
+ net_server_princ(),
+ (krb5_keytab) NULL,
+ &ap_options,
+ &ticket)) {
+ com_err(programname, kret, proto_rd_req_msg, my_id);
+ goto err_reply;
+ }
+
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:check AP_REQ(options are %x)\n", my_id, ap_options));
+ /* Check our options */
+ if ((ap_options & AP_OPTS_MUTUAL_REQUIRED) == 0) {
+ kret = KRB5KRB_AP_ERR_MSG_TYPE;
+ goto err_reply;
+ }
+
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:make AP_REP\n", my_id));
+ if (kret = krb5_mk_rep(kcontext, auth_context, &out_data)) {
+ com_err(programname, kret, proto_mk_rep_msg, my_id);
+ goto cleanup;
+ }
+
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:write AP_REP(%d bytes)\n", my_id, out_data.length));
+ if (kret = krb5_write_message(kcontext,
+ (krb5_pointer) &cl_sock,
+ &out_data)) {
+ com_err(programname, kret, proto_wr_rep_msg, my_id);
+ goto cleanup;
+ }
+
+ /*
+ * Initialization is now complete.
+ *
+ * If enabled, the protocol times out after proto_proto_timeout seconds.
+ */
+ if (setjmp(timeout_jmp) == 0) {
+ if (proto_proto_timeout > 0) {
+ signal(SIGALRM, proto_alarmclock);
+ }
+ /*
+ * Loop forever - or until somebody puts us out of our misery.
+ */
+ while (1) {
+ krb5_int32 cmd_error;
+ krb5_int32 err_aux;
+ krb5_int32 cmd_repl_ncomps;
+ krb5_data *cmd_repl_complist;
+ int do_quit;
+
+ /*
+ * Read a command and figure out what to do.
+ */
+ if (proto_proto_timeout > 0)
+ alarm(proto_proto_timeout);
+ num_args = 0;
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:waiting for command\n", my_id));
+ kret = krb5_read_adm_cmd(kcontext,
+ (krb5_pointer) &cl_sock,
+ auth_context,
+ &num_args,
+ &arglist);
+ if (proto_proto_timeout > 0)
+ alarm(0);
+ if (kret) {
+ /*
+ * It's OK to have connections abort here.
+ */
+ if (kret == ECONNABORTED) {
+ com_err(programname, kret, proto_conn_abort_msg, my_id);
+ kret = 0;
+ }
+ else if (kret == KRB5KRB_AP_ERR_BADORDER) {
+ com_err(programname, kret, proto_seq_err_msg, my_id);
+ kret = 0;
+ }
+ else
+ com_err(programname, kret, proto_rd_cmd_msg, my_id);
+ goto cleanup;
+ }
+
+ cmd_error = KRB5_ADM_SUCCESS;
+ do_quit = 0;
+
+ /*
+ * Now check our arguments.
+ */
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:parse command\n", my_id));
+ cmd_repl_ncomps = 0;
+ cmd_repl_complist = (krb5_data *) NULL;
+ err_aux = 0;
+ if (num_args > 0) {
+ if (!strcmp(arglist[0].data, KRB5_ADM_QUIT_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:QUIT command\n", my_id));
+ /* QUIT takes no arguments */
+ if (num_args == 1) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:QUIT command syntax OK\n", my_id));
+ do_quit = 1;
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:QUIT command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else if (!strcmp(arglist[0].data, KRB5_ADM_CHECKPW_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHECKPW command\n", my_id));
+ if (num_args == 2) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHECKPW command syntax OK\n", my_id));
+ cmd_error = passwd_check(kcontext,
+ proto_debug_level,
+ auth_context,
+ ticket,
+ &arglist[1],
+ &err_aux);
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHECKPW command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else if (!strcmp(arglist[0].data, KRB5_ADM_CHANGEPW_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHANGEPW command\n", my_id));
+ if (num_args == 3) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHANGEPW command syntax OK\n", my_id));
+ cmd_error = passwd_change(kcontext,
+ proto_debug_level,
+ auth_context,
+ ticket,
+ &arglist[1],
+ &arglist[2],
+ &err_aux);
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:CHANGEPW command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else if (!strcmp(arglist[0].data, KRB5_ADM_MOTD_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MOTD command\n", my_id));
+ if (num_args <= 2) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MOTD command syntax OK\n", my_id));
+ printf("@@@ motd command ");
+ if (num_args == 2)
+ printf("context is %s", arglist[2].data);
+ printf("\n");
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MOTD command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else if (!strcmp(arglist[0].data, KRB5_ADM_MIME_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MIME command\n", my_id));
+ if (num_args == 1) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MIME command syntax OK\n", my_id));
+ mime_setting = 1;
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:MIME command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else if (!strcmp(arglist[0].data, KRB5_ADM_LANGUAGE_CMD)) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:LANGUAGE command\n", my_id));
+ if (num_args == 2) {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:LANGUAGE command syntax OK\n", my_id));
+ if (output_lang_supported(arglist[1].data)) {
+ if (curr_lang)
+ free(curr_lang);
+ curr_lang = (char *)
+ malloc(strlen(arglist[1].data));
+ if (curr_lang)
+ strcpy(curr_lang, arglist[1].data);
+ }
+ else
+ cmd_error = KRB5_ADM_LANG_NOT_SUPPORTED;
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:LANGUAGE command syntax BAD\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_ARGS;
+ }
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:UNKNOWN command %s\n", my_id,
+ arglist[0].data));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_BAD_CMD;
+ }
+ }
+ else {
+ DPRINT(DEBUG_REQUESTS, proto_debug_level,
+ ("> %d:NO command!\n", my_id));
+ cmd_error = KRB5_ADM_CMD_UNKNOWN;
+ err_aux = KRB5_ADM_NO_CMD;
+ }
+
+ /*
+ * Now make the reply.
+ */
+ DPRINT(DEBUG_PROTO, proto_debug_level,
+ ("= %d:sending reply(stat=%d)\n", my_id, cmd_error));
+ if (cmd_error == KRB5_ADM_SUCCESS) {
+ kret = krb5_send_adm_reply(kcontext,
+ (krb5_pointer) &cl_sock,
+ auth_context,
+ cmd_error,
+ cmd_repl_ncomps,
+ cmd_repl_complist);
+ if (kret) {
+ com_err(programname, kret, proto_wr_reply_msg, my_id);
+ goto cleanup;
+ }
+ }
+ else {
+ char *adm_errmsg;
+ krb5_data reply_comps;
+
+ adm_errmsg = output_adm_error(curr_lang,
+ mime_setting,
+ cmd_error,
+ err_aux,
+ num_args,
+ arglist);
+ if (!adm_errmsg) {
+ com_err(programname, kret, proto_fmt_reply_msg, my_id);
+ goto cleanup;
+ }
+ reply_comps.data = adm_errmsg;
+ reply_comps.length = strlen(adm_errmsg);
+ kret = krb5_send_adm_reply(kcontext,
+ (krb5_pointer) &cl_sock,
+ auth_context,
+ cmd_error,
+ 1,
+ &reply_comps);
+ free(adm_errmsg);
+ if (kret) {
+ com_err(programname, kret, proto_wr_reply_msg, my_id);
+ goto cleanup;
+ }
+ }
+ if (cmd_repl_ncomps > 0)
+ krb5_free_adm_data(kcontext,
+ cmd_repl_ncomps,
+ cmd_repl_complist);
+
+ if (do_quit)
+ break;
+ krb5_free_adm_data(kcontext, num_args, arglist);
+ }
+ }
+ else {
+ DLOG(DEBUG_REQUESTS, proto_debug_level, "connection timed out");
+ }
+
+
+ err_reply:
+ if (kret) {
+ krb5_error_code er_kret;
+ krb5_error errbuf;
+ char *errmsg;
+ krb5_data errout;
+
+ memset((char *) &errbuf, 0, sizeof(errbuf));
+ krb5_us_timeofday(kcontext, &errbuf.stime, &errbuf.susec);
+ errbuf.server = net_server_princ();
+ errbuf.error = kret - ERROR_TABLE_BASE_krb5;
+ if (errbuf.error > 127)
+ errbuf.error = KRB_ERR_GENERIC;
+ /* Format the error message in our language */
+ errmsg = output_krb5_errmsg(curr_lang, mime_setting, kret);
+ errbuf.text.length = strlen(errmsg);
+ errbuf.text.data = errmsg;
+ er_kret = krb5_mk_error(kcontext, &errbuf, &errout);
+ if (!er_kret)
+ krb5_write_message(kcontext, (krb5_pointer) &cl_sock, &errout);
+ free(errbuf.text.data);
+ krb5_xfree(errout.data);
+ }
+
+ cleanup:
+ /* If the alarm was set, make sure it's cancelled */
+ if (proto_proto_timeout > 0)
+ alarm(0);
+ if (ticket)
+ krb5_free_ticket(kcontext, ticket);
+ if (rcache)
+ krb5_rc_close(kcontext, rcache);
+ if (auth_context)
+ krb5_xfree(auth_context);
+ if (curr_lang)
+ free(curr_lang);
+ if (num_args)
+ krb5_free_adm_data(kcontext, num_args, arglist);
+ if (in_data.data)
+ krb5_xfree(in_data.data);
+ if (out_data.data)
+ krb5_xfree(out_data.data);
+ if (local && local->contents)
+ free(local->contents);
+ if (remote && remote->contents)
+ free(remote->contents);
+ if (local)
+ free(local);
+ if (remote)
+ free(remote);
+ close(cl_sock);
+
+ done:
+ DPRINT(DEBUG_CALLS, proto_debug_level, ("X proto_serv() = %d\n", kret));
+ return(kret);
+}
--- /dev/null
+/*
+ * kadmin/v5server/srv_acl.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.
+ *
+ */
+
+/*
+ * srv_acl.c - Handle Kerberos ACL related functions.
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+
+typedef struct _acl_op_table {
+ char ao_op;
+ krb5_int32 ao_mask;
+} aop_t;
+
+typedef struct _acl_entry {
+ struct _acl_entry *ae_next;
+ char *ae_name;
+ int ae_name_bad;
+ krb5_principal ae_principal;
+ krb5_int32 ae_op_allowed;
+} aent_t;
+
+static const aop_t acl_op_table[] = {
+ { 'a', ACL_ADD_PRINCIPAL },
+ { 'd', ACL_DELETE_PRINCIPAL },
+ { 'm', ACL_MODIFY_PRINCIPAL },
+ { 'c', ACL_CHANGEPW },
+ { 'o', ACL_CHANGE_OWN_PW },
+ { 'i', ACL_INQUIRE },
+ { 'p', ACL_PRINCIPAL_MASK },
+ { 'w', ACL_PASSWD_MASK },
+ { 'x', ACL_ALL_MASK },
+ { '*', ACL_ALL_MASK },
+ { '\0', 0 }
+};
+
+static aent_t *acl_list_head = (aent_t *) NULL;
+static aent_t *acl_list_tail = (aent_t *) NULL;
+
+static const char *acl_default_file = "/etc/krb5_adm.acl";
+static char *acl_acl_file = (char *) NULL;
+static int acl_inited = 0;
+static int acl_debug_level = 0;
+
+static const char *acl_line2long_msg = "%s: line %d too long, truncated\n";
+static const char *acl_op_bad_msg = "Unrecognized ACL operation '%c' in %s\n";
+static const char *acl_syn_err_msg = "%s: syntax error at line %d <%10s...>\n";
+static const char *acl_cantopen_msg = "cannot open ACL file";
+\f
+/*
+ * acl_get_line() - Get a line from the ACL file.
+ */
+static char *
+acl_get_line(fp, lnp)
+ FILE *fp;
+ int *lnp;
+{
+ int i, domore;
+ static char acl_buf[BUFSIZ];
+
+ for (domore = 1; domore && !feof(fp); ) {
+ /* Copy in the line */
+ for (i=0;
+ ((i<BUFSIZ) &&
+ (!feof(fp)) &&
+ ((acl_buf[i] = fgetc(fp)) != '\n'));
+ i++);
+ acl_buf[i] = '\0';
+
+ /* Check if we exceeded our buffer size */
+ if ((i == BUFSIZ) && (!feof(fp)) && (acl_buf[i] != '\n')) {
+ fprintf(stderr, acl_line2long_msg, acl_acl_file, *lnp);
+ while (fgetc(fp) != '\n');
+ }
+ if (acl_buf[0] == EOF) /* ptooey */
+ acl_buf[0] = '\0';
+ else
+ (*lnp)++;
+ if ((acl_buf[0] != '#') && (acl_buf[0] != '\0'))
+ domore = 0;
+ }
+ if (domore || (strlen(acl_buf) == 0))
+ return((char *) NULL);
+ else
+ return(acl_buf);
+}
+\f
+/*
+ * acl_parse_line() - Parse the contents of an ACL line.
+ */
+static aent_t *
+acl_parse_line(lp)
+ char *lp;
+{
+ static char acle_principal[BUFSIZ];
+ static char acle_ops[BUFSIZ];
+ aent_t *acle;
+ char *op;
+ int t, found, opok;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_parse_line(line=%20s)\n", lp));
+ /*
+ * Format is very simple:
+ * entry ::= <whitespace> <principal> <whitespace> <opstring>
+ */
+ acle = (aent_t *) NULL;
+ if (sscanf(lp, "%s %s", acle_principal, acle_ops) == 2) {
+ acle = (aent_t *) malloc(sizeof(aent_t));
+ if (acle) {
+ acle->ae_next = (aent_t *) NULL;
+ acle->ae_op_allowed = (krb5_int32) 0;
+ opok = 1;
+ for (op=acle_ops; *op; op++) {
+ char rop;
+
+ rop = (isupper(*op)) ? tolower(*op) : *op;
+ found = 0;
+ for (t=0; acl_op_table[t].ao_op; t++) {
+ if (rop == acl_op_table[t].ao_op) {
+ found = 1;
+ if (rop == *op)
+ acle->ae_op_allowed |= acl_op_table[t].ao_mask;
+ else
+ acle->ae_op_allowed &= ~acl_op_table[t].ao_mask;
+ }
+ }
+ if (!found) {
+ fprintf(stderr, acl_op_bad_msg, *op, lp);
+ opok = 0;
+ }
+ }
+ if (opok) {
+ acle->ae_name = (char *) malloc(strlen(acle_principal)+1);
+ if (acle->ae_name) {
+ strcpy(acle->ae_name, acle_principal);
+ acle->ae_principal = (krb5_principal) NULL;
+ acle->ae_name_bad = 0;
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("A ACL entry %s -> opmask %x\n",
+ acle->ae_name, acle->ae_op_allowed));
+ }
+ else {
+ free(acle);
+ acle = (aent_t *) NULL;
+ }
+ }
+ else {
+ free(acle);
+ acle = (aent_t *) NULL;
+ }
+ }
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_parse_line() = %x\n", (long) acle));
+ return(acle);
+}
+\f
+/*
+ * acl_free_entries() - Free all ACL entries.
+ */
+static void
+acl_free_entries()
+{
+ aent_t *ap;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_free_entries()\n"));
+ for (ap=acl_list_head; ap; ap = ap->ae_next) {
+ if (ap->ae_name)
+ free(ap->ae_name);
+ if (ap->ae_principal)
+ krb5_free_principal((krb5_context) NULL, ap->ae_principal);
+ free(ap);
+ }
+ acl_list_head = acl_list_tail = (aent_t *) NULL;
+ acl_inited = 0;
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_free_entries()\n"));
+}
+\f
+/*
+ * acl_load_acl_file() - Open and parse the ACL file.
+ */
+static int
+acl_load_acl_file()
+{
+ FILE *afp;
+ char *alinep;
+ aent_t **aentpp;
+ int alineno;
+ int retval = 1;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_load_acl_file()\n"));
+ /* Open the ACL file for read */
+ if (afp = fopen(acl_acl_file, "r")) {
+ alineno = 1;
+ aentpp = &acl_list_head;
+
+ /* Get a non-comment line */
+ while (alinep = acl_get_line(afp, &alineno)) {
+ /* Parse it */
+ *aentpp = acl_parse_line(alinep);
+ /* If syntax error, then fall out */
+ if (!*aentpp) {
+ fprintf(stderr, acl_syn_err_msg,
+ acl_acl_file, alineno, alinep);
+ retval = 0;
+ break;
+ }
+ acl_list_tail = *aentpp;
+ aentpp = &(*aentpp)->ae_next;
+ }
+ fclose(afp);
+ }
+ else {
+ com_err(acl_acl_file, errno, acl_cantopen_msg);
+ }
+
+ if (!retval) {
+ acl_free_entries();
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_load_acl_file() = %d\n", retval));
+ return(retval);
+}
+\f
+/*
+ * acl_reload_acl_file() - Reload the acl file.
+ */
+static krb5_sigtype
+acl_reload_acl_file()
+{
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_reload_acl_file()\n"));
+ acl_free_entries();
+ acl_inited = acl_load_acl_file();
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_reload_acl_file()\n"));
+}
+\f
+/*
+ * acl_match_data() - See if two data entries match.
+ *
+ * Wildcarding is only supported for a whole component.
+ */
+static krb5_boolean
+acl_match_data(e1, e2)
+ krb5_data *e1, *e2;
+{
+ krb5_boolean retval;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_match_entry(%s, %s)\n", e1->data, e2->data));
+ retval = 0;
+ if (!strncmp(e1->data, "*", e1->length) ||
+ !strncmp(e2->data, "*", e2->length)) {
+ retval = 1;
+ }
+ else {
+ if ((e1->length == e2->length) &&
+ (!strncmp(e1->data, e2->data, e1->length)))
+ retval = 1;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval));
+ return(retval);
+}
+\f
+/*
+ * acl_find_entry() - Find a matching entry.
+ */
+static aent_t *
+acl_find_entry(kcontext, principal)
+ krb5_context kcontext;
+ krb5_principal principal;
+{
+ aent_t *entry;
+ krb5_error_code kret;
+ int i;
+ int matchgood;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_find_entry()\n"));
+ for (entry=acl_list_head; entry; entry = entry->ae_next) {
+ if (!strcmp(entry->ae_name, "*")) {
+ DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
+ break;
+ }
+ if (!entry->ae_principal && !entry->ae_name_bad) {
+ kret = krb5_parse_name(kcontext,
+ entry->ae_name,
+ &entry->ae_principal);
+ if (kret)
+ entry->ae_name_bad = 1;
+ }
+ if (entry->ae_name_bad) {
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("A Bad ACL entry %s\n", entry->ae_name));
+ continue;
+ }
+ matchgood = 0;
+ if (acl_match_data(&entry->ae_principal->realm,
+ &principal->realm) &&
+ (entry->ae_principal->length == principal->length)) {
+ matchgood = 1;
+ for (i=0; i<principal->length; i++) {
+ if (!acl_match_data(&entry->ae_principal->data[i],
+ &principal->data[i])) {
+ matchgood = 0;
+ break;
+ }
+ }
+ }
+ if (matchgood)
+ break;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_find_entry()=%x\n",entry));
+ return(entry);
+}
+\f
+/*
+ * acl_init() - Initialize ACL context.
+ */
+krb5_error_code
+acl_init(kcontext, debug_level, acl_file)
+ krb5_context kcontext;
+ int debug_level;
+ char *acl_file;
+{
+ krb5_error_code kret;
+
+ kret = 0;
+ acl_debug_level = debug_level;
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_init(afile=%s)\n",
+ ((acl_file) ? acl_file : "(null)")));
+ acl_acl_file = (acl_file) ? acl_file : acl_default_file;
+ acl_inited = acl_load_acl_file();
+ signal(SIGHUP, acl_reload_acl_file);
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_init() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * acl_finish - Terminate ACL context.
+ */
+void
+acl_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_finish()\n"));
+ acl_free_entries();
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_finish()\n"));
+}
+\f
+/*
+ * acl_op_permitted() - Is this operation permitted for this principal?
+ */
+krb5_boolean
+acl_op_permitted(kcontext, principal, opmask)
+ krb5_context kcontext;
+ krb5_principal principal;
+ krb5_int32 opmask;
+{
+ krb5_boolean retval;
+ aent_t *aentry;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n"));
+ retval = 1;
+ if (aentry = acl_find_entry(kcontext, principal)) {
+ if ((aentry->ae_op_allowed & opmask) != opmask)
+ retval = 0;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n",
+ retval));
+ return(retval);
+}
--- /dev/null
+/*
+ * kadmin/v5server/srv_key.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.
+ *
+ */
+
+/*
+ * srv_key.c - Handle Kerberos key related functions.
+ */
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+#include "mit-des.h"
+
+static const char *key_bad_etype_fmt = "%s: bad etype %d (%s).\n";
+static const char *key_def_realm_fmt = "%s: cannot find default realm (%s).\n";
+static const char *key_setup_mkey_fmt = "%s: cannot setup master key name (%s).\n";
+static const char *key_get_mkey_fmt = "%s: cannot retrieve master key (%s).\n";
+static const char *key_vfy_mkey_fmt = "%s: cannot verify master key (%s).\n";
+static const char *key_proc_mkey_fmt = "%s: cannot process master key (%s).\n";
+static const char *key_kgen_initf_fmt = "%s: disabling key type %d because initialization failed (%s).\n";
+static const char *key_bad_name_fmt = "%s: cannot set database name to %s (%s).\n";
+static const char *key_cant_init_fmt = "%s: cannot initialize database (%s).\n";
+static const char *key_vmast_key_fmt = "%s: cannot verify master key (%s).\n";
+static const char *key_key_pp_fmt = "%s: cannot preprocess key (%s).\n";
+static const char *key_getm_fmt = "%s: cannot get master entry (%s).\n";
+
+static int mprinc_init = 0;
+static krb5_principal master_principal;
+
+static int mkeyb_init = 0;
+static krb5_keyblock master_keyblock;
+
+static int mencb_init = 0;
+static krb5_encrypt_block master_encblock;
+
+static int mrand_init = 0;
+static krb5_pointer master_random;
+
+static int ment_init = 0;
+static krb5_db_entry master_entry;
+
+static int key_debug_level = 0;
+
+extern char *programname;
+\f
+/*
+ * key_init() - Initialize key context.
+ */
+krb5_error_code
+key_init(kcontext, debug_level, enc_type, key_type, master_key_name, manual,
+ db_file, db_realm)
+ krb5_context kcontext;
+ int debug_level;
+ int enc_type;
+ int key_type;
+ char *master_key_name;
+ int manual;
+ char *db_file;
+ char *db_realm;
+{
+ krb5_enctype kdc_etype;
+ char *mkey_name;
+ char *the_realm;
+
+ krb5_error_code kret;
+ krb5_enctype etype;
+ int one_success;
+ int number_of_entries;
+ krb5_boolean more_entries;
+
+ key_debug_level = debug_level;
+ DPRINT(DEBUG_CALLS, key_debug_level,
+ ("* key_init(enc-type=%d, key-type=%d,\n\tmkeyname=%s, manual=%d,\n\tdb=%s, realm=%s)\n",
+ enc_type, key_type,
+ ((master_key_name) ? master_key_name : "(null)"),
+ manual,
+ ((db_file) ? db_file : "(default)"),
+ ((db_realm) ? db_realm : "(null)")));
+ /*
+ * Figure out arguments.
+ */
+ master_keyblock.keytype = ((key_type == -1) ? KEYTYPE_DES : key_type);
+ mkey_name = ((!master_key_name) ? KRB5_KDB_M_NAME : master_key_name);
+ kdc_etype = ((enc_type == -1) ? DEFAULT_KDC_ETYPE : enc_type);
+ if (!valid_etype(kdc_etype)) {
+ kret = KRB5_PROG_ETYPE_NOSUPP;
+ fprintf(stderr, key_bad_etype_fmt, programname, kdc_etype,
+ error_message(kret));
+ goto leave;
+ }
+ if (!db_realm) {
+ kret = krb5_get_default_realm(kcontext, &the_realm);
+ if (kret) {
+ fprintf(stderr, key_def_realm_fmt, programname,
+ error_message(kret));
+ goto leave;
+ }
+ }
+ else
+ the_realm = db_realm;
+ DPRINT(DEBUG_REALM, key_debug_level,
+ ("- initializing for realm %s\n", the_realm));
+
+ /* Set database name if supplied */
+ if (db_file && (kret = krb5_db_set_name(kcontext, db_file))) {
+ fprintf(stderr, key_bad_name_fmt, programname, db_file,
+ error_message(kret));
+ goto leave;
+ }
+
+ /* Initialize database */
+ if (kret = krb5_db_init(kcontext)) {
+ fprintf(stderr, key_cant_init_fmt, programname,
+ error_message(kret));
+ goto leave;
+ }
+
+ /* Assemble and parse the master key name */
+ kret = krb5_db_setup_mkey_name(kcontext,
+ mkey_name,
+ the_realm,
+ (char **) NULL,
+ &master_principal);
+ if (kret) {
+ fprintf(stderr, key_setup_mkey_fmt, programname,
+ error_message(kret));
+ goto cleanup;
+ }
+ mprinc_init = 1;
+ DPRINT(DEBUG_HOST, key_debug_level,
+ ("- master key is %s@%s\n", mkey_name, the_realm));
+
+ /* Get the master database entry and save it. */
+ number_of_entries = 1;
+ kret = krb5_db_get_principal(kcontext,
+ master_principal,
+ &master_entry,
+ &number_of_entries,
+ &more_entries);
+ if (!kret) {
+ if (number_of_entries != 1) {
+ if (number_of_entries)
+ krb5_db_free_principal(kcontext,
+ &master_entry,
+ number_of_entries);
+ kret = KRB5_KDB_NOMASTERKEY;
+ }
+ else if (more_entries) {
+ krb5_db_free_principal(kcontext,
+ &master_entry,
+ number_of_entries);
+ kret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+ }
+ }
+ if (kret) {
+ fprintf(stderr, key_getm_fmt, programname, error_message(kret));
+ goto leave;
+ }
+ ment_init = 1;
+
+ krb5_use_cstype(kcontext, &master_encblock, kdc_etype);
+ mencb_init = 1;
+
+ /* Go get the master key */
+ kret = krb5_db_fetch_mkey(kcontext,
+ master_principal,
+ &master_encblock,
+ manual,
+ FALSE, /* Only read once if manual */
+ 0, /* No salt */
+ &master_keyblock);
+ if (kret) {
+ fprintf(stderr, key_get_mkey_fmt, programname,
+ error_message(kret));
+ goto cleanup;
+ }
+ mkeyb_init = 1;
+
+ /* Verify the master key */
+ if (kret = krb5_db_verify_master_key(kcontext,
+ master_principal,
+ &master_keyblock,
+ &master_encblock)) {
+ fprintf(stderr, key_vmast_key_fmt, programname,
+ error_message(kret));
+ goto leave;
+ }
+
+ /* Do any key pre-processing */
+ if (kret = krb5_process_key(kcontext,
+ &master_encblock,
+ &master_keyblock)) {
+ fprintf(stderr, key_key_pp_fmt, programname, error_message(kret));
+ goto leave;
+ }
+
+ /* Now initialize the random key */
+ kret = krb5_init_random_key(kcontext,
+ &master_encblock,
+ &master_keyblock,
+ &master_random);
+ if (!kret)
+ mrand_init = 1;
+
+ cleanup:
+ if (kret) {
+ if (mrand_init) {
+ krb5_finish_random_key(kcontext, &master_encblock, &master_random);
+ mrand_init = 0;
+ }
+ if (mencb_init) {
+ krb5_finish_key(kcontext, &master_encblock);
+ mencb_init = 0;
+ }
+ if (mkeyb_init) {
+ memset(master_keyblock.contents, 0, master_keyblock.length);
+ krb5_xfree(master_keyblock.contents);
+ mkeyb_init = 0;
+ }
+ if (ment_init) {
+ krb5_db_free_principal(kcontext, &master_entry, 1);
+ ment_init = 0;
+ }
+ }
+ if (the_realm != db_realm)
+ krb5_xfree(the_realm);
+ leave:
+ DPRINT(DEBUG_CALLS, key_debug_level, ("X key_init() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * key_finish - Terminate key context.
+ */
+void
+key_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, key_debug_level, ("* key_finish()\n"));
+ if (mrand_init) {
+ krb5_finish_random_key(kcontext, &master_encblock, &master_random);
+ mrand_init = 0;
+ }
+ if (mkeyb_init) {
+ krb5_finish_key(kcontext, &master_encblock);
+ memset((char *) &master_encblock, 0,
+ sizeof(master_encblock));
+ mkeyb_init = 0;
+ }
+ if (mprinc_init) {
+ krb5_free_principal(kcontext, master_principal);
+ mprinc_init = 0;
+ }
+ if (mencb_init) {
+ master_encblock.crypto_entry = 0;
+ mencb_init = 0;
+ }
+ if (ment_init) {
+ krb5_db_free_principal(kcontext, &master_entry, 1);
+ ment_init = 0;
+ }
+ krb5_db_fini(kcontext);
+ /* memset((char *) tgs_key.contents, 0, tgs_key.length); */
+ DPRINT(DEBUG_CALLS, key_debug_level, ("X key_finish()\n"));
+}
+\f
+/*
+ * key_string_to_keys() - convert string to keys.
+ */
+krb5_error_code
+key_string_to_keys(kcontext, principal, string, psalttype, asalttype,
+ primary, alternate)
+ krb5_context kcontext;
+ krb5_principal principal;
+ krb5_data *string;
+ krb5_int32 psalttype;
+ krb5_int32 asalttype;
+ krb5_keyblock *primary;
+ krb5_keyblock *alternate;
+{
+ krb5_error_code kret;
+ krb5_data psalt_data, asalt_data;
+
+ DPRINT(DEBUG_CALLS, key_debug_level, ("* key_string_to_keys()\n"));
+ kret = KRB_ERR_GENERIC;
+ psalt_data.length = asalt_data.length = 0;
+ psalt_data.data = asalt_data.data = (char *) NULL;
+
+ /*
+ * Determine the primary salt type.
+ */
+ switch (psalttype) {
+ case KRB5_KDB_SALTTYPE_NORMAL:
+ /* Normal salt */
+ if (kret = krb5_principal2salt(kcontext, principal, &psalt_data))
+ goto done;
+ asalt_data.data = (char *) NULL;
+ asalt_data.length = 0;
+ break;
+ case KRB5_KDB_SALTTYPE_V4:
+ /* V4 salt */
+ psalt_data.data = (char *) NULL;
+ psalt_data.length = 0;
+ if (kret = krb5_principal2salt(kcontext, principal, &asalt_data))
+ goto done;
+ break;
+ case KRB5_KDB_SALTTYPE_NOREALM:
+ if (kret = krb5_principal2salt_norealm(kcontext,
+ principal,
+ &psalt_data))
+ goto done;
+ asalt_data.data = (char *) NULL;
+ asalt_data.length = 0;
+ break;
+ case KRB5_KDB_SALTTYPE_ONLYREALM:
+ {
+ krb5_data *tmp;
+
+ if (kret = krb5_copy_data(kcontext,
+ krb5_princ_realm(kcontext, principal),
+ &tmp))
+ goto done;
+ psalt_data = *tmp;
+ krb5_xfree(tmp);
+ asalt_data.data = (char *) NULL;
+ asalt_data.length = 0;
+ break;
+ }
+ default:
+ goto done;
+ }
+
+ /* Now convert the string to keys */
+ kret = krb5_string_to_key(kcontext,
+ &master_encblock,
+ master_keyblock.keytype,
+ primary,
+ string,
+ &psalt_data);
+ if (!kret)
+ kret = krb5_string_to_key(kcontext,
+ &master_encblock,
+ master_keyblock.keytype,
+ alternate,
+ string,
+ &asalt_data);
+
+ done:
+ if (kret) {
+ if (primary->contents) {
+ memset((char *) primary->contents, 0, primary->length);
+ krb5_xfree(primary->contents);
+ }
+ if (alternate->contents) {
+ memset((char *) alternate->contents, 0, alternate->length);
+ krb5_xfree(alternate->contents);
+ }
+ }
+ if (psalt_data.data) {
+ memset(psalt_data.data, 0, psalt_data.length);
+ krb5_xfree(psalt_data.data);
+ }
+ if (asalt_data.data) {
+ memset(asalt_data.data, 0, asalt_data.length);
+ krb5_xfree(asalt_data.data);
+ }
+ DPRINT(DEBUG_CALLS, key_debug_level,
+ ("X key_string_to_keys() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * key_encrypt_keys() - encrypt keys.
+ */
+krb5_error_code
+key_encrypt_keys(kcontext, principal, primary, alternate, eprimary, ealternate)
+ krb5_context kcontext;
+ krb5_principal principal;
+ krb5_keyblock *primary;
+ krb5_keyblock *alternate;
+ krb5_encrypted_keyblock *eprimary;
+ krb5_encrypted_keyblock *ealternate;
+{
+ krb5_error_code kret;
+
+ DPRINT(DEBUG_CALLS, key_debug_level, ("* key_encrypt_keys()\n"));
+
+ kret = krb5_kdb_encrypt_key(kcontext,
+ &master_encblock,
+ primary,
+ eprimary);
+ if (kret)
+ kret = krb5_kdb_encrypt_key(kcontext,
+ &master_encblock,
+ alternate,
+ ealternate);
+ done:
+ if (kret) {
+ if (eprimary->contents) {
+ memset((char *) eprimary->contents, 0, eprimary->length);
+ krb5_xfree(eprimary->contents);
+ }
+ if (ealternate->contents) {
+ memset((char *) ealternate->contents, 0, ealternate->length);
+ krb5_xfree(ealternate->contents);
+ }
+ }
+ DPRINT(DEBUG_CALLS, key_debug_level,
+ ("X key_encrypt_keys() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * key_decrypt_keys() - decrypt keys.
+ */
+krb5_error_code
+key_decrypt_keys(kcontext, principal, eprimary, ealternate, primary, alternate)
+ krb5_context kcontext;
+ krb5_principal principal;
+ krb5_encrypted_keyblock *eprimary;
+ krb5_encrypted_keyblock *ealternate;
+ krb5_keyblock *primary;
+ krb5_keyblock *alternate;
+{
+ krb5_error_code kret;
+
+ DPRINT(DEBUG_CALLS, key_debug_level, ("* key_decrypt_keys()\n"));
+
+ kret = krb5_kdb_decrypt_key(kcontext,
+ &master_encblock,
+ eprimary,
+ primary);
+ if (kret)
+ kret = krb5_kdb_decrypt_key(kcontext,
+ &master_encblock,
+ ealternate,
+ alternate);
+ done:
+ if (kret) {
+ if (primary->contents) {
+ memset((char *) primary->contents, 0, primary->length);
+ krb5_xfree(primary->contents);
+ }
+ if (alternate->contents) {
+ memset((char *) alternate->contents, 0, alternate->length);
+ krb5_xfree(alternate->contents);
+ }
+ }
+ DPRINT(DEBUG_CALLS, key_debug_level,
+ ("X key_decrypt_keys() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * key_pwd_is_weak() - Check for weakness of key from password
+ */
+krb5_boolean
+key_pwd_is_weak(kcontext, principal, string, psalttype, asalttype)
+ krb5_context kcontext;
+ krb5_principal principal;
+ krb5_data *string;
+ krb5_int32 psalttype;
+ krb5_int32 asalttype;
+{
+ krb5_boolean weakness;
+ krb5_error_code kret;
+ krb5_keyblock primary;
+ krb5_keyblock alternate;
+
+ DPRINT(DEBUG_CALLS, key_debug_level, ("* key_pwd_is_weak()\n"));
+ weakness = 0;
+
+ if (master_encblock.key->etype != ETYPE_NULL) {
+ memset((char *) &primary, 0, sizeof(primary));
+ memset((char *) &alternate, 0, sizeof(alternate));
+
+ kret = key_string_to_keys(kcontext,
+ principal,
+ string,
+ psalttype,
+ asalttype,
+ &primary,
+ &alternate);
+ if (!kret) {
+ if (primary.length &&
+ (primary.length == sizeof(mit_des_cblock)) &&
+ mit_des_is_weak_key(primary.contents))
+ weakness = 1;
+ if (alternate.length &&
+ (alternate.length == sizeof(mit_des_cblock)) &&
+ mit_des_is_weak_key(alternate.contents))
+ weakness = 1;
+ if (primary.contents) {
+ memset((char *) primary.contents, 0, primary.length);
+ krb5_xfree(primary.contents);
+ }
+ if (alternate.contents) {
+ memset((char *) alternate.contents, 0, alternate.length);
+ krb5_xfree(alternate.contents);
+ }
+ }
+ }
+ DPRINT(DEBUG_CALLS, key_debug_level,
+ ("X key_pwd_is_weak() = %d\n", weakness));
+ return(weakness);
+}
+
--- /dev/null
+/*
+ * kadmin/v5server/srv_main.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.
+ *
+ */
+
+/*
+ * srv_main.c
+ * Main function of administrative server which speaks new Kerberos V5
+ * administrative protocol.
+ */
+\f
+#include <stdio.h>
+#include <sys/signal.h>
+#include <syslog.h>
+#include <setjmp.h>
+#include "k5-int.h"
+#include "com_err.h"
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#else /* HAVE_STDARG_H */
+#include <varargs.h>
+#endif /* HAVE_STDARG_H */
+
+#define KADM_MAX_ERRMSG_SIZE 1024
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif /* LOG_AUTH */
+
+static const char *usage_format = "%s: usage is %s [-a aclfile] [-d database] [-e enctype] [-i]\n\t[-k mkeytype] [-l langlist] [-m bool] [-r realm] [-t timeout]\n\t[-D dbg] [-M mkeyname].\n";
+static const char *fval_not_number = "%s: value (%s) specified for -%c is not numeric.\n";
+static const char *extra_params = "%s extra paramters beginning with %s... \n";
+static const char *no_memory_fmt = "%s: cannot allocate %d bytes for %s.\n";
+static const char *begin_op_msg = "%s starting.";
+static const char *disp_err_fmt = "dispatch error.";
+static const char *happy_exit_fmt = "terminating normally.";
+static const char *init_error_fmt = "%s: cannot initialize %s.\n";
+static const char *unh_signal_fmt = "exiting on signal %d.";
+
+static const char *messages_msg = "messages";
+static const char *proto_msg = "protocol module";
+static const char *net_msg = "network";
+static const char *output_msg = "output";
+static const char *acl_msg = "ACLs";
+static const char *key_msg = "key and database";
+static const char *server_name_msg = "Kerberos V5 administrative server";
+
+char *programname = (char *) NULL;
+static jmp_buf terminal_jmp;
+\f
+static void
+usage(prog)
+ char *prog;
+{
+ fprintf(stderr, usage_format, prog, prog);
+}
+
+/*
+ * An unhandled signal just proceeds from the setjmp() in main.
+ */
+static krb5_sigtype
+unhandled_signal(signo)
+ int signo;
+{
+ longjmp(terminal_jmp, signo);
+ /* NOTREACHED */
+}
+
+static void
+kadm_com_err_proc(whoami, code, format, ap)
+ const char *whoami;
+ long code;
+ const char *format;
+ va_list ap;
+{
+ char *outbuf;
+
+ outbuf = (char *) malloc(KADM_MAX_ERRMSG_SIZE);
+ if (outbuf) {
+ char *cp;
+ sprintf(outbuf, "%s: ", whoami);
+ if (code) {
+ strcat(outbuf, error_message(code));
+ strcat(outbuf, " - ");
+ }
+ cp = &outbuf[strlen(outbuf)];
+ vsprintf(cp, format, ap);
+#ifndef DEBUG
+ syslog(LOG_AUTH|LOG_ERR, outbuf);
+#endif /* DEBUG */
+ strcat(outbuf, "\n");
+ fprintf(stderr, outbuf);
+ free(outbuf);
+ }
+ else {
+ fprintf(stderr, no_memory_fmt, programname,
+ KADM_MAX_ERRMSG_SIZE, messages_msg);
+ }
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int option;
+ krb5_error_code error;
+
+ int enc_type = -1;
+ int key_type = -1;
+ int manual_entry = 0;
+ krb5_boolean mime_enabled = 0;
+ int debug_level = 0;
+ int timeout = -1;
+ char *acl_file = (char *) NULL;
+ char *db_file = (char *) NULL;
+ char *language_list = (char *) NULL;
+ char *db_realm = (char *) NULL;
+ char *master_key_name = (char *) NULL;
+
+ /* Kerberatic contexts */
+ krb5_context kcontext;
+
+ const char *errmsg;
+ int signal_number;
+
+ /*
+ * usage is:
+ * kadmind5 [-a aclfile]
+ * [-d database]
+ * [-e enctype]
+ * [-i]
+ * [-k masterkeytype]
+ * [-l languagelist]
+ * [-m yesno]
+ * [-r realmname]
+ * [-t timeout]
+ * [-D debuglevel]
+ * [-M masterkeyname]
+ */
+ error = 0;
+ while ((option = getopt(argc, argv, "a:d:e:ik:l:m:r:t:D:M:")) != EOF) {
+ switch (option) {
+ case 'a':
+ acl_file = optarg;
+ break;
+ case 'd':
+ db_file = optarg;
+ break;
+ case 'e':
+ if (sscanf(optarg, "%d", &enc_type) != 1) {
+ fprintf(stderr, fval_not_number, argv[0], optarg, 'e');
+ error++;
+ }
+ break;
+ case 'i':
+ manual_entry++;
+ break;
+ case 'k':
+ if (sscanf(optarg, "%d", &key_type) != 1) {
+ fprintf(stderr, fval_not_number, argv[0], optarg, 'k');
+ error++;
+ }
+ break;
+ case 'l':
+ language_list = optarg;
+ break;
+ case 'm':
+ if (sscanf(optarg, "%d", &mime_enabled) != 1) {
+ fprintf(stderr, fval_not_number, argv[0], optarg, 'm');
+ error++;
+ }
+ break;
+ case 'r':
+ db_realm = optarg;
+ break;
+ case 't':
+ if (sscanf(optarg, "%d", &timeout) != 1) {
+ fprintf(stderr, fval_not_number, argv[0], optarg, 't');
+ error++;
+ }
+ break;
+ case 'D':
+ if (sscanf(optarg, "%d", &debug_level) != 1) {
+ fprintf(stderr, fval_not_number, argv[0], optarg, 'D');
+ error++;
+ }
+ break;
+ case 'M':
+ master_key_name = optarg;
+ break;
+ default:
+ error++;
+ break;
+ }
+ }
+ if (optind - argc > 0) {
+ fprintf(stderr, extra_params, argv[0], argv[optind+1]);
+ error++;
+ }
+ if (error) {
+ usage(argv[0]);
+ return(1);
+ }
+
+ /*
+ * We've come this far. Our arguments are good.
+ */
+#ifndef DEBUG
+ programname = (char *) strrchr(argv[0], '/');
+ if (programname)
+ programname++;
+ else
+ programname = argv[0];
+#else /* DEBUG */
+ programname = argv[0];
+#endif /* DEBUG */
+ krb5_init_context(&kcontext);
+ krb5_init_ets(kcontext);
+ openlog(programname, LOG_AUTH|LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6);
+ (void) set_com_err_hook(kadm_com_err_proc);
+
+ if ((signal_number = setjmp(terminal_jmp)) == 0) {
+ /*
+ * Initialize signal handling.
+ */
+ signal(SIGINT, unhandled_signal);
+ signal(SIGTERM, unhandled_signal);
+ signal(SIGHUP, unhandled_signal);
+ signal(SIGQUIT, unhandled_signal);
+ signal(SIGPIPE, unhandled_signal);
+ signal(SIGALRM, unhandled_signal);
+ signal(SIGCHLD, unhandled_signal);
+
+ /*
+ * Initialize our modules.
+ */
+ error = key_init(kcontext, debug_level, enc_type, key_type,
+ master_key_name, manual_entry, db_file, db_realm);
+ if (!error) {
+ error = acl_init(kcontext, debug_level, acl_file);
+ if (!error) {
+ error = output_init(kcontext, debug_level,
+ language_list, mime_enabled);
+ if (!error) {
+ error = net_init(kcontext,
+ debug_level);
+ if (!error) {
+ error = proto_init(kcontext, debug_level, timeout);
+
+ if (error)
+ errmsg = proto_msg;
+ }
+ else
+ errmsg = net_msg;
+ }
+ else
+ errmsg = output_msg;
+ }
+ else
+ errmsg = acl_msg;
+ }
+ else
+ errmsg = key_msg;
+
+ if (!error) {
+ /*
+ * We've successfully initialized here.
+ */
+#ifndef DEBUG
+ syslog(LOG_AUTH|LOG_INFO, begin_op_msg, server_name_msg);
+#endif /* DEBUG */
+
+ /*
+ * net_dispatch() only returns when we're done for some reason.
+ */
+ error = net_dispatch(kcontext);
+
+ com_err(programname, error,
+ ((error) ? disp_err_fmt : happy_exit_fmt));
+ }
+ else {
+ /* Initialization error */
+ fprintf(stderr, init_error_fmt, programname, errmsg);
+ }
+ }
+ else {
+ /* Received an unhandled signal */
+ com_err(programname, 0, unh_signal_fmt, signal_number);
+ }
+
+ /* Now clean up after ourselves */
+ proto_finish(kcontext, debug_level);
+ net_finish(kcontext, debug_level);
+ output_finish(kcontext, debug_level);
+ acl_finish(kcontext, debug_level);
+ key_finish(kcontext, debug_level);
+ krb5_xfree(kcontext);
+ return(error);
+}
--- /dev/null
+/*
+ * kadmin/v5server/srv_net.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.
+ *
+ */
+
+/*
+ * srv_net.c - handle networking functions of the administrative server.
+ */
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#ifdef USE_PTHREADS
+#include <pthread.h>
+#endif /* USE_PTHREADS */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+#include "adm.h"
+
+#define MAX_BIND_TRIES 5
+
+/*
+ * This module can use the pthreads library. To do so, define USE_PTHREADS.
+ * You'll need to find out what else pthreads requires (e.g. -lmach -lc_r
+ * under OSF/1).
+ */
+#ifdef USE_PTHREADS
+#define net_slave_type pthread_t *
+#ifndef MAX_SLAVES
+#define MAX_SLAVES SOMAXCONN
+#endif /* MAX_SLAVES */
+#else /* USE_PTHREADS */
+#define net_slave_type pid_t
+#ifndef MAX_SLAVES
+#define MAX_SLAVES SOMAXCONN
+#endif /* MAX_SLAVES */
+#endif /* USE_PTHREADS */
+#define NET_SLAVE_FULL_SLEEP 15 /* seconds */
+
+/*
+ * Slave information storage.
+ */
+typedef struct _net_slave_info {
+ int sl_inuse;
+ net_slave_type sl_id;
+ krb5_context sl_context;
+ int sl_socket;
+ struct sockaddr_in sl_local_addr; /* local address */
+ struct sockaddr_in sl_remote_addr; /* remote address */
+} net_slave_info;
+
+/*
+ * Error messages.
+ */
+static const char *net_waiterr_msg = "child wait failed - cannot reap children";
+static const char *net_def_realm_fmt = "%s: cannot get default realm (%s).\n";
+static const char *net_no_mem_fmt = "%s: cannot get memory.\n";
+static const char *net_parse_srv_fmt = "%s: cannot parse server name %s (%s).\n";
+static const char *net_no_hostname_fmt = "%s: cannot get our host name (%s).\n";
+static const char *net_no_hostent_fmt = "%s: cannot get our host entry (%s).\n";
+static const char *net_no_servent_fmt = "%s: cannot get service entry for %s (%s).\n";
+static const char *net_sockerr_fmt = "%s: cannot open network socket (%s).\n";
+static const char *net_binderr_fmt = "%s: cannot bind to network address (%s).\n";
+
+static const char *net_select_fmt = "select failed";
+static const char *net_cl_disp_fmt = "client dispatch failed";
+static const char *net_not_ready_fmt = "select error - no socket to read";
+static const char *net_dispatch_msg = "network dispatch";
+
+static int net_debug_level = 0;
+
+static char *net_service_name = (char *) NULL;
+static int net_service_princ_init = 0;
+static krb5_principal net_service_principal = (krb5_principal) NULL;
+static int net_server_addr_init = 0;
+static struct sockaddr_in net_server_addr;
+static int net_listen_socket = -1;
+static int net_slaves_active = 0;
+static int net_max_slaves = 0;
+static net_slave_info *net_slave_table = (net_slave_info *) NULL;
+
+static jmp_buf shutdown_jmp;
+
+extern char *programname;
+\f
+/*
+ * net_find_free_entry() - Find a free entry in the slave table.
+ */
+static net_slave_info *
+net_find_free_entry()
+{
+ int i, found;
+
+ /* Find a table entry */
+ while (1) {
+ found = 0;
+ for (i=0; i<net_max_slaves; i++) {
+ if (!net_slave_table[i].sl_inuse) {
+ net_slave_table[i].sl_inuse = 1;
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ sleep(NET_SLAVE_FULL_SLEEP);
+ }
+ return(&net_slave_table[i]);
+}
+\f
+/*
+ * net_find_slave() - Find a slave entry by its identity.
+ */
+static net_slave_info *
+net_find_slave(id)
+ net_slave_type id;
+{
+ int i, found;
+
+ for (i=0; i<net_max_slaves; i++) {
+ if (net_slave_table[i].sl_inuse &&
+ (net_slave_table[i].sl_id == id)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ return(&net_slave_table[i]);
+ else
+ return((net_slave_info *) NULL);
+}
+
+/*
+ * net_free_slave_entry() - Mark an entry as free.
+ */
+static void
+net_free_slave_entry(entp)
+ net_slave_info *entp;
+{
+ entp->sl_inuse = 0;
+}
+\f
+/*
+ * net_shutdown() - Destroy all slaves on signal reception
+ */
+static krb5_sigtype
+net_shutdown()
+{
+ int i;
+
+ /* Loop through all slaves */
+ for (i=0; i<net_max_slaves; i++) {
+ if (net_slave_table[i].sl_inuse){
+#ifdef DEBUG
+ /* If not us (see net_dispatch_client) */
+ if (net_slave_table[i].sl_id != (net_slave_type) getpid()) {
+#endif /* DEBUG */
+#if USE_PTHREADS
+ pthread_cancel(*net_slave_table[i].sl_id);
+#else /* USE_PTHREADS */
+ kill(net_slave_table[i].sl_id, SIGKILL);
+#endif /* USE_PTHREADS */
+#ifdef DEBUG
+ }
+#endif /* DEBUG */
+ }
+ }
+ sleep(5); /* to allow children to die and be reaped */
+ longjmp(shutdown_jmp, 1);
+ /* NOTREACHED */
+}
+\f
+#if !USE_PTHREADS
+/*
+ * net_reaper() - Child process termination handler.
+ */
+static krb5_sigtype
+net_reaper()
+{
+#ifdef WAIT_USES_INT
+ int child_exit;
+#else /* WAIT_USES_INT */
+ union wait child_exit;
+#endif /* WAIT_USES_INT */
+ pid_t deadmeat;
+ net_slave_info *slent;
+
+ /* Reap everybody we can */
+ while (
+ (
+#ifdef HAVE_WAITPID
+ deadmeat = waitpid((pid_t) -1, &child_exit, WNOHANG)
+#else /* HAVE_WAITPID */
+ deadmeat = wait3(&child_exit, WNOHANG, (struct rusage *) NULL)
+#endif /* HAVE_WAITPID */
+ ) > 0) {
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| process %d finished with %d\n", deadmeat, child_exit));
+ slent = net_find_slave(deadmeat);
+ if (slent) {
+ net_free_slave_entry(slent);
+ }
+ else {
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| cannot find slave entry for %d\n", deadmeat));
+ }
+ }
+ if ((deadmeat == -1) && (errno != ECHILD))
+ com_err(programname, errno, net_waiterr_msg);
+}
+#endif /* USE_PTHREADS */
+\f
+#if USE_PTHREADS
+/*
+ * net_slave_proto() - pthread main routine.
+ */
+static krb5_error_code
+net_slave_proto(stent)
+ net_slave_info *stent;
+{
+ krb5_error_code kret;
+
+ DPRINT(DEBUG_CALLS, net_debug_level,
+ ("* net_slave_proto()\n"));
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| thread %d starting\n", stent->sl_id));
+ kret = proto_serv(stent->sl_context,
+ (krb5_int32) stent->sl_id,
+ stent->sl_socket,
+ &stent->sl_local_addr,
+ &stent->sl_remote_addr);
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| thread %d finished with %d\n", stent->sl_id, kret));
+ DPRINT(DEBUG_CALLS, net_debug_level,
+ ("* net_slave_proto() = %d\n", kret));
+ net_free_slave_entry(stent);
+ return(kret);
+}
+#endif /* USE_PTHREADS */
+\f
+/*
+ * net_dispatch_client() - Handle client dispatch.
+ */
+static krb5_error_code
+net_dispatch_client(kcontext, listen_sock, conn_sock, client_addr)
+ krb5_context kcontext;
+ int listen_sock;
+ int conn_sock;
+ struct sockaddr_in *client_addr;
+{
+ krb5_error_code kret;
+ net_slave_info *slent;
+
+ DPRINT(DEBUG_CALLS, net_debug_level,
+ ("* net_dispatch_client(listen=%d)\n", listen_sock));
+ kret = 0;
+
+ /* Find a free entry */
+ slent = net_find_free_entry();
+
+ /* Initialize the slave entry */
+ slent->sl_context = kcontext;
+ slent->sl_socket = conn_sock;
+ memcpy((char *) &slent->sl_remote_addr,
+ (char *) client_addr,
+ sizeof(struct sockaddr_in));
+ memcpy((char *) &slent->sl_local_addr,
+ (char *) &net_server_addr,
+ sizeof(struct sockaddr_in));
+
+#ifdef DEBUG
+ if (net_debug_level < DEBUG_REQUESTS) {
+#endif /* DEBUG */
+ /* Do a real slave creation */
+#if USE_PTHREADS
+ if (!slent->sl_id)
+ slent->sl_id = (pthread_t *) malloc(sizeof(pthread_t));
+ if (slent->sl_id == (pthread_t *) NULL) {
+ kret = ENOMEM;
+ goto done;
+ }
+ if (kret = pthread_create(slent->sl_id,
+ pthread_attr_default,
+ (pthread_startroutine_t) net_slave_proto,
+ (pthread_addr_t) slent)) {
+ kret = errno;
+ goto done;
+ }
+ if (pthread_detach(slent->sl_id)) {
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| (%d) child thread %d detach failed (%d)\n",
+ getpid(), slent->sl_id, errno));
+ }
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| (%d) created child thread %d\n",
+ getpid(), slent->sl_id));
+#else /* USE_PTHREADS */
+ slent->sl_id = fork();
+ if (slent->sl_id < 0) {
+ kret = errno;
+ slent->sl_inuse = 0;
+ goto done;
+ }
+
+ if (slent->sl_id > 0) {
+ /* parent */
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| (%d) created child process %d\n",
+ getpid(), slent->sl_id));
+ kret = 0;
+ goto done;
+ }
+ else {
+ /* child */
+ signal(SIGINT, SIG_IGN); /* Ignore SIGINT */
+ signal(SIGTERM, SIG_IGN); /* Ignore SIGTERM */
+ signal(SIGHUP, SIG_IGN); /* Ignore SIGHUP */
+ signal(SIGQUIT, SIG_IGN); /* Ignore SIGQUIT */
+ signal(SIGPIPE, SIG_IGN); /* Ignore SIGPIPE */
+ signal(SIGCHLD, SIG_DFL); /* restore SIGCHLD handling */
+ close(listen_sock);
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| process %d starting\n", getpid()));
+ kret = proto_serv(slent->sl_context,
+ (krb5_int32) slent->sl_id,
+ slent->sl_socket,
+ &slent->sl_local_addr,
+ &slent->sl_remote_addr);
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| process %d exiting with %d\n", getpid(), kret));
+ exit(kret);
+ }
+#endif /* USE_PTHREADS */
+#ifdef DEBUG
+ }
+ else {
+ net_slave_info *sl1;
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| (%d) not doing child creation\n", getpid()));
+ slent->sl_id = (net_slave_type) getpid();
+ kret = proto_serv(slent->sl_context,
+ (krb5_int32) slent->sl_id,
+ slent->sl_socket,
+ &slent->sl_local_addr,
+ &slent->sl_remote_addr);
+ sl1 = net_find_slave(slent->sl_id);
+ if (!sl1)
+ net_free_slave_entry(sl1);
+ DPRINT(DEBUG_SPROC, net_debug_level,
+ ("| (%d) returned with %d\n", getpid(), kret));
+ }
+#endif /* DEBUG */
+ done:
+ DPRINT(DEBUG_CALLS, net_debug_level,
+ ("X net_dispatch_client() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * net_init() - Initialize network context.
+ */
+krb5_error_code
+net_init(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ krb5_error_code kret;
+ char *local_realm;
+ char our_host_name[MAXHOSTNAMELEN];
+ struct hostent *our_hostent;
+ struct servent *our_servent;
+ int bind_tries;
+ int bind_sleep;
+
+ net_debug_level = debug_level;
+ DPRINT(DEBUG_CALLS, net_debug_level, ("* net_init()\n"));
+
+ /*
+ * Get our realm.
+ */
+ if (kret = krb5_get_default_realm(kcontext, &local_realm)) {
+ fprintf(stderr, net_def_realm_fmt, programname, error_message(kret));
+ goto done;
+ }
+
+ /* Allocate the slave table */
+ net_slave_table = (net_slave_info *) malloc(MAX_SLAVES *
+ sizeof(net_slave_info));
+ /* Make our service name */
+ net_service_name = (char *) malloc(strlen(local_realm) +
+ strlen(KRB5_ADM_SERVICE_NAME) + 2);
+ if ((net_service_name == (char *) NULL) ||
+ (net_slave_table == (net_slave_info *) NULL)) {
+ kret = ENOMEM;
+ krb5_xfree(local_realm);
+ fprintf(stderr, net_no_mem_fmt, programname);
+ goto done;
+ }
+ (void) sprintf(net_service_name, "%s%s%s",
+ KRB5_ADM_SERVICE_NAME, "/", local_realm);
+ krb5_xfree(local_realm);
+ memset((char *) net_slave_table, 0, MAX_SLAVES * sizeof(net_slave_info));
+ net_max_slaves = MAX_SLAVES;
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- name of service is %s\n", net_service_name));
+
+ /* Now formulate the principal name */
+ if (kret = krb5_parse_name(kcontext,
+ net_service_name,
+ &net_service_principal)) {
+ fprintf(stderr, net_parse_srv_fmt, programname, net_service_name,
+ error_message(kret));
+ goto done;
+ }
+ net_service_princ_init = 1;
+
+ /* Now get our host name/entry */
+ if (gethostname(our_host_name, sizeof(our_host_name))) {
+ kret = errno;
+ fprintf(stderr, net_no_hostname_fmt, programname, error_message(kret));
+ goto done;
+ }
+ if (!(our_hostent = gethostbyname(our_host_name))) {
+ kret = errno;
+ fprintf(stderr, net_no_hostent_fmt, programname, error_message(kret));
+ goto done;
+ }
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- name of host is %s\n", our_hostent->h_name));
+
+ /* Now initialize our network address */
+ net_server_addr.sin_family = AF_INET;
+ memcpy((char *) &net_server_addr.sin_addr,
+ (char *) our_hostent->h_addr,
+ sizeof(net_server_addr.sin_addr));
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- address of host is %x\n",
+ ntohl(net_server_addr.sin_addr.s_addr)));
+
+ /* Get the service entry */
+ if (!(our_servent = getservbyname(KRB5_ADM_SERVICE_NAME, "tcp"))) {
+ kret = errno;
+ fprintf(stderr, net_no_servent_fmt, programname,
+ KRB5_ADM_SERVICE_NAME, error_message(kret));
+ goto done;
+ }
+ net_server_addr.sin_port = our_servent->s_port;
+ net_server_addr_init = 1;
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- service name (%s) is on port %d\n", our_servent->s_name,
+ our_servent->s_port));
+
+ /* Now open the listen socket */
+ net_listen_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (net_listen_socket < 0) {
+ kret = errno;
+ fprintf(stderr, net_sockerr_fmt, programname, error_message(kret));
+ goto done;
+ }
+
+ /* Bind socket */
+ bind_sleep = 1;
+ bind_tries = 0;
+ do {
+ if (bind(net_listen_socket,
+ &net_server_addr,
+ sizeof(net_server_addr)) < 0) {
+ kret = errno;
+ if (errno != EADDRINUSE) {
+ fprintf(stderr, net_binderr_fmt, programname,
+ error_message(kret));
+ goto done;
+ }
+ else {
+ bind_tries++;
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- bind failed sleeping for %d seconds\n",
+ bind_sleep));
+ sleep(bind_sleep);
+ bind_sleep = bind_sleep << 1;
+ }
+ }
+ else {
+ DPRINT(DEBUG_HOST, net_debug_level,
+ ("- bound socket %d on port\n", net_listen_socket));
+ break;
+ }
+ } while (bind_tries < MAX_BIND_TRIES);
+
+ done:
+ DPRINT(DEBUG_CALLS, net_debug_level, ("X net_init() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * net_finish() - Finish network context.
+ */
+void
+net_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, net_debug_level, ("* net_finish()\n"));
+ if (net_max_slaves)
+ free(net_slave_table);
+ if (net_listen_socket >= 0)
+ close(net_listen_socket);
+ if (net_service_princ_init)
+ krb5_free_principal(kcontext, net_service_principal);
+ if (net_service_name)
+ free(net_service_name);
+ DPRINT(DEBUG_CALLS, net_debug_level, ("X net_finish()\n"));
+}
+\f
+/*
+ * net_dispatch() - Listen and dispatch request.
+ *
+ * Loop forever selecting on the listen socket. When an incoming connection
+ * comes in, dispatch to net_client_connect().
+ */
+krb5_error_code
+net_dispatch(kcontext)
+ krb5_context kcontext;
+{
+ krb5_error_code kret;
+ fd_set mask, readfds;
+ int nready;
+
+ DPRINT(DEBUG_CALLS, net_debug_level, ("* net_dispatch()\n"));
+
+ kret = 0;
+
+ /* Set up the fdset mask */
+ FD_ZERO(&mask);
+ FD_SET(net_listen_socket, &mask);
+
+ /*
+ * SIGTERM (or SIGINT, if debug) shuts us down.
+ */
+ signal(SIGTERM, net_shutdown);
+#ifdef DEBUG
+ signal(SIGINT, net_shutdown);
+#endif /* DEBUG */
+
+#if !USE_PTHREADS
+ /*
+ * SIGCHILD indicates end of child process life.
+ */
+ signal(SIGCHLD, net_reaper);
+#endif /* !USE_PTHREADS */
+
+ /* Receive connections on the socket */
+ DLOG(DEBUG_OPERATION, net_debug_level, "listening on socket");
+ if (setjmp(shutdown_jmp) == 0) {
+ if (listen(net_listen_socket, SOMAXCONN) < 0)
+ kret = errno;
+ }
+ else
+ kret = EINTR;
+ DLOG(DEBUG_OPERATION, net_debug_level, "listen done");
+
+ while (kret == 0) {
+ /*
+ * Prepare to catch signals.
+ */
+ if (setjmp(shutdown_jmp) == 0) {
+ readfds = mask;
+ DLOG(DEBUG_OPERATION, net_debug_level, "doing select");
+ if ((nready = select(net_listen_socket+1,
+ &readfds,
+ (fd_set *) NULL,
+ (fd_set *) NULL,
+ (struct timeval *) NULL)) == 0) {
+ DLOG(DEBUG_OPERATION, net_debug_level, "nobody ready");
+ continue; /* Nobody ready */
+ }
+
+ if ((nready < 0) && (errno != EINTR)) {
+ com_err(net_dispatch_msg, errno, net_select_fmt);
+ continue;
+ }
+
+ if (FD_ISSET(net_listen_socket, &readfds)) {
+ struct sockaddr_in client_addr;
+ int addrlen;
+ int conn_sock;
+
+ addrlen = sizeof(client_addr);
+ DLOG(DEBUG_OPERATION, net_debug_level,
+ "accept connection");
+ while (((conn_sock = accept(net_listen_socket,
+ (struct sockaddr *) &client_addr,
+ &addrlen)) < 0) &&
+ (errno == EINTR));
+
+ if (conn_sock < 0) {
+ kret = errno;
+ break;
+ }
+ DLOG(DEBUG_OPERATION, net_debug_level,
+ "accepted connection");
+ kret = net_dispatch_client(kcontext,
+ net_listen_socket,
+ conn_sock,
+ &client_addr);
+ if (kret) {
+ com_err(net_dispatch_msg, kret, net_cl_disp_fmt);
+ continue;
+ }
+ DLOG(DEBUG_OPERATION, net_debug_level, "dispatch done");
+ }
+ else {
+ com_err(net_dispatch_msg, 0, net_not_ready_fmt);
+ kret = EIO;
+ }
+ }
+ else {
+ DLOG(DEBUG_OPERATION, net_debug_level,
+ "dispatch interrupted by SIGTERM");
+ kret = 0;
+ break;
+ }
+ }
+
+ DPRINT(DEBUG_CALLS, net_debug_level, ("X net_dispatch() = %d\n", kret));
+ return(kret);
+}
+\f
+/*
+ * Return our service principal.
+ */
+krb5_principal
+net_server_princ()
+{
+ if (net_service_princ_init)
+ return(net_service_principal);
+ else
+ return((krb5_principal) NULL);
+}
--- /dev/null
+/*
+ * kadmin/v5server/srv_output.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.
+ *
+ */
+
+/*
+ * srv_output.c - Handle Kerberos output related functions.
+ */
+#include "k5-int.h"
+#include "com_err.h"
+#include "kadm5_defs.h"
+#include "adm.h"
+
+static const char *out_adm_success = "Operation successful.";
+static const char *out_adm_cmd_unknown = "Command %s unknown.";
+static const char *out_adm_pw_unaccept = "Password unacceptable.";
+static const char *out_adm_bad_princ = "Principal unknown.";
+static const char *out_adm_pwd_too_short = "Password is too short.";
+static const char *out_adm_pwd_weak = "Password generates weak key.";
+static const char *out_adm_not_allowed = "You are not allowed to change your password.";
+static const char *out_adm_bad_pw = "Password incorrect.";
+static const char *out_adm_not_in_tkt = "Not an initial ticket.";
+static const char *out_adm_cant_change = "Cannot change password.";
+static const char *out_adm_lang_unsupp = "Language %s unsupported.";
+static const char *out_adm_bad_args = "Bad argument list format for %s command.";
+static const char *out_adm_bad_cmd = "Command %s not supported.";
+static const char *out_adm_no_cmd = "No command in message.";
+static const char *out_adm_no_err = "Unknown error.";
+static int output_debug_level = 0;
+static int output_mime_enabled = 0;
+\f
+static char *
+lang_error_message(lang, kval)
+ char *lang;
+ krb5_error_code kval;
+{
+ char *ret;
+ char *ermsg;
+
+ ermsg = error_message(kval);
+ if (lang && output_lang_supported(lang)) {
+ /*
+ * Just for demonstration purposes.
+ */
+ ret = (char *) malloc(strlen(ermsg)+strlen(lang)+3+1);
+ if (ret)
+ sprintf(ret, "%s - %s", lang, ermsg);
+ }
+ else {
+ ret = (char *) malloc(strlen(ermsg)+1);
+ if (ret)
+ strcpy(ret, ermsg);
+ }
+ return(ret);
+}
+
+static char *
+lang_adm_message(lang, ecode, aux, nargs, alist)
+ char *lang;
+ krb5_int32 ecode;
+ krb5_int32 aux;
+ krb5_int32 nargs;
+ krb5_data *alist;
+{
+ char *ret;
+ const char *ermsg;
+ char *erarg;
+ int alen;
+
+ erarg = (char *) NULL;
+ switch (ecode) {
+ case KRB5_ADM_SUCCESS:
+ ermsg = out_adm_success; break;
+ case KRB5_ADM_CMD_UNKNOWN:
+ switch (aux) {
+ case KRB5_ADM_BAD_ARGS:
+ ermsg = out_adm_bad_args;
+ erarg = ((nargs >= 1) ? alist[0].data : (char *) NULL);
+ break;
+ case KRB5_ADM_BAD_CMD:
+ ermsg = out_adm_bad_cmd;
+ erarg = ((nargs >= 1) ? alist[0].data : (char *) NULL);
+ break;
+ case KRB5_ADM_NO_CMD:
+ ermsg = out_adm_no_cmd;
+ break;
+ default:
+ ermsg = out_adm_bad_args;
+ erarg = ((nargs >= 1) ? alist[0].data : (char *) NULL);
+ break;
+ }
+ break;
+ case KRB5_ADM_PW_UNACCEPT:
+ switch (aux) {
+ case KRB5_ADM_BAD_PRINC:
+ ermsg = out_adm_bad_princ;
+ break;
+ case KRB5_ADM_PWD_TOO_SHORT:
+ ermsg = out_adm_pwd_too_short;
+ break;
+ case KRB5_ADM_PWD_WEAK:
+ ermsg = out_adm_pwd_weak;
+ break;
+ default:
+ ermsg = out_adm_pw_unaccept;
+ break;
+ }
+ break;
+ case KRB5_ADM_BAD_PW:
+ ermsg = out_adm_bad_pw; break;
+ case KRB5_ADM_NOT_IN_TKT:
+ ermsg = out_adm_not_in_tkt; break;
+ case KRB5_ADM_CANT_CHANGE:
+ switch (aux) {
+ case KRB5_ADM_BAD_PRINC:
+ ermsg = out_adm_bad_princ;
+ break;
+ case KRB5_ADM_PWD_TOO_SHORT:
+ ermsg = out_adm_pwd_too_short;
+ break;
+ case KRB5_ADM_PWD_WEAK:
+ ermsg = out_adm_pwd_weak;
+ break;
+ case KRB5_ADM_NOT_ALLOWED:
+ ermsg = out_adm_not_allowed;
+ break;
+ default:
+ ermsg = out_adm_cant_change;
+ break;
+ }
+ break;
+ case KRB5_ADM_LANG_NOT_SUPPORTED:
+ ermsg = out_adm_lang_unsupp;
+ erarg = ((nargs >= 2) ? alist[1].data : (char *) NULL);
+ break;
+ default:
+ ermsg = out_adm_no_err; break;
+ }
+
+ alen = strlen(ermsg)+1;
+ if (erarg)
+ alen += strlen(erarg);
+ if (lang && output_lang_supported(lang)) {
+ alen += strlen(lang)+3;
+ }
+ ret = (char *) malloc(alen);
+ if (lang && output_lang_supported(lang)) {
+ char *xxx;
+
+ /*
+ * Just for demonstration purposes.
+ */
+ if (ret) {
+ sprintf(ret, "%s - ", lang);
+ xxx = &ret[strlen(ret)];
+ sprintf(xxx, ermsg, erarg);
+ }
+ }
+ else {
+ if (ret)
+ sprintf(ret, ermsg, erarg);
+ }
+ return(ret);
+}
+
+static char *
+mimeify_text(msg)
+ char *msg;
+{
+ char *ret;
+ /*
+ * Just for demonstration purposes.
+ */
+
+ if (output_mime_enabled) {
+ ret = (char *) malloc(strlen(msg)+6+3);
+ if (ret)
+ sprintf(ret, "MIME: %s\r\n", msg);
+ if (!ret)
+ ret = msg;
+ }
+ else
+ ret = msg;
+ return(ret);
+}
+
+/*
+ * output_init() - Initialize output context.
+ */
+krb5_error_code
+output_init(kcontext, debug_level, language_list, mime_enabled)
+ krb5_context kcontext;
+ int debug_level;
+ char *language_list;
+ krb5_boolean mime_enabled;
+{
+ krb5_error_code kret;
+
+ kret = 0;
+ output_debug_level = debug_level;
+ DPRINT(DEBUG_CALLS, output_debug_level,
+ ("* output_init(llist=%s, mime=%d)\n",
+ ((language_list) ? language_list : "(null)"),
+ mime_enabled));
+ output_mime_enabled = mime_enabled;
+ DPRINT(DEBUG_CALLS, output_debug_level, ("X output_init() = %d\n", kret));
+ return(kret);
+}
+
+/*
+ * output_finish - Terminate output context.
+ */
+void
+output_finish(kcontext, debug_level)
+ krb5_context kcontext;
+ int debug_level;
+{
+ DPRINT(DEBUG_CALLS, output_debug_level, ("* output_finish()\n"));
+ DPRINT(DEBUG_CALLS, output_debug_level, ("X output_finish()\n"));
+}
+
+/*
+ * output_lang_supported- Is a language supported?
+ */
+krb5_boolean
+output_lang_supported(lname)
+ char *lname;
+{
+ krb5_boolean ret;
+ DPRINT(DEBUG_CALLS, output_debug_level,
+ ("* output_lang_supported(lang=%s)\n",
+ ((lname) ? lname : "(default)")));
+ ret = 1;
+ DPRINT(DEBUG_CALLS, output_debug_level,
+ ("X output_lang_supported() = %d\n", ret));
+ return(ret);
+}
+
+/*
+ * output_errmsg - Return an error message.
+ */
+char *
+output_krb5_errmsg(lang, mime, kval)
+ char * lang;
+ krb5_boolean mime;
+ krb5_error_code kval;
+{
+ char *ret;
+ char *ermsg;
+ int alen;
+
+ DPRINT(DEBUG_CALLS, output_debug_level,
+ ("* output_krb5_errmsg(v=%d, lang=%s, mime=%d)\n",
+ kval, ((lang) ? lang : "(default)", mime)));
+ ermsg = lang_error_message(lang, kval);
+ if (mime) {
+ ret = mimeify_text(ermsg);
+ if (ret != ermsg)
+ free(ermsg);
+ }
+ else
+ ret = ermsg;
+ DPRINT(DEBUG_CALLS, output_debug_level, ("X output_krb5_errmsg()\n"));
+ return(ret);
+}
+
+/*
+ * output_adm_error - Output an administrative error message string.
+ */
+char *
+output_adm_error(lang, mime, ecode, aux, nargs, alist)
+ char *lang;
+ krb5_boolean mime;
+ krb5_int32 ecode;
+ krb5_int32 aux;
+ krb5_int32 nargs;
+ krb5_data *alist;
+{
+ char *ermsg;
+ char *ret;
+
+ DPRINT(DEBUG_CALLS, output_debug_level,
+ ("* output_adm_err(lang=%s, mime=%d, code=%d/%d)\n",
+ ((lang) ? lang : "(default)"), mime, ecode, aux));
+ ermsg = lang_adm_message(lang, ecode, aux, nargs, alist);
+ if (mime) {
+ ret = mimeify_text(ermsg);
+ if (ret != ermsg)
+ free(ermsg);
+ }
+ else
+ ret = ermsg;
+ DPRINT(DEBUG_CALLS, output_debug_level, ("X output_adm_err()\n"));
+ return(ret);
+}