diff options
Diffstat (limited to 'kerberosIV/kadmind')
-rw-r--r-- | kerberosIV/kadmind/Makefile | 25 | ||||
-rw-r--r-- | kerberosIV/kadmind/admin_server.c | 448 | ||||
-rw-r--r-- | kerberosIV/kadmind/kadm_funcs.c | 371 | ||||
-rw-r--r-- | kerberosIV/kadmind/kadm_ser_wrap.c | 210 | ||||
-rw-r--r-- | kerberosIV/kadmind/kadm_server.c | 154 | ||||
-rw-r--r-- | kerberosIV/kadmind/kadmind.8 | 126 |
6 files changed, 1334 insertions, 0 deletions
diff --git a/kerberosIV/kadmind/Makefile b/kerberosIV/kadmind/Makefile new file mode 100644 index 00000000000..b3f340cc3cd --- /dev/null +++ b/kerberosIV/kadmind/Makefile @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.1 1995/12/14 06:52:48 tholo Exp $ + +PROG= kadmind +SRCS= admin_server.c kadm_funcs.c kadm_ser_wrap.c kadm_server.c +.if exists(${.CURDIR}/../kadm/obj) +CFLAGS+=-I${.CURDIR}/../kadm/obj +.else +CFLAGS+=-I${.CURDIR}/../kadm +.endif +.if exists(${.CURDIR}/../krb/obj) +CFLAGS+=-I${.CURDIR}/../krb/obj +.else +CFLAGS+=-I${.CURDIR}/../krb +.endif +.if exists(${.CURDIR}/../ss/obj) +CFLAGS+=-I${.CURDIR}/../ss/obj +.else +CFLAGS+=-I${.CURDIR}/../ss +.endif +LDADD+= -lkadm -lkdb -lkrb -ldes -lacl -lcom_err +DPADD= ${LIBKADM} ${LIBKDB} ${LIBKRB} ${LIBDES} ${LIBACL} ${LIBCOM_ERR} +MAN= kadmind.8 +BINDIR=/usr/libexec + +.include <bsd.prog.mk> diff --git a/kerberosIV/kadmind/admin_server.c b/kerberosIV/kadmind/admin_server.c new file mode 100644 index 00000000000..cc62531798e --- /dev/null +++ b/kerberosIV/kadmind/admin_server.c @@ -0,0 +1,448 @@ +/* $Id: admin_server.c,v 1.1 1995/12/14 06:52:49 tholo Exp $ */ + +/*- + * Copyright (C) 1989 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America is assumed + * to 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. + */ + +/* + * Top-level loop of the kerberos Administration server + */ + +/* + admin_server.c + this holds the main loop and initialization and cleanup code for the server +*/ + +#include <kadm_locl.h> + +/* Almost all procs and such need this, so it is global */ +admin_params prm; /* The command line parameters struct */ + +static char prog[32]; /* WHY IS THIS NEEDED??????? */ +char *progname = prog; +/* GLOBAL */ +char *acldir = DEFAULT_ACL_DIR; +static char krbrlm[REALM_SZ]; + +static unsigned pidarraysize = 0; +static int *pidarray = (int *)0; + +static exit_now = 0; + +static void +doexit() +{ + exit_now = 1; +#ifndef sgi /* Sigh -- sgi cc balks at this... */ + return (void)(0); +#endif +} + +static void +do_child() +{ + /* SIGCHLD brings us here */ + int pid; + register int i, j; + + int status; + + pid = wait(&status); + + for (i = 0; i < pidarraysize; i++) + if (pidarray[i] == pid) { + /* found it */ + for (j = i; j < pidarraysize-1; j++) + /* copy others down */ + pidarray[j] = pidarray[j+1]; + pidarraysize--; + if (WIFEXITED(status) || WIFSIGNALED(status)) + log("child %d: termsig %d, retcode %d", pid, + WTERMSIG(status), WEXITSTATUS(status)); +#ifndef sgi + return (void)(0); +#endif + } + log("child %d not in list: termsig %d, retcode %d", pid, + WTERMSIG(status), WEXITSTATUS(status)); +#ifndef sgi + return (void)(0); +#endif +} + +static int nSIGCHLD = 0; + +static void +count_SIGCHLD() +{ + nSIGCHLD++; +#ifndef sgi + return (void)(0); +#endif +} + +static void +kill_children(void) +{ + int i; + void (*ofunc)(); + + ofunc = signal(SIGCHLD, count_SIGCHLD); + + for (i = 0; i < pidarraysize; i++) { + kill(pidarray[i], SIGINT); + log("killing child %d", pidarray[i]); + } + + (void) signal(SIGCHLD, ofunc); + + for (; nSIGCHLD != 0; nSIGCHLD--) + do_child(); + + return; +} + +/* close the system log file */ +static void +close_syslog(void) +{ + log("Shutting down admin server"); +} + +static void +byebye(void) /* say goodnight gracie */ +{ + printf("Admin Server (kadm server) has completed operation.\n"); +} + +static void +clear_secrets(void) +{ + bzero((char *)server_parm.master_key, sizeof(server_parm.master_key)); + bzero((char *)server_parm.master_key_schedule, + sizeof(server_parm.master_key_schedule)); + server_parm.master_key_version = 0L; + return; +} + +#ifdef DEBUG +#define cleanexit(code) {kerb_fini(); return;} +#endif + +#ifndef DEBUG +static void +cleanexit(int val) +{ + kerb_fini(); + clear_secrets(); + exit(val); +} +#endif + +static void +process_client(int fd, struct sockaddr_in *who) +{ + u_char *dat; + int dat_len; + u_short dlen; + int retval; + int on = 1; + Principal service; + des_cblock skey; + int more; + int status; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) + log("setsockopt keepalive: %d",errno); + + server_parm.recv_addr = *who; + + if (kerb_init()) { /* Open as client */ + log("can't open krb db"); + cleanexit(1); + } + /* need to set service key to changepw.KRB_MASTER */ + + status = kerb_get_principal(server_parm.sname, server_parm.sinst, &service, + 1, &more); + if (status == -1) { + /* db locked */ + u_long retcode = KADM_DB_INUSE; + char *pdat; + + dat_len = KADM_VERSIZE + sizeof(u_long); + dat = (u_char *) malloc((unsigned)dat_len); + pdat = (char *) dat; + retcode = htonl((u_long) KADM_DB_INUSE); + (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE); + bcopy((char *)&retcode, &pdat[KADM_VERSIZE], sizeof(u_long)); + goto out; + } else if (!status) { + log("no service %s.%s",server_parm.sname, server_parm.sinst); + cleanexit(2); + } + + bcopy((char *)&service.key_low, (char *)skey, 4); + bcopy((char *)&service.key_high, (char *)(((long *) skey) + 1), 4); + bzero((char *)&service, sizeof(service)); + kdb_encrypt_key (&skey, &skey, &server_parm.master_key, + server_parm.master_key_schedule, DES_DECRYPT); + (void) krb_set_key((char *)skey, 0); /* if error, will show up when + rd_req fails */ + bzero((char *)skey, sizeof(skey)); + + while (1) { + if ((retval = krb_net_read(fd, (char *)&dlen, sizeof(u_short))) != + sizeof(u_short)) { + if (retval < 0) + log("dlen read: %s",error_message(errno)); + else if (retval) + log("short dlen read: %d",retval); + (void) close(fd); + cleanexit(retval ? 3 : 0); + } + if (exit_now) { + cleanexit(0); + } + dat_len = (int) ntohs(dlen); + dat = (u_char *) malloc((unsigned)dat_len); + if (!dat) { + log("malloc: No memory"); + (void) close(fd); + cleanexit(4); + } + if ((retval = krb_net_read(fd, (char *)dat, dat_len)) != dat_len) { + if (retval < 0) + log("data read: %s",error_message(errno)); + else + log("short read: %d vs. %d", dat_len, retval); + (void) close(fd); + cleanexit(5); + } + if (exit_now) { + cleanexit(0); + } + if ((retval = kadm_ser_in(&dat,&dat_len)) != KADM_SUCCESS) + log("processing request: %s", error_message(retval)); + + /* kadm_ser_in did the processing and returned stuff in + dat & dat_len , return the appropriate data */ + + out: + dlen = (u_short) dat_len; + + if (dat_len != (int)dlen) { + clear_secrets(); + abort(); /* XXX */ + } + dlen = htons(dlen); + + if (krb_net_write(fd, (char *)&dlen, sizeof(u_short)) < 0) { + log("writing dlen to client: %s",error_message(errno)); + (void) close(fd); + cleanexit(6); + } + + if (krb_net_write(fd, (char *)dat, dat_len) < 0) { + log(LOG_ERR, "writing to client: %s",error_message(errno)); + (void) close(fd); + cleanexit(7); + } + free((char *)dat); + } + /*NOTREACHED*/ +} + +/* +kadm_listen +listen on the admin servers port for a request +*/ +static int +kadm_listen(void) +{ + int found; + int admin_fd; + int peer_fd; + fd_set mask, readfds; + struct sockaddr_in peer; + int addrlen; + int pid; + + (void) signal(SIGINT, doexit); + (void) signal(SIGTERM, doexit); + (void) signal(SIGHUP, doexit); + (void) signal(SIGQUIT, doexit); + (void) signal(SIGPIPE, SIG_IGN); /* get errors on write() */ + (void) signal(SIGALRM, doexit); + (void) signal(SIGCHLD, do_child); + + if ((admin_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return KADM_NO_SOCK; + if (bind(admin_fd, (struct sockaddr *)&server_parm.admin_addr, + sizeof(struct sockaddr_in)) < 0) + return KADM_NO_BIND; + (void) listen(admin_fd, 1); + FD_ZERO(&mask); + FD_SET(admin_fd, &mask); + + for (;;) { /* loop nearly forever */ + if (exit_now) { + clear_secrets(); + kill_children(); + return(0); + } + readfds = mask; + if ((found = select(admin_fd+1,&readfds,(fd_set *)0, + (fd_set *)0, (struct timeval *)0)) == 0) + continue; /* no things read */ + if (found < 0) { + if (errno != EINTR) + log("select: %s",error_message(errno)); + continue; + } + if (FD_ISSET(admin_fd, &readfds)) { + /* accept the conn */ + addrlen = sizeof(peer); + if ((peer_fd = accept(admin_fd, (struct sockaddr *)&peer, + &addrlen)) < 0) { + log("accept: %s",error_message(errno)); + continue; + } +#ifndef DEBUG + /* if you want a sep daemon for each server */ + if ((pid = fork())) { + /* parent */ + if (pid < 0) { + log("fork: %s",error_message(errno)); + (void) close(peer_fd); + continue; + } + /* fork succeded: keep tabs on child */ + (void) close(peer_fd); + if (pidarray) { + pidarray = (int *)realloc((char *)pidarray, ++pidarraysize); + pidarray[pidarraysize-1] = pid; + } else { + pidarray = (int *)malloc(pidarraysize = 1); + pidarray[0] = pid; + } + } else { + /* child */ + (void) close(admin_fd); +#endif /* DEBUG */ + /* do stuff */ + process_client (peer_fd, &peer); +#ifndef DEBUG + } +#endif + } else { + log("something else woke me up!"); + return(0); + } + } + /*NOTREACHED*/ +} + +/* +** Main does the logical thing, it sets up the database and RPC interface, +** as well as handling the creation and maintenance of the syslog file... +*/ +int +main(int argc, char **argv) /* admin_server main routine */ + + +{ + int errval; + int c; + + prog[sizeof(prog)-1]='\0'; /* Terminate... */ + (void) strncpy(prog, argv[0], sizeof(prog)-1); + + /* initialize the admin_params structure */ + prm.sysfile = KADM_SYSLOG; /* default file name */ + prm.inter = 1; + + bzero(krbrlm, sizeof(krbrlm)); + + while ((c = getopt(argc, argv, "f:hnd:a:r:")) != EOF) + switch(c) { + case 'f': /* Syslog file name change */ + prm.sysfile = optarg; + break; + case 'n': + prm.inter = 0; + break; + case 'a': /* new acl directory */ + acldir = optarg; + break; + case 'd': + /* put code to deal with alt database place */ + if ((errval = kerb_db_set_name(optarg))) { + fprintf(stderr, "opening database %s: %s", + optarg, error_message(errval)); + exit(1); + } + break; + case 'r': + (void) strncpy(krbrlm, optarg, sizeof(krbrlm) - 1); + break; + case 'h': /* get help on using admin_server */ + default: + printf("Usage: admin_server [-h] [-n] [-r realm] [-d dbname] [-f filename] [-a acldir]\n"); + exit(-1); /* failure */ + } + + if (krbrlm[0] == 0) + if (krb_get_lrealm(krbrlm, 0) != KSUCCESS) { + fprintf(stderr, + "Unable to get local realm. Fix krb.conf or use -r.\n"); + exit(1); + } + + printf("KADM Server %s initializing\n",KADM_VERSTR); + printf("Please do not use 'kill -9' to kill this job, use a\n"); + printf("regular kill instead\n\n"); + + set_logfile(prm.sysfile); + log("Admin server starting"); + + (void) kerb_db_set_lockmode(KERB_DBL_NONBLOCKING); + errval = kerb_init(); /* Open the Kerberos database */ + if (errval) { + fprintf(stderr, "error: kerb_init() failed"); + close_syslog(); + byebye(); + } + /* set up the server_parm struct */ + if ((errval = kadm_ser_init(prm.inter, krbrlm))==KADM_SUCCESS) { + kerb_fini(); /* Close the Kerberos database-- + will re-open later */ + errval = kadm_listen(); /* listen for calls to server from + clients */ + } + if (errval != KADM_SUCCESS) { + fprintf(stderr,"error: %s\n",error_message(errval)); + kerb_fini(); /* Close if error */ + } + close_syslog(); /* Close syslog file, print + closing note */ + byebye(); /* Say bye bye on the terminal + in use */ + exit(1); +} /* procedure main */ diff --git a/kerberosIV/kadmind/kadm_funcs.c b/kerberosIV/kadmind/kadm_funcs.c new file mode 100644 index 00000000000..6f9a6b78fca --- /dev/null +++ b/kerberosIV/kadmind/kadm_funcs.c @@ -0,0 +1,371 @@ +/* $Id: kadm_funcs.c,v 1.1 1995/12/14 06:52:49 tholo Exp $ */ + +/*- + * Copyright (C) 1989 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America is assumed + * to 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. + */ + +/* + * Kerberos administration server-side database manipulation routines + */ + +/* +kadm_funcs.c +the actual database manipulation code +*/ + +#include <kadm_locl.h> +#include <sys/param.h> + +static int +check_access(char *pname, char *pinst, char *prealm, enum acl_types acltype) +{ + char checkname[MAX_K_NAME_SZ]; + char filename[MAXPATHLEN]; + + (void) sprintf(checkname, "%s.%s@%s", pname, pinst, prealm); + + switch (acltype) { + case ADDACL: + (void) sprintf(filename, "%s%s", acldir, ADD_ACL_FILE); + break; + case GETACL: + (void) sprintf(filename, "%s%s", acldir, GET_ACL_FILE); + break; + case MODACL: + (void) sprintf(filename, "%s%s", acldir, MOD_ACL_FILE); + break; + } + return(acl_check(filename, checkname)); +} + +static int +wildcard(char *str) +{ + if (!strcmp(str, WILDCARD_STR)) + return(1); + return(0); +} + +#define failadd(code) { (void) log("FAILED addding '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; } + +int +kadm_add_entry (char *rname, char *rinstance, char *rrealm, Kadm_vals *valsin, Kadm_vals *valsout) + /* requestors name */ + /* requestors instance */ + /* requestors realm */ + + +{ + long numfound; /* check how many we get written */ + int more; /* pointer to more grabbed records */ + Principal data_i, data_o; /* temporary principal */ + u_char flags[4]; + des_cblock newpw; + Principal default_princ; + + if (!check_access(rname, rinstance, rrealm, ADDACL)) { + (void) log("WARNING: '%s.%s@%s' tried to add an entry for '%s.%s'", + rname, rinstance, rrealm, valsin->name, valsin->instance); + return KADM_UNAUTH; + } + + /* Need to check here for "legal" name and instance */ + if (wildcard(valsin->name) || wildcard(valsin->instance)) { + failadd(KADM_ILL_WILDCARD); + } + + (void) log("request to add an entry for '%s.%s' from '%s.%s@%s'", + valsin->name, valsin->instance, rname, rinstance, rrealm); + + numfound = kerb_get_principal(KERB_DEFAULT_NAME, KERB_DEFAULT_INST, + &default_princ, 1, &more); + if (numfound == -1) { + failadd(KADM_DB_INUSE); + } else if (numfound != 1) { + failadd(KADM_UK_RERROR); + } + + kadm_vals_to_prin(valsin->fields, &data_i, valsin); + (void) strncpy(data_i.name, valsin->name, ANAME_SZ); + (void) strncpy(data_i.instance, valsin->instance, INST_SZ); + + if (!IS_FIELD(KADM_EXPDATE,valsin->fields)) + data_i.exp_date = default_princ.exp_date; + if (!IS_FIELD(KADM_ATTR,valsin->fields)) + data_i.attributes = default_princ.attributes; + if (!IS_FIELD(KADM_MAXLIFE,valsin->fields)) + data_i.max_life = default_princ.max_life; + + bzero((char *)&default_princ, sizeof(default_princ)); + + /* convert to host order */ + data_i.key_low = ntohl(data_i.key_low); + data_i.key_high = ntohl(data_i.key_high); + + + bcopy(&data_i.key_low,newpw,4); + bcopy(&data_i.key_high,(char *)(((long *) newpw) + 1),4); + + /* encrypt new key in master key */ + kdb_encrypt_key (&newpw, &newpw, &server_parm.master_key, + server_parm.master_key_schedule, DES_ENCRYPT); + bcopy(newpw,&data_i.key_low,4); + bcopy((char *)(((long *) newpw) + 1), &data_i.key_high,4); + bzero((char *)newpw, sizeof(newpw)); + + data_o = data_i; + numfound = kerb_get_principal(valsin->name, valsin->instance, + &data_o, 1, &more); + if (numfound == -1) { + failadd(KADM_DB_INUSE); + } else if (numfound) { + failadd(KADM_INUSE); + } else { + data_i.key_version++; + data_i.kdc_key_ver = server_parm.master_key_version; + (void) strncpy(data_i.mod_name, rname, sizeof(data_i.mod_name)-1); + (void) strncpy(data_i.mod_instance, rinstance, + sizeof(data_i.mod_instance)-1); + + numfound = kerb_put_principal(&data_i, 1); + if (numfound == -1) { + failadd(KADM_DB_INUSE); + } else if (numfound) { + failadd(KADM_UK_SERROR); + } else { + numfound = kerb_get_principal(valsin->name, valsin->instance, + &data_o, 1, &more); + if ((numfound!=1) || (more!=0)) { + failadd(KADM_UK_RERROR); + } + bzero((char *)flags, sizeof(flags)); + SET_FIELD(KADM_NAME,flags); + SET_FIELD(KADM_INST,flags); + SET_FIELD(KADM_EXPDATE,flags); + SET_FIELD(KADM_ATTR,flags); + SET_FIELD(KADM_MAXLIFE,flags); + kadm_prin_to_vals(flags, valsout, &data_o); + (void) log("'%s.%s' added.", valsin->name, valsin->instance); + return KADM_DATA; /* Set all the appropriate fields */ + } + } +} +#undef failadd + +#define failget(code) { (void) log("FAILED retrieving '%s.%s' (%s)", valsin->name, valsin->instance, error_message(code)); return code; } + +int +kadm_get_entry (char *rname, char *rinstance, char *rrealm, Kadm_vals *valsin, u_char *flags, Kadm_vals *valsout) + /* requestors name */ + /* requestors instance */ + /* requestors realm */ + /* what they wannt to get */ + /* which fields we want */ + /* what data is there */ +{ + long numfound; /* check how many were returned */ + int more; /* To point to more name.instances */ + Principal data_o; /* Data object to hold Principal */ + + + if (!check_access(rname, rinstance, rrealm, GETACL)) { + (void) log("WARNING: '%s.%s@%s' tried to get '%s.%s's entry", + rname, rinstance, rrealm, valsin->name, valsin->instance); + return KADM_UNAUTH; + } + + if (wildcard(valsin->name) || wildcard(valsin->instance)) { + failget(KADM_ILL_WILDCARD); + } + + (void) log("retrieve '%s.%s's entry for '%s.%s@%s'", + valsin->name, valsin->instance, rname, rinstance, rrealm); + + /* Look up the record in the database */ + numfound = kerb_get_principal(valsin->name, valsin->instance, + &data_o, 1, &more); + if (numfound == -1) { + failget(KADM_DB_INUSE); + } else if (numfound) { /* We got the record, let's return it */ + kadm_prin_to_vals(flags, valsout, &data_o); + (void) log("'%s.%s' retrieved.", valsin->name, valsin->instance); + return KADM_DATA; /* Set all the appropriate fields */ + } else { + failget(KADM_NOENTRY); /* Else whimper and moan */ + } +} +#undef failget + +#define failmod(code) { (void) log("FAILED modifying '%s.%s' (%s)", valsin1->name, valsin1->instance, error_message(code)); return code; } + +int +kadm_mod_entry (char *rname, char *rinstance, char *rrealm, Kadm_vals *valsin1, Kadm_vals *valsin2, Kadm_vals *valsout) + /* requestors name */ + /* requestors instance */ + /* requestors realm */ + /* holds the parameters being + passed in */ + /* the actual record which is returned */ +{ + long numfound; + int more; + Principal data_o, temp_key; + u_char fields[4]; + des_cblock newpw; + + if (wildcard(valsin1->name) || wildcard(valsin1->instance)) { + failmod(KADM_ILL_WILDCARD); + } + + if (!check_access(rname, rinstance, rrealm, MODACL)) { + (void) log("WARNING: '%s.%s@%s' tried to change '%s.%s's entry", + rname, rinstance, rrealm, valsin1->name, valsin1->instance); + return KADM_UNAUTH; + } + + (void) log("request to modify '%s.%s's entry from '%s.%s@%s' ", + valsin1->name, valsin1->instance, rname, rinstance, rrealm); + + numfound = kerb_get_principal(valsin1->name, valsin1->instance, + &data_o, 1, &more); + if (numfound == -1) { + failmod(KADM_DB_INUSE); + } else if (numfound) { + kadm_vals_to_prin(valsin2->fields, &temp_key, valsin2); + (void) strncpy(data_o.name, valsin1->name, ANAME_SZ); + (void) strncpy(data_o.instance, valsin1->instance, INST_SZ); + if (IS_FIELD(KADM_EXPDATE,valsin2->fields)) + data_o.exp_date = temp_key.exp_date; + if (IS_FIELD(KADM_ATTR,valsin2->fields)) + data_o.attributes = temp_key.attributes; + if (IS_FIELD(KADM_MAXLIFE,valsin2->fields)) + data_o.max_life = temp_key.max_life; + if (IS_FIELD(KADM_DESKEY,valsin2->fields)) { + data_o.key_version++; + data_o.kdc_key_ver = server_parm.master_key_version; + + + /* convert to host order */ + temp_key.key_low = ntohl(temp_key.key_low); + temp_key.key_high = ntohl(temp_key.key_high); + + + bcopy(&temp_key.key_low,newpw,4); + bcopy(&temp_key.key_high,(char *)(((long *) newpw) + 1),4); + + /* encrypt new key in master key */ + kdb_encrypt_key (&newpw, &newpw, &server_parm.master_key, + server_parm.master_key_schedule, DES_ENCRYPT); + bcopy(newpw,&data_o.key_low,4); + bcopy((char *)(((long *) newpw) + 1), &data_o.key_high,4); + bzero((char *)newpw, sizeof(newpw)); + } + bzero((char *)&temp_key, sizeof(temp_key)); + + (void) strncpy(data_o.mod_name, rname, sizeof(data_o.mod_name)-1); + (void) strncpy(data_o.mod_instance, rinstance, + sizeof(data_o.mod_instance)-1); + more = kerb_put_principal(&data_o, 1); + + bzero((char *)&data_o, sizeof(data_o)); + + if (more == -1) { + failmod(KADM_DB_INUSE); + } else if (more) { + failmod(KADM_UK_SERROR); + } else { + numfound = kerb_get_principal(valsin1->name, valsin1->instance, + &data_o, 1, &more); + if ((more!=0)||(numfound!=1)) { + failmod(KADM_UK_RERROR); + } + bzero((char *) fields, sizeof(fields)); + SET_FIELD(KADM_NAME,fields); + SET_FIELD(KADM_INST,fields); + SET_FIELD(KADM_EXPDATE,fields); + SET_FIELD(KADM_ATTR,fields); + SET_FIELD(KADM_MAXLIFE,fields); + kadm_prin_to_vals(fields, valsout, &data_o); + (void) log("'%s.%s' modified.", valsin1->name, valsin1->instance); + return KADM_DATA; /* Set all the appropriate fields */ + } + } + else { + failmod(KADM_NOENTRY); + } +} +#undef failmod + +#define failchange(code) { (void) log("FAILED changing key for '%s.%s@%s' (%s)", rname, rinstance, rrealm, error_message(code)); return code; } + +int +kadm_change (char *rname, char *rinstance, char *rrealm, unsigned char *newpw) +{ + long numfound; + int more; + Principal data_o; + des_cblock local_pw; + + if (strcmp(server_parm.krbrlm, rrealm)) { + (void) log("change key request from wrong realm, '%s.%s@%s'!\n", + rname, rinstance, rrealm); + return(KADM_WRONG_REALM); + } + + if (wildcard(rname) || wildcard(rinstance)) { + failchange(KADM_ILL_WILDCARD); + } + (void) log("'%s.%s@%s' wants to change its password", + rname, rinstance, rrealm); + + bcopy(newpw, local_pw, sizeof(local_pw)); + + /* encrypt new key in master key */ + kdb_encrypt_key (&local_pw, &local_pw, &server_parm.master_key, + server_parm.master_key_schedule, DES_ENCRYPT); + + numfound = kerb_get_principal(rname, rinstance, + &data_o, 1, &more); + if (numfound == -1) { + failchange(KADM_DB_INUSE); + } else if (numfound) { + bcopy(local_pw,&data_o.key_low,4); + bcopy((char *)(((long *) local_pw) + 1), &data_o.key_high,4); + data_o.key_version++; + data_o.kdc_key_ver = server_parm.master_key_version; + (void) strncpy(data_o.mod_name, rname, sizeof(data_o.mod_name)-1); + (void) strncpy(data_o.mod_instance, rinstance, + sizeof(data_o.mod_instance)-1); + more = kerb_put_principal(&data_o, 1); + bzero((char *) local_pw, sizeof(local_pw)); + bzero((char *) &data_o, sizeof(data_o)); + if (more == -1) { + failchange(KADM_DB_INUSE); + } else if (more) { + failchange(KADM_UK_SERROR); + } else { + (void) log("'%s.%s@%s' password changed.", rname, rinstance, rrealm); + return KADM_SUCCESS; + } + } + else { + failchange(KADM_NOENTRY); + } +} +#undef failchange diff --git a/kerberosIV/kadmind/kadm_ser_wrap.c b/kerberosIV/kadmind/kadm_ser_wrap.c new file mode 100644 index 00000000000..eec12f47c00 --- /dev/null +++ b/kerberosIV/kadmind/kadm_ser_wrap.c @@ -0,0 +1,210 @@ +/* $Id: kadm_ser_wrap.c,v 1.1 1995/12/14 06:52:49 tholo Exp $ */ + +/*- + * Copyright (C) 1989 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America is assumed + * to 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. + */ + +/* + * Kerberos administration server-side support functions + */ + +/* +kadm_ser_wrap.c +unwraps wrapped packets and calls the appropriate server subroutine +*/ + +#include <kadm_locl.h> +#include <sys/param.h> + +/* GLOBAL */ +Kadm_Server server_parm; + +/* +kadm_ser_init +set up the server_parm structure +*/ +int +kadm_ser_init(int inter, char *realm) + /* interactive or from file */ + +{ + struct servent *sep; + struct hostent *hp; + char hostname[MAXHOSTNAMELEN]; + + (void) init_kadm_err_tbl(); + (void) init_krb_err_tbl(); + if (gethostname(hostname, sizeof(hostname))) + return KADM_NO_HOSTNAME; + + (void) strcpy(server_parm.sname, PWSERV_NAME); + (void) strcpy(server_parm.sinst, KRB_MASTER); + (void) strcpy(server_parm.krbrlm, realm); + + server_parm.admin_fd = -1; + /* setting up the addrs */ + if ((sep = getservbyname(KADM_SNAME, "tcp")) == NULL) + return KADM_NO_SERV; + bzero((char *)&server_parm.admin_addr,sizeof(server_parm.admin_addr)); + server_parm.admin_addr.sin_family = AF_INET; + if ((hp = gethostbyname(hostname)) == NULL) + return KADM_NO_HOSTNAME; + bcopy(hp->h_addr, (char *) &server_parm.admin_addr.sin_addr.s_addr, + hp->h_length); + server_parm.admin_addr.sin_port = sep->s_port; + /* setting up the database */ + if (kdb_get_master_key((inter==1), &server_parm.master_key, + server_parm.master_key_schedule) != 0) + return KADM_NO_MAST; + if ((server_parm.master_key_version = + kdb_verify_master_key(&server_parm.master_key, + server_parm.master_key_schedule,stderr))<0) + return KADM_NO_VERI; + return KADM_SUCCESS; +} + +static void errpkt(u_char **dat, int *dat_len, int code) +{ + u_int32_t retcode; + char *pdat; + + free((char *)*dat); /* free up req */ + *dat_len = KADM_VERSIZE + sizeof(u_int32_t); + *dat = (u_char *) malloc((unsigned)*dat_len); + pdat = (char *) *dat; + retcode = htonl((u_int32_t) code); + (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE); + bcopy((char *)&retcode, &pdat[KADM_VERSIZE], sizeof(u_int32_t)); + return; +} + +/* +kadm_ser_in +unwrap the data stored in dat, process, and return it. +*/ +int +kadm_ser_in(u_char **dat, int *dat_len) +{ + u_char *in_st; /* pointer into the sent packet */ + int in_len,retc; /* where in packet we are, for + returns */ + u_int32_t r_len; /* length of the actual packet */ + KTEXT_ST authent; /* the authenticator */ + AUTH_DAT ad; /* who is this, klink */ + u_int32_t ncksum; /* checksum of encrypted data */ + des_key_schedule sess_sched; /* our schedule */ + MSG_DAT msg_st; + u_char *retdat, *tmpdat; + int retval, retlen; + + if (strncmp(KADM_VERSTR, (char *)*dat, KADM_VERSIZE)) { + errpkt(dat, dat_len, KADM_BAD_VER); + return KADM_BAD_VER; + } + in_len = KADM_VERSIZE; + /* get the length */ + if ((retc = stv_long(*dat, &r_len, in_len, *dat_len)) < 0) + return KADM_LENGTH_ERROR; + in_len += retc; + authent.length = *dat_len - r_len - KADM_VERSIZE - sizeof(u_int32_t); + bcopy((char *)(*dat) + in_len, (char *)authent.dat, authent.length); + authent.mbz = 0; + /* service key should be set before here */ + if ((retc = krb_rd_req(&authent, server_parm.sname, server_parm.sinst, + server_parm.recv_addr.sin_addr.s_addr, &ad, (char *)0))) + { + errpkt(dat, dat_len,retc + krb_err_base); + return retc + krb_err_base; + } + +#define clr_cli_secrets() {bzero((char *)sess_sched, sizeof(sess_sched)); bzero((char *)ad.session, sizeof(ad.session));} + + in_st = *dat + *dat_len - r_len; +#ifdef NOENCRYPTION + ncksum = 0; +#else + ncksum = des_quad_cksum((des_cblock *)in_st, (des_cblock *)0, (long) r_len, 0, &ad.session); +#endif + if (ncksum!=ad.checksum) { /* yow, are we correct yet */ + clr_cli_secrets(); + errpkt(dat, dat_len,KADM_BAD_CHK); + return KADM_BAD_CHK; + } +#ifdef NOENCRYPTION + bzero(sess_sched, sizeof(sess_sched)); +#else + des_key_sched(&ad.session, sess_sched); +#endif + if ((retc = (int) krb_rd_priv(in_st, r_len, sess_sched, &ad.session, + &server_parm.recv_addr, + &server_parm.admin_addr, &msg_st))) { + clr_cli_secrets(); + errpkt(dat, dat_len,retc + krb_err_base); + return retc + krb_err_base; + } + switch (msg_st.app_data[0]) { + case CHANGE_PW: + retval = kadm_ser_cpw(msg_st.app_data+1,(int) msg_st.app_length,&ad, + &retdat, &retlen); + break; + case ADD_ENT: + retval = kadm_ser_add(msg_st.app_data+1,(int) msg_st.app_length,&ad, + &retdat, &retlen); + break; + case GET_ENT: + retval = kadm_ser_get(msg_st.app_data+1,(int) msg_st.app_length,&ad, + &retdat, &retlen); + break; + case MOD_ENT: + retval = kadm_ser_mod(msg_st.app_data+1,(int) msg_st.app_length,&ad, + &retdat, &retlen); + break; + default: + clr_cli_secrets(); + errpkt(dat, dat_len, KADM_NO_OPCODE); + return KADM_NO_OPCODE; + } + /* Now seal the response back into a priv msg */ + free((char *)*dat); + tmpdat = (u_char *) malloc((unsigned)(retlen + KADM_VERSIZE + + sizeof(u_int32_t))); + (void) strncpy((char *)tmpdat, KADM_VERSTR, KADM_VERSIZE); + retval = htonl((u_int32_t)retval); + bcopy((char *)&retval, (char *)tmpdat + KADM_VERSIZE, sizeof(u_int32_t)); + if (retlen) { + bcopy((char *)retdat, (char *)tmpdat + KADM_VERSIZE + sizeof(u_int32_t), + retlen); + free((char *)retdat); + } + /* slop for mk_priv stuff */ + *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE + + sizeof(u_int32_t) + 200)); + if ((*dat_len = krb_mk_priv(tmpdat, *dat, + (u_int32_t) (retlen + KADM_VERSIZE + + sizeof(u_int32_t)), + sess_sched, + &ad.session, &server_parm.admin_addr, + &server_parm.recv_addr)) < 0) { + clr_cli_secrets(); + errpkt(dat, dat_len, KADM_NO_ENCRYPT); + return KADM_NO_ENCRYPT; + } + clr_cli_secrets(); + return KADM_SUCCESS; +} diff --git a/kerberosIV/kadmind/kadm_server.c b/kerberosIV/kadmind/kadm_server.c new file mode 100644 index 00000000000..7412b607c06 --- /dev/null +++ b/kerberosIV/kadmind/kadm_server.c @@ -0,0 +1,154 @@ +/* $Id: kadm_server.c,v 1.1 1995/12/14 06:52:48 tholo Exp $ */ + +/*- + * Copyright (C) 1989 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America is assumed + * to 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. + */ + +/* + * Kerberos administration server-side subroutines + */ + +#include <kadm_locl.h> + +/* +kadm_ser_cpw - the server side of the change_password routine + recieves : KTEXT, {key} + returns : CKSUM, RETCODE + acl : caller can change only own password + +Replaces the password (i.e. des key) of the caller with that specified in key. +Returns no actual data from the master server, since this is called by a user +*/ +int +kadm_ser_cpw(u_char *dat, int len, AUTH_DAT *ad, u_char **datout, int *outlen) +{ + u_int32_t keylow, keyhigh; + des_cblock newkey; + int stvlen; + + /* take key off the stream, and change the database */ + + if ((stvlen = stv_long(dat, &keyhigh, 0, len)) < 0) + return(KADM_LENGTH_ERROR); + if (stv_long(dat, &keylow, stvlen, len) < 0) + return(KADM_LENGTH_ERROR); + + keylow = ntohl(keylow); + keyhigh = ntohl(keyhigh); + bcopy((char *)&keyhigh, (char *)(((int32_t *)newkey) + 1), 4); + bcopy((char *)&keylow, (char *)newkey, 4); + *datout = 0; + *outlen = 0; + + return(kadm_change(ad->pname, ad->pinst, ad->prealm, newkey)); +} + +/* +kadm_ser_add - the server side of the add_entry routine + recieves : KTEXT, {values} + returns : CKSUM, RETCODE, {values} + acl : su, sms (as alloc) + +Adds and entry containing values to the database +returns the values of the entry, so if you leave certain fields blank you will + be able to determine the default values they are set to +*/ +int +kadm_ser_add(u_char *dat, int len, AUTH_DAT *ad, u_char **datout, int *outlen) +{ + Kadm_vals values, retvals; + long status; + + if ((status = stream_to_vals(dat, &values, len)) < 0) + return(KADM_LENGTH_ERROR); + if ((status = kadm_add_entry(ad->pname, ad->pinst, ad->prealm, + &values, &retvals)) == KADM_DATA) { + *outlen = vals_to_stream(&retvals,datout); + return KADM_SUCCESS; + } else { + *outlen = 0; + return status; + } +} + +/* +kadm_ser_mod - the server side of the mod_entry routine + recieves : KTEXT, {values, values} + returns : CKSUM, RETCODE, {values} + acl : su, sms (as register or dealloc) + +Modifies all entries corresponding to the first values so they match the + second values. +returns the values for the changed entries +*/ +int +kadm_ser_mod(u_char *dat, int len, AUTH_DAT *ad, u_char **datout, int *outlen) +{ + Kadm_vals vals1, vals2, retvals; + int wh; + long status; + + if ((wh = stream_to_vals(dat, &vals1, len)) < 0) + return KADM_LENGTH_ERROR; + if ((status = stream_to_vals(dat+wh,&vals2, len-wh)) < 0) + return KADM_LENGTH_ERROR; + if ((status = kadm_mod_entry(ad->pname, ad->pinst, ad->prealm, &vals1, + &vals2, &retvals)) == KADM_DATA) { + *outlen = vals_to_stream(&retvals,datout); + return KADM_SUCCESS; + } else { + *outlen = 0; + return status; + } +} + +/* +kadm_ser_get + recieves : KTEXT, {values, flags} + returns : CKSUM, RETCODE, {count, values, values, values} + acl : su + +gets the fields requested by flags from all entries matching values +returns this data for each matching recipient, after a count of how many such + matches there were +*/ +int +kadm_ser_get(u_char *dat, int len, AUTH_DAT *ad, u_char **datout, int *outlen) +{ + Kadm_vals values, retvals; + u_char fl[FLDSZ]; + int loop,wh; + long status; + + if ((wh = stream_to_vals(dat, &values, len)) < 0) + return KADM_LENGTH_ERROR; + if (wh + FLDSZ > len) + return KADM_LENGTH_ERROR; + for (loop=FLDSZ-1; loop>=0; loop--) + fl[loop] = dat[wh++]; + if ((status = kadm_get_entry(ad->pname, ad->pinst, ad->prealm, + &values, fl, &retvals)) == KADM_DATA) { + *outlen = vals_to_stream(&retvals,datout); + return KADM_SUCCESS; + } else { + *outlen = 0; + return status; + } +} + diff --git a/kerberosIV/kadmind/kadmind.8 b/kerberosIV/kadmind/kadmind.8 new file mode 100644 index 00000000000..fbb6e4944e6 --- /dev/null +++ b/kerberosIV/kadmind/kadmind.8 @@ -0,0 +1,126 @@ +.\" Copyright 1987, 1988, 1989 by the Student Information Processing Board +.\" of the Massachusetts Institute of Technology +.\" +.\" 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 names of M.I.T. and the M.I.T. S.I.P.B. not be +.\" used in advertising or publicity pertaining to distribution +.\" of the software without specific, written prior permission. +.\" M.I.T. and the M.I.T. S.I.P.B. make no representations about +.\" the suitability of this software for any purpose. It is +.\" provided "as is" without express or implied warranty. +.\" +.\" $Id: kadmind.8,v 1.1 1995/12/14 06:52:49 tholo Exp $ +.TH KADMIND 8 "Kerberos Version 4.0" "MIT Project Athena" +.SH NAME +kadmind \- Kerberos database administration daemon +.SH SYNOPSIS +.B kadmind +[ +.B \-n +] [ +.B \-h +] [ +.B \-r realm +] [ +.B \-f filename +] [ +.B \-d dbname +] [ +.B \-a acldir +] +.SH DESCRIPTION +.I kadmind +is the network database server for the Kerberos password-changing and +administration tools. +.PP +Upon execution, it prompts the user to enter the master key string for +the database. +.PP +If the +.B \-n +option is specified, the master key is instead fetched from the master +key cache file. +.PP +If the +.B \-r +.I realm +option is specified, the admin server will pretend that its +local realm is +.I realm +instead of the actual local realm of the host it is running on. +This makes it possible to run a server for a foreign kerberos +realm. +.PP +If the +.B \-f +.I filename +option is specified, then that file is used to hold the log information +instead of the default. +.PP +If the +.B \-d +.I dbname +option is specified, then that file is used as the database name instead +of the default. +.PP +If the +.B \-a +.I acldir +option is specified, then +.I acldir +is used as the directory in which to search for access control lists +instead of the default. +.PP +If the +.B \-h +option is specified, +.I kadmind +prints out a short summary of the permissible control arguments, and +then exits. +.PP +When performing requests on behalf of clients, +.I kadmind +checks access control lists (ACLs) to determine the authorization of the client +to perform the requested action. +Currently three distinct access types are supported: +.TP 1i +Addition +(.add ACL file). If a principal is on this list, it may add new +principals to the database. +.TP +Retrieval +(.get ACL file). If a principal is on this list, it may retrieve +database entries. NOTE: A principal's private key is never returned by +the get functions. +.TP +Modification +(.mod ACL file). If a principal is on this list, it may modify entries +in the database. +.PP +A principal is always granted authorization to change its own password. +.SH FILES +.TP 20n +/kerberos/admin_server.syslog +Default log file. +.TP +/kerberos +Default access control list directory. +.TP +admin_acl.{add,get,mod} +Access control list files (within the directory) +.TP +/kerberos/principal.pag, /kerberos/principal.dir +Default DBM files containing database +.TP +/.k +Master key cache file. +.SH "SEE ALSO" +kerberos(1), kpasswd(1), kadmin(8), acl_check(3) +.SH AUTHORS +Douglas A. Church, MIT Project Athena +.br +John T. Kohl, Project Athena/Digital Equipment Corporation |