/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include #include #include #include #include #include #define TKTTIMELEFT 60*10 /* ten minutes */ static int verify_creds() { krb5_context kcontext; krb5_ccache ccache; krb5_error_code kres; kres = krb5_init_context(&kcontext); if( kres == 0 ) { kres = krb5_cc_default( kcontext, &ccache ); if( kres == 0 ) { krb5_principal user_princ; kres = krb5_cc_get_principal( kcontext, ccache, &user_princ ); if( kres == 0 ) krb5_free_principal( kcontext, user_princ ); krb5_cc_close( kcontext, ccache ); } krb5_free_context(kcontext); } return kres; } static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions ) { krb5_preauthtype preauth[] = { KRB5_PADATA_ENC_TIMESTAMP }; krb5_enctype etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC}; krb5_get_init_creds_opt_set_address_list(outOptions, NULL); krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) ); krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) ); } typedef void * kbrccache_t; #define CCACHE_PREFIX_DEFAULT "MEMORY:C_" static kbrccache_t userinitcontext( const char * user, const char * domain, const char * passwd, const char * cachename, int initialize, int * outError ) { krb5_context kcontext = 0; krb5_ccache kcache = 0; krb5_creds kcreds; krb5_principal kme = 0; krb5_error_code kres; char * pPass = strdup( passwd ); char * pName = NULL; char * pCacheName = NULL; int numCreds = 0; memset( &kcreds, 0, sizeof(kcreds) ); kres = krb5_init_context( &kcontext ); if( kres ) goto return_error; if( domain ) kres = krb5_build_principal( kcontext, &kme, strlen(domain), domain, user, (char *) 0 ); else kres = krb5_parse_name( kcontext, user, &kme ); if( kres ) goto fail; krb5_unparse_name( kcontext, kme, &pName ); if( cachename ) { if (asprintf(&pCacheName, "%s%s", cachename, pName) < 0) { kres = KRB5_CC_NOMEM; goto fail; } kres = krb5_cc_resolve( kcontext, pCacheName, &kcache ); if( kres ) { kres = krb5_cc_resolve( kcontext, CCACHE_PREFIX_DEFAULT, &kcache ); if( kres == 0 ) pCacheName = strdup(CCACHE_PREFIX_DEFAULT); } } else { kres = krb5_cc_default( kcontext, &kcache ); pCacheName = strdup( krb5_cc_get_name( kcontext, kcache ) ); } if( kres ) { krb5_free_context(kcontext); goto return_error; } if( initialize ) krb5_cc_initialize( kcontext, kcache, kme ); if( kres == 0 && user && passwd ) { long timeneeded = time(0L) +TKTTIMELEFT; int have_credentials = 0; krb5_cc_cursor cc_curs = NULL; numCreds = 0; if( (kres=krb5_cc_start_seq_get(kcontext, kcache, &cc_curs)) >= 0 ) { while( (kres=krb5_cc_next_cred(kcontext, kcache, &cc_curs, &kcreds))== 0) { numCreds++; if( krb5_principal_compare( kcontext, kme, kcreds.client ) ) { if( kcreds.ticket_flags & TKT_FLG_INITIAL && kcreds.times.endtime>timeneeded ) have_credentials = 1; } krb5_free_cred_contents( kcontext, &kcreds ); if( have_credentials ) break; } krb5_cc_end_seq_get( kcontext, kcache, &cc_curs ); } else { const char * errmsg = error_message(kres); fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg ); } if( kres != 0 || have_credentials == 0 ) { krb5_get_init_creds_opt *options = NULL; kres = krb5_get_init_creds_opt_alloc(kcontext, &options); if ( kres == 0 ) { get_init_creds_opt_init(options); /* ** no valid credentials - get new ones */ kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass, NULL /*prompter*/, NULL /*data*/, 0 /*starttime*/, 0 /*in_tkt_service*/, options /*options*/ ); } if( kres == 0 ) { if( numCreds <= 0 ) kres = krb5_cc_initialize( kcontext, kcache, kme ); if( kres == 0 ) kres = krb5_cc_store_cred( kcontext, kcache, &kcreds ); if( kres == 0 ) have_credentials = 1; } krb5_get_init_creds_opt_free(kcontext, options); } #ifdef NOTUSED if( have_credentials ) { int mstat; kres = gss_krb5_ccache_name( &mstat, pCacheName, NULL ); if( getenv( ENV_DEBUG_LDAPKERB ) ) fprintf( stderr, "gss credentials cache set to %s(%d)\n", pCacheName, kres ); } #endif krb5_cc_close( kcontext, kcache ); } fail: if( kres ) { const char * errmsg = error_message(kres); fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg ); } krb5_free_principal( kcontext, kme ); krb5_free_cred_contents( kcontext, &kcreds ); if( pName ) free( pName ); free(pPass); krb5_free_context(kcontext); return_error: if( kres ) { if( pCacheName ) { free(pCacheName); pCacheName = NULL; } } if( outError ) *outError = kres; return pCacheName; } static int init_creds() { char user[512]; char * password = NULL; int result; user[0] = 0; result = -1; for(;;) { while( user[0] == 0 ) { int userlen; printf( "Username: "); fflush(stdout); if( fgets( user, sizeof(user), stdin ) == NULL ) return -1; userlen = strlen( user); if( userlen < 2 ) continue; user[userlen-1] = 0; /* get rid of the newline */ break; } { kbrccache_t usercontext; password = getpass( "Password: "); if( ! password ) return -1; result = 0; usercontext = userinitcontext( user, NULL, password, NULL, 1, &result ); if( usercontext ) break; } } return result; } int main( int argc, char ** argv ) { char * new_password = NULL; char * new_password2; krb5_context kcontext; krb5_error_code kerr; krb5_principal target_principal; if( argc < 2 ) { fprintf( stderr, "Usage: setpass user@REALM\n"); exit(1); } /* ** verify credentials - */ if( verify_creds() ) init_creds(); if( verify_creds() ) { fprintf( stderr, "No user credentials available\n"); exit(1); } /* ** check the principal name - */ krb5_init_context(&kcontext); kerr = krb5_parse_name( kcontext, argv[1], &target_principal ); { char * pname = NULL; kerr = krb5_unparse_name( kcontext, target_principal, &pname ); printf( "Changing password for %s:\n", pname); fflush( stdout ); free( pname ); } /* ** get the new password - */ while( !new_password ) { new_password = getpass("Enter new password: "); new_password2 = getpass("Verify new password: "); if( strcmp( new_password, new_password2 ) ) { printf("Passwords do not match\n"); free( new_password ); free( new_password2 ); continue; } } /* ** change the password - */ { int pw_result; krb5_ccache ccache; krb5_data pw_res_string, res_string; kerr = krb5_cc_default( kcontext, &ccache ); if( kerr == 0 ) { kerr = krb5_set_password_using_ccache(kcontext, ccache, new_password, target_principal, &pw_result, &pw_res_string, &res_string ); if( kerr ) fprintf( stderr, "Failed: %s\n", error_message(kerr) ); else { if( pw_result ) { fprintf( stderr, "Failed(%d)", pw_result ); if( pw_res_string.length > 0 ) fprintf( stderr, ": %s", pw_res_string.data); if( res_string.length > 0 ) fprintf( stderr, " %s", res_string.data); fprintf( stderr, "\n"); } } } } return(0); }