Build ksetpw, a client for the Microsoft set password protocol. Not
authorSam Hartman <hartmans@mit.edu>
Fri, 25 Apr 2003 18:50:04 +0000 (18:50 +0000)
committerSam Hartman <hartmans@mit.edu>
Fri, 25 Apr 2003 18:50:04 +0000 (18:50 +0000)
of release quality yet, so don't actually install.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15374 dc483132-0cff-0310-8789-dd5450dbe970

src/clients/kpasswd/ChangeLog
src/clients/kpasswd/Makefile.in
src/clients/kpasswd/ksetpwd.c [new file with mode: 0644]

index 1019de41c9f5aada7fd1a17fca7f6af7e6172cc1..ac31dda99eaa6168b7850a4e150e4fbad9c61dd7 100644 (file)
@@ -1,3 +1,9 @@
+2003-04-25  Sam Hartman  <hartmans@mit.edu>
+
+       * Makefile.in :   Add rule to build ksetpw, a set/change password
+       client for the Microsoft protocol.  We do not install this program
+       by default because it is not of release quality yet.
+
 2003-02-25  Tom Yu  <tlyu@mit.edu>
 
        * kpasswd.c (main): Don't pass a NULL pointer to printf().
index 89c1340285b8878c3a4f5e6d042259399a2fbfde..3f6394342ea95bb0e3d4f2331d2728ba789739eb 100644 (file)
@@ -8,12 +8,16 @@ PROG_RPATH=$(KRB5_LIBDIR)
 kpasswd: kpasswd.o $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o kpasswd kpasswd.o $(KRB5_BASE_LIBS)
 
+ksetpwd: ksetpwd.o $(KRB5_BASE_DEPLIBS)
+       $(CC_LINK) -o ksetpwd ksetpwd.o $(KRB5_BASE_LIBS)
+
 kpasswd.o:     $(srcdir)/kpasswd.c
+ksetpwd.o:     $(srcdir)/ksetpwd.c
 
-all-unix:: kpasswd
+all-unix:: kpasswd ksetpwd
 
 clean-unix::
-       $(RM) kpasswd.o kpasswd
+       $(RM) kpasswd.o kpasswd ksetpwd.o ksetpwd
 
 install-all install-kdc install-server install-client install-unix::
        $(INSTALL_PROGRAM) kpasswd $(DESTDIR)$(CLIENT_BINDIR)/`echo kpasswd|sed '$(transform)'`
diff --git a/src/clients/kpasswd/ksetpwd.c b/src/clients/kpasswd/ksetpwd.c
new file mode 100644 (file)
index 0000000..7b72b36
--- /dev/null
@@ -0,0 +1,312 @@
+#include <krb5.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define TKTTIMELEFT     60*10   /* ten minutes */
+
+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;
+}
+
+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};
+    memset( outOptions, 0, sizeof(*outOptions) );
+    krb5_get_init_creds_opt_init(outOptions);
+    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_"
+
+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, 0 );
+       else
+               kres = krb5_parse_name( kcontext, user, &kme );
+       if( kres )
+               goto fail;
+       krb5_unparse_name( kcontext, kme, &pName );
+       if( cachename )
+       {
+               pCacheName = malloc( strlen( pName ) + strlen( cachename ) + 1 );
+               if( pCacheName == NULL )
+               {
+                       kres = KRB5_CC_NOMEM;
+                       goto fail;
+               }
+               strcpy( pCacheName, cachename );
+               strcat( pCacheName, pName );
+               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;
+                       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;
+                       }
+               }
+#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;
+}
+
+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_ccache             ccache;
+       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 -
+*/
+       fprintf( stderr, "the password is %s\n", new_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");
+                               }
+                       }
+               }
+       }
+}