[6450] in Kerberos
Code for moving to kerberos
daemon@ATHENA.MIT.EDU (Emil Sit)
Sat Jan 6 21:42:22 1996
To: kerberos@MIT.EDU
Date: 7 Jan 1996 02:35:51 GMT
From: sit@ (Emil Sit)
In article <199512240320.WAA13253@toxicwaste.media.mit.edu>,
Derek Atkins <warlord@MIT.EDU> wrote:
>thing -- ask a user for a password, compare it to the passwd entry in
>YP, and then add the password to kerberos. This, too, would be fairly
>simple to write but I don't have code for you...
>
>Perhaps someone else has code to share?
I am converting an AIX /etc/security/passwd single machine system to
a CNS (ie krb4 based) multiple machine system. One of the (many) things
I have to do is get their crypt()'ed passwords into the kdc. I wrote up
this code to do it. It does basically what derek suggested. There are
very likely some non-secure or non-standard things done in the code, since
I have never used the kerberos API before and never done any security
related coding.
The basic outline of the code is pretty simple. It checks to see if a
kerberos instance of the person exists, and exits if it does. If not,
it prompts for a password (using getpass() ... this may not port well)
and checks against /etc/security/passwd entry (AIXism). If it matches,
it does a password check on kdc side to see if it is a blatantly bad
pw. If that's ok, it will add the principal and exit.
You'll have to create a register.<hostname> principal, stick its key in
your srvtab or (krb-srvtab), and also put "register.*" in your
admin_acl.add.
I compile with:
gcc -Wall -g -c -I/usr/kerberos/include reg.c
gcc -Wall -g -o reg reg.o -L/usr/kerberos/lib -ls -lkadm -lkrb -ldes -lcom_err
It seems to be working ok for me so far on my limited testing, but I would
appreciate if a more knowledgable person would comment on it.
Thanks,
Emil
-=-=-Cut Here-=-=-=-
/*
* Verifies existing user on local machine and if they
* exist, add them with their password
*
* Copyright (C) 1996 by the Bronx High School of Science
*
* Bronx Science makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* $Id: reg.c,v 1.6 1996/01/05 18:01:43 esit Exp esit $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/nameser.h> /* For MAXDNAME */
/*
* This program must have appropriate permissions to obtain the
* encrypted password. On AIX, this is suid root.
*/
#include <pwd.h> /* /etc/passwd stuff */
#include <userpw.h> /* /etc/security/passwd stuff */
#include <unistd.h>
/*
* We use a register.hostname key in KEYFILE (usu /etc/krb-srvtab)
* so we need to be suid root for that too. Alternately,
* you can store it in some other file and compile that in.
* Maybe one day this will be a command line param.
*/
#include <kadm.h>
#include <kadm_err.h>
#include <krb_err.h>
#include <com_err.h>
/* My error codes */
#define ERR_USER 1
#define ERR_KRB 2
#define ERR_SYS 3
#define PE_NO 0
#define PE_YES 1
#define PE_UNSURE 2
/*
* function declarations
*/
int chk_good_pw( des_cblock *key );
int add_principal(char *name, char *instance, char *realm, des_cblock *key );
int princ_exists( char *name, char *instance, char *realm);
int init_principal( char *name, char *instance, char *realm);
void leave( char *str, int x );
char progname[MAXPATHLEN];
/* sigh. Make this global so that we can wipe it in an exit procedure */
char *pword = NULL;
int main( int argc, char *argv[] )
{
char myname[ANAME_SZ];
char myinst[INST_SZ];
char myrealm[REALM_SZ];
char tktstring[MAXPATHLEN];
char host[MAXDNAME+1];
char hostinst[INST_SZ];
char *cpword = NULL;
struct userpw *upw_chk;
des_cblock newkey;
int status;
/* Initializations */
memset( myname, 0, sizeof(myname) ); /* new princ */
memset( myinst, 0, sizeof(myinst) );
memset( myrealm, 0, sizeof(myrealm) );
(void) sprintf( tktstring, "/tmp/tkt_ank_%d", getpid() );
krb_set_tkt_string( tktstring );
(void) strcpy( progname, argv[0] ); /* com_err */
if ( gethostname( host, MAXDNAME ) < 0 ) { /* svc tickets */
leave( "Error: Unable to get hostname. Try from a different machine.\n", ERR_SYS );
}
(void) strncpy( hostinst, krb_get_phost(host), INST_SZ );
/* Do we need to to continue? */
(void) init_principal( myname, myinst, myrealm );
#ifndef DEBUG
printf( "Checking for %s.%s@%s...", myname, myinst, myrealm );
if ( princ_exists( myname, myinst, myrealm ) == PE_NO ) {
printf( "Not found. Continuing...\n" );
} else {
printf( "Found. Exitting...\n" );
exit( 0 );
}
#endif /* NOT DEBUG */
/* Begin setup */
status = kadm_init_link( PWSERV_NAME, KRB_MASTER, myrealm );
if ( status != KSUCCESS ) {
com_err( progname, status, "while initializing." );
exit( ERR_KRB );
}
/* Get tickets to check password. */
status = krb_get_svc_in_tkt("register", hostinst, myrealm, PWSERV_NAME,
KRB_MASTER, 1, KEYFILE );
if ( status != KSUCCESS ) {
/* According to src, get_svc_in_tkt errs need to be offset
* by krb_err_base if using com_err. This does the same.
*/
fprintf( stderr, "Kerberos error: %s\n", krb_get_err_text(status) );
leave( NULL, ERR_KRB );
}
printf( "Please enter your password. We require this to finish setting up a new\n" );
printf( "security system. Users who do not complete this process will *NOT* be\n" );
printf( "allowed to use ANY of the Internet machines at BSC starting March 1.\n");
pword = getpass( "Your current password: " );
if ( pword == NULL ) {
leave( "Error reading password.", ERR_USER );
}
if ( strlen(pword) == 0 ) {
leave( "You have an empty password! I don't trust you...", ERR_USER );
}
/* Convert stuff so we don't need cleartext pw anymore */
(void) des_string_to_key( pword, newkey );
upw_chk = getuserpw( myname );
if ( upw_chk == NULL ) {
leave( "Unable to access password file.", ERR_SYS );
}
cpword = crypt( pword, upw_chk->upw_passwd );
memset( pword, 0, sizeof(pword) );
/* strcmp returns non zero when strings are different */
/* We should probably prompt for password again. :) */
if ( strcmp( cpword, upw_chk->upw_passwd ) ) {
leave( "Incorrect password.", ERR_USER );
}
/* Check for good password; loop until we get one. */
status = chk_good_pw( &newkey );
while ( status == KADM_INSECURE_PW ) {
printf("Please choose another password.\n\n");
des_read_password( &newkey, "Password: ", 1 );
status = chk_good_pw( &newkey );
}
status = add_principal( myname, myinst, myrealm, &newkey );
if ( status != KADM_SUCCESS ) {
com_err(progname, status,
"while adding principal.");
}
(void) dest_tkt();
return 0;
}
/* Talk to kdc and see if it is a good key */
int chk_good_pw( des_cblock *key )
{
int status;
char *ret_st;
status = kadm_check_pw( *key, NULL, (u_char **)&ret_st );
if (ret_st) {
printf("\n%s\n", ret_st);
free(ret_st);
}
if (status != KADM_SUCCESS) {
com_err(progname, status,
"while checking password.");
leave( NULL, ERR_KRB );
}
if (status == KADM_DB_INUSE) {
com_err(progname, 0, "Please try again later.");
leave( NULL, ERR_KRB );
}
return( status );
}
int add_principal(char *name, char *instance, char *realm, des_cblock *key )
{
Kadm_vals vals;
int status = KADM_SUCCESS;
bzero( (char *)vals.fields, sizeof(vals.fields) );
SET_FIELD( KADM_NAME, vals.fields );
SET_FIELD( KADM_INST, vals.fields );
SET_FIELD( KADM_DESKEY, vals.fields );
strcpy( vals.name, name );
strcpy( vals.instance, instance );
memcpy( (char *) &vals.key_low, (char *) key, sizeof(KRB_INT32) );
memcpy( (char *) &vals.key_high, (char *)(((KRB_INT32 *) key) + 1), sizeof(KRB_INT32) );
vals.key_low = htonl(vals.key_low);
vals.key_high = htonl(vals.key_high);
status = kadm_add(&vals);
return( status );
}
/* init_principal
* Takes blank name, inst, realm; sets them to current user.
* Checks for validity of user; returns if user is valid
*/
int init_principal(char *name, char *instance, char *realm)
{
int status;
uid_t userno;
struct passwd *upw;
userno = getuid();
if ( userno < 200 ) {
fprintf( stderr, "Error: uid < 200. Please consult the system administrators.\n" );
exit( ERR_USER );
}
upw = getpwuid( getuid() );
if ( upw != NULL ) {
(void) strcpy( name, upw->pw_name );
} else {
fprintf( stderr, "Error: you don't appear to be in the passwd file.\n" );
exit( ERR_USER );
}
if ( ( status = krb_get_lrealm( realm, 1 ) ) != KSUCCESS ) {
com_err( progname, status, "while getting local realm." );
exit( ERR_KRB );
}
return 0;
}
/* Snarfed from src/kadmin/get_srvtab.c from CNS krb4 95q1 */
int princ_exists(char *name, char *instance, char *realm)
{
int status;
status = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm, 1, "");
if ((status == KSUCCESS) || (status == INTK_BADPW))
return(PE_YES);
else if (status == KDC_PR_UNKNOWN)
return(PE_NO);
else
return(PE_UNSURE);
}
void leave( char *str, int x )
{
if (str)
(void) fprintf( stderr, "%s\n", str );
if (pword)
memset( pword, 0, sizeof(pword) );
(void) dest_tkt();
exit(x);
}
-=-=-Cut Here-=-=-=-
--
Emil Sit | E-mail: sit@mit.edu or esit@bxscience.edu
http://www.bxscience.edu/~esit/ | PGP Public key available on request