/* * kadmin/v4server/kadm_ser_wrap.c * * Copyright 1988 by the Massachusetts Institute of Technology. * * For copying and distribution information, please see the file * . * * Kerberos administration server-side support functions */ #include /* kadm_ser_wrap.c unwraps wrapped packets and calls the appropriate server subroutine */ #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "kadm_server.h" #include #include #include #include #ifdef OVSEC_KADM #include extern void *ovsec_handle; #endif Kadm_Server server_parm; /* kadm_ser_init set up the server_parm structure */ #ifdef OVSEC_KADM kadm_ser_init(inter, realm, params) int inter; /* interactive or from file */ char realm[]; kadm5_config_params *params; #else kadm_ser_init(inter, realm) int inter; /* interactive or from file */ char realm[]; #endif { struct servent *sep; struct hostent *hp; char hostname[MAXHOSTNAMELEN]; char *mkey_name; krb5_error_code retval; int numfound = 1; krb5_boolean more; krb5_db_entry master_entry; krb5_key_data *kdatap; 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); if (krb5_build_principal(kadm_context, &server_parm.sprinc, strlen(realm), realm, PWSERV_NAME, KRB_MASTER, 0)) return KADM_NO_MAST; server_parm.admin_fd = -1; /* setting up the addrs */ if ((sep = getservbyname(KADM_SNAME, "tcp")) == NULL) return KADM_NO_SERV; memset((char *)&server_parm.admin_addr, 0,sizeof(server_parm.admin_addr)); server_parm.admin_addr.sin_family = AF_INET; if ((hp = gethostbyname(hostname)) == NULL) return KADM_NO_HOSTNAME; memcpy((char *) &server_parm.admin_addr.sin_addr.s_addr, hp->h_addr, hp->h_length); server_parm.admin_addr.sin_port = sep->s_port; /* setting up the database */ mkey_name = KRB5_KDB_M_NAME; #ifdef OVSEC_KADM server_parm.master_keyblock.enctype = params->enctype; krb5_use_enctype(kadm_context, &server_parm.master_encblock, server_parm.master_keyblock.enctype); #else if (inter == 1) { server_parm.master_keyblock.enctype = ENCTYPE_DES_CBC_MD5; krb5_use_enctype(kadm_context, &server_parm.master_encblock, server_parm.master_keyblock.enctype); } else server_parm.master_keyblock.enctype = ENCTYPE_UNKNOWN; #endif retval = krb5_db_setup_mkey_name(kadm_context, mkey_name, realm, (char **) 0, &server_parm.master_princ); if (retval) return KADM_NO_MAST; krb5_db_fetch_mkey(kadm_context, server_parm.master_princ, &server_parm.master_encblock, (inter == 1), FALSE, #ifdef OVSEC_KADM params->stash_file, #else (char *) NULL, #endif NULL, &server_parm.master_keyblock); if (retval) return KADM_NO_MAST; retval = krb5_db_verify_master_key(kadm_context, server_parm.master_princ, &server_parm.master_keyblock, &server_parm.master_encblock); if (retval) return KADM_NO_VERI; retval = krb5_process_key(kadm_context, &server_parm.master_encblock, &server_parm.master_keyblock); if (retval) return KADM_NO_VERI; retval = krb5_db_get_principal(kadm_context, server_parm.master_princ, &master_entry, &numfound, &more); if (retval || more || !numfound) return KADM_NO_VERI; retval = krb5_dbe_find_enctype(kadm_context, &master_entry, -1, -1, -1, &kdatap); if (retval) return KRB5_PROG_KEYTYPE_NOSUPP; server_parm.max_life = master_entry.max_life; server_parm.max_rlife = master_entry.max_renewable_life; server_parm.expiration = master_entry.expiration; server_parm.mkvno = kdatap->key_data_kvno; /* don't set flags, as master has some extra restrictions (??? quoted from kdb_edit.c) */ krb5_db_free_principal(kadm_context, &master_entry, numfound); return KADM_SUCCESS; } static void errpkt(dat, dat_len, code) u_char **dat; int *dat_len; int code; { krb5_ui_4 retcode; char *pdat; free((char *)*dat); /* free up req */ *dat_len = KADM_VERSIZE + sizeof(krb5_ui_4); *dat = (u_char *) malloc((unsigned)*dat_len); if (!(*dat)) { syslog(LOG_ERR, "malloc(%d) returned null while in errpkt!", *dat_len); abort(); } pdat = (char *) *dat; retcode = htonl((krb5_ui_4) code); (void) strncpy(pdat, KADM_ULOSE, KADM_VERSIZE); memcpy(&pdat[KADM_VERSIZE], (char *)&retcode, sizeof(krb5_ui_4)); return; } /* kadm_ser_in unwrap the data stored in dat, process, and return it. */ kadm_ser_in(dat,dat_len) 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 */ krb5_ui_4 r_len; /* length of the actual packet */ KTEXT_ST authent; /* the authenticator */ AUTH_DAT ad; /* who is this, klink */ krb5_ui_4 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(krb5_ui_4); memcpy((char *)authent.dat, (char *)(*dat) + in_len, 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() {memset((char *)sess_sched, 0, sizeof(sess_sched)); memset((char *)ad.session, 0, sizeof(ad.session));} in_st = *dat + *dat_len - r_len; #ifdef NOENCRYPTION ncksum = 0; #else ncksum = quad_cksum(in_st, (krb5_ui_4 *)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 memset(sess_sched, 0, 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; #ifndef OVSEC_KADM case ADD_ENT: retval = kadm_ser_add(msg_st.app_data+1,(int) msg_st.app_length,&ad, &retdat, &retlen); break; case DEL_ENT: retval = kadm_ser_del(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; case CHECK_PW: retval = kadm_ser_ckpw(msg_st.app_data+1,(int) msg_st.app_length,&ad, &retdat, &retlen); break; case CHG_STAB: retval = kadm_ser_stab(msg_st.app_data+1,(int) msg_st.app_length,&ad, &retdat, &retlen); break; #endif /* OVSEC_KADM */ 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(krb5_ui_4))); if (!tmpdat) { clr_cli_secrets(); syslog(LOG_ERR, "malloc(%d) returned null while in kadm_ser_in!", retlen + KADM_VERSIZE + sizeof(krb5_ui_4)); errpkt(dat, dat_len, KADM_NOMEM); return KADM_NOMEM; } (void) strncpy((char *)tmpdat, KADM_VERSTR, KADM_VERSIZE); retval = htonl((krb5_ui_4)retval); memcpy((char *)tmpdat + KADM_VERSIZE, (char *)&retval, sizeof(krb5_ui_4)); if (retlen) { memcpy((char *)tmpdat + KADM_VERSIZE + sizeof(krb5_ui_4), (char *)retdat, retlen); free((char *)retdat); } /* slop for mk_priv stuff */ *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE + sizeof(krb5_ui_4) + 200)); if ((*dat_len = krb_mk_priv(tmpdat, *dat, (u_long) (retlen + KADM_VERSIZE + sizeof(krb5_ui_4)), 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; }