net ads password and net ads chostpass commands from Remus Koos
authorAndrew Tridgell <tridge@samba.org>
Thu, 20 Dec 2001 03:54:52 +0000 (03:54 +0000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 20 Dec 2001 03:54:52 +0000 (03:54 +0000)
(This used to be commit 412e79c448bf02e3097b5c14a36fe0172d8d2895)

source3/Makefile.in
source3/libads/kerberos.c
source3/libads/krb5_setpw.c
source3/libads/ldap.c
source3/nsswitch/.cvsignore
source3/tdb/.cvsignore
source3/utils/net_ads.c

index a713d61f36c5e151973763736615c5240651ac7b..3fa516b48cab42056dc528860afaaa896221e88e 100644 (file)
@@ -133,7 +133,7 @@ UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
 PARAM_OBJ = param/loadparm.o param/params.o dynconfig.o
 
 LIBADS_OBJ = libads/ldap.o libads/sasl.o libads/krb5_setpw.o libads/kerberos.o \
-            libads/ads_struct.o passdb/secrets.o 
+            libads/ads_struct.o passdb/secrets.o libads/util.o
 
 LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
             libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
index 8378442885e80d12929bb6065049eef4e1c3c4eb..aba22e023b28b0662811f9b969681f5dd3dbdc0a 100644 (file)
@@ -3,6 +3,8 @@
    Version 3.0
    kerberos utility library
    Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Remus Koos 2001
+   
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -27,8 +29,7 @@
   simulate a kinit, putting the tgt in the default cache location
   remus@snapserver.com
 */
-int kerberos_kinit_password(const char *principal, const char *password, 
-                           time_t real_time)
+int kerberos_kinit_password(const char *principal, const char *password)
 {
        krb5_context ctx;
        krb5_error_code code = 0;
@@ -44,10 +45,6 @@ int kerberos_kinit_password(const char *principal, const char *password,
        if ((code = krb5_init_context(&ctx)))
                return code;
        
-       if (real_time) {
-               krb5_set_real_time(ctx, real_time, 0);
-       }
-
        if ((code = krb5_cc_default(ctx, &cc))) {
                krb5_free_context(ctx);
                return code;
@@ -58,7 +55,7 @@ int kerberos_kinit_password(const char *principal, const char *password,
                return code;
        }
        
-       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, password, NULL, 
+       if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, (char*)password, NULL, 
                                                NULL, 0, NULL, NULL))) {
                krb5_free_principal(ctx, me);
                krb5_free_context(ctx);         
@@ -105,7 +102,7 @@ int ads_kinit_password(ADS_STRUCT *ads)
                asprintf(&ads->user_name, "HOST/%s", global_myname);
        }
        asprintf(&s, "%s@%s", ads->user_name, ads->realm);
-       ret = kerberos_kinit_password(s, ads->password, 0);
+       ret = kerberos_kinit_password(s, ads->password);
 
        if (ret) {
                DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
index b46a579263df56762764c7baba1a186c80f2cf3c..e15c22091d2d345f5dc16920a0feb91489db0bc7 100644 (file)
@@ -3,6 +3,7 @@
    Version 3.0
    krb5 set password implementation
    Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 /* This implements the Kerb password change protocol as specifed in
  * kerb-chg-password-02.txt
  */
-static DATA_BLOB encode_krb5_setpw(const char *hostname, 
-                                  const char *realm, const char *password)
+static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
 {
+        char* princ_part1 = NULL;
+       char* princ_part2 = NULL;
+       char* realm = NULL;
+       char* c;
+       char* princ;
+
        ASN1_DATA req;
        DATA_BLOB ret;
 
+
+       princ = strdup(principal);
+
+       if ((c = strchr(princ, '/')) == NULL) {
+           c = princ; 
+       } else {
+           *c = '\0';
+           c++;
+           princ_part1 = princ;
+       }
+
+       princ_part2 = c;
+
+       if ((c = strchr(c, '@')) != NULL) {
+           *c = '\0';
+           c++;
+           realm = c;
+       }
+
        memset(&req, 0, sizeof(req));
        
        asn1_push_tag(&req, ASN1_SEQUENCE(0));
@@ -54,8 +79,11 @@ static DATA_BLOB encode_krb5_setpw(const char *hostname,
 
        asn1_push_tag(&req, ASN1_CONTEXT(1));
        asn1_push_tag(&req, ASN1_SEQUENCE(0));
-       asn1_write_GeneralString(&req, "HOST");
-       asn1_write_GeneralString(&req, hostname);
+
+       if (princ_part1) 
+           asn1_write_GeneralString(&req, princ_part1);
+       
+       asn1_write_GeneralString(&req, princ_part2);
        asn1_pop_tag(&req);
        asn1_pop_tag(&req);
        asn1_pop_tag(&req);
@@ -69,14 +97,15 @@ static DATA_BLOB encode_krb5_setpw(const char *hostname,
        ret = data_blob(req.data, req.length);
        asn1_free(&req);
 
+       free(princ);
+
        return ret;
 }      
 
 static krb5_error_code build_setpw_request(krb5_context context,
                                           krb5_auth_context auth_context,
                                           krb5_data *ap_req,
-                                          const char *hostname,
-                                          const char *realm,
+                                          const char *princ,
                                           const char *passwd,
                                           krb5_data *packet)
 {
@@ -95,13 +124,16 @@ static krb5_error_code build_setpw_request(krb5_context context,
                return ret;
        }
 
-       setpw = encode_krb5_setpw(hostname, realm, passwd);
+       setpw = encode_krb5_setpw(princ, passwd);
 
        encoded_setpw.data = setpw.data;
        encoded_setpw.length = setpw.length;
 
        ret = krb5_mk_priv(context, auth_context,
                           &encoded_setpw, &cipherpw, &replay);
+       
+       data_blob_free(&setpw);         /*from 'encode_krb5_setpw(...)' */
+       
        if (ret) {
                DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
                return ret;
@@ -118,6 +150,8 @@ static krb5_error_code build_setpw_request(krb5_context context,
        packet->length = PTR_DIFF(p,packet->data);
        RSSVAL(packet->data, 0, packet->length);
        
+       free(cipherpw.data);    /* from 'krb5_mk_priv(...)' */
+
        return 0;
 }
 
@@ -196,6 +230,7 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
        }
 
        if (clearresult.length < 2) {
+               free(clearresult.data);
                ret = KRB5KRB_AP_ERR_MODIFIED;
                return KRB5KRB_AP_ERR_MODIFIED;
        }
@@ -204,21 +239,23 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
        
        res_code = RSVAL(p, 0);
        
+       free(clearresult.data);
+
        if ((res_code < KRB5_KPASSWD_SUCCESS) || 
-           (res_code > KRB5_KPASSWD_ACCESSDENIED)) {
+           (res_code >= KRB5_KPASSWD_ACCESSDENIED)) {
                return KRB5KRB_AP_ERR_MODIFIED;
        }
        
        return 0;
 }
 
-ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
-                            const char *realm,  const char *newpw)
+ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw)
 {
        krb5_context context;
        krb5_auth_context auth_context = NULL;
        krb5_principal principal;
        char *princ_name;
+       char *realm;
        krb5_creds creds, *credsp;
        krb5_ccache ccache;
        krb5_data ap_req, chpw_req, chpw_rep;
@@ -234,33 +271,40 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
        
        ret = krb5_cc_default(context, &ccache);
        if (ret) {
+               krb5_free_context(context);
                DEBUG(1,("Failed to get default creds (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
        ZERO_STRUCT(creds);
        
+       realm = strchr(princ, '@');
+       realm++;
+
        asprintf(&princ_name, "kadmin/changepw@%s", realm);
        ret = krb5_parse_name(context, princ_name, &creds.server);
        if (ret) {
+                krb5_free_context(context);
                DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
        free(princ_name);
 
-       asprintf(&princ_name, "HOST/%s@%s", hostname, realm);
-       ret = krb5_parse_name(context, princ_name, &principal);
+       /* parse the principal we got as a function argument */
+       ret = krb5_parse_name(context, princ, &principal);
        if (ret) {
+                krb5_free_context(context);
                DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
-       free(princ_name);
 
        krb5_princ_set_realm(context, creds.server,
                             krb5_princ_realm(context, principal));
        
        ret = krb5_cc_get_principal(context, ccache, &creds.client);
        if (ret) {
+               krb5_free_principal(context, principal);
+                krb5_free_context(context);
                DEBUG(1,("Failed to get principal from ccache (%s)\n", 
                         error_message(ret)));
                return ADS_ERROR_KRB5(ret);
@@ -268,13 +312,21 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
        
        ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
        if (ret) {
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
        
+       //we might have to call krb5_free_creds(...) from now on ...
        ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
                                   NULL, credsp, &ap_req);
        if (ret) {
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
@@ -282,6 +334,11 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
        sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
        if (sock == -1) {
                int rc = errno;
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("failed to open kpasswd socket to %s (%s)\n", 
                         kdc_host, strerror(errno)));
                return ADS_ERROR_SYSTEM(rc);
@@ -301,18 +358,37 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
 
        ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
        if (ret) {
+               close(sock);
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
        ret = build_setpw_request(context, auth_context, &ap_req,
-                                 hostname, realm, newpw, &chpw_req);
+                                 princ, newpw, &chpw_req);
        if (ret) {
+               close(sock);
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
        if (write(sock, chpw_req.data, chpw_req.length) != chpw_req.length) {
+               close(sock);
+               free(chpw_req.data);
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
                return ADS_ERROR(LDAP_ENCODING_ERROR);
        }
@@ -324,6 +400,14 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
 
        ret = read(sock, chpw_rep.data, chpw_rep.length);
        if (ret < 0) {
+               close(sock);
+               free(chpw_rep.data);
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
+               DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
                return ADS_ERROR_SYSTEM(errno);
        }
 
@@ -332,6 +416,12 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
 
        ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
        if (ret) {
+               free(chpw_rep.data);
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", 
                         error_message(ret)));
                return ADS_ERROR_KRB5(ret);
@@ -341,12 +431,39 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *hostname,
        free(chpw_rep.data);
 
        if (ret) {
+               free(ap_req.data);
+               krb5_free_creds(context, credsp);
+               krb5_free_principal(context, creds.client);
+               krb5_free_principal(context, principal);
+               krb5_free_context(context);
                DEBUG(1,("parse_setpw_reply failed (%s)\n", 
                         error_message(ret)));
                return ADS_ERROR_KRB5(ret);
        }
 
+       free(ap_req.data);
+       krb5_free_creds(context, credsp);
+       krb5_free_principal(context, creds.client);
+       krb5_free_principal(context, principal);
+       krb5_free_context(context);
+
        return ADS_SUCCESS;
 }
 
+
+ADS_STATUS kerberos_set_password(const char *kpasswd_server, 
+                                const char *auth_principal, const char *auth_password,
+                                const char *target_principal, const char *new_password)
+{
+    int ret;
+
+    if ((ret = kerberos_kinit_password(auth_principal, auth_password))) {
+       DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
+       return ADS_ERROR_KRB5(ret);
+    }
+
+    return krb5_set_password(kpasswd_server, target_principal, new_password);
+}
+
+
 #endif
index 3452614315fce250ac9fc383bb86ff74b802794f..d2b9f74c4d6ac1221875eb933d6661dd45c5d87f 100644 (file)
@@ -3,6 +3,8 @@
    Version 3.0
    ads (active directory) utility library
    Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Remus Koos 2001
+   
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -442,9 +444,17 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
 {
        ADS_STATUS status;
        char *host = strdup(hostname);
+       char *principal; 
+
        strlower(host);
-       status = krb5_set_password(ads->kdc_server, host, ads->realm, password);
+
+       asprintf(&principal, "%s@%s", host, ads->realm);
+       
+       status = krb5_set_password(ads->kdc_server, principal, password);
+       
        free(host);
+       free(principal);
+
        return status;
 }
 
index 5f2a5c4cf75b63243388947ab92430c37ecd05d2..090b859b372062e2855c3d1d2b7ceffe4f162ef7 100644 (file)
@@ -1,2 +1,3 @@
 *.po
 *.po32
+diffs
index b0e66acabce1b674cb75a2c15b6e53c8ffe1cf0b..0bc8c1aedf040334e5fed900fde3384cd230aef4 100644 (file)
@@ -1,8 +1,9 @@
-tdbtool
+*.po
+*.po32
+tdbdump
 tdbtest
+tdbtool
 tdbtorture
 test.db
 test.gdbm
 test.tdb
-*.po
-*.po32
index 3bfc9d935cc9b746f07600673f79989373491647..0853cd3bbf96d1399542664cecb19f742a0b89e1 100644 (file)
@@ -3,6 +3,7 @@
    Version 3.0
    net ads commands
    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+   Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -38,6 +39,11 @@ int net_ads_usage(int argc, const char **argv)
 "\n\tshows some info on the server\n"\
 "\nnet ads status"\
 "\n\tdump the machine account details to stdout\n"
+"\nnet ads password <username@realm> -Uadmin_username@realm%%admin_pass"\
+"\n\tchange a user's password using an admin account"
+"\n\t(note: use realm in UPPERCASE)\n"
+"\nnet ads chostpass"
+"\n\tchange the trust account password of this machine in the AD tree\n"
                );
        return -1;
 }
@@ -257,6 +263,89 @@ static int net_ads_join(int argc, const char **argv)
        return 0;
 }
 
+
+static int net_ads_password(int argc, const char **argv)
+{
+    ADS_STRUCT *ads;
+    extern char *opt_user_name;
+    extern char *opt_password;
+    char *auth_principal = opt_user_name;
+    char *auth_password = opt_password;
+    char *realm = NULL;
+    char *new_password = NULL;
+    char *c;
+    char *prompt;
+    ADS_STATUS ret;
+
+    
+    if ((argc != 1) || (opt_user_name == NULL) || 
+       (opt_password == NULL) || (strchr(opt_user_name, '@') == NULL) ||
+       (strchr(argv[0], '@') == NULL)) {
+       return net_ads_usage(argc, argv);
+    }
+    
+    c = strchr(auth_principal, '@');
+    realm = ++c;
+
+    /* use the realm so we can eventually change passwords for users 
+    in realms other than default */
+    if (!(ads = ads_init(realm, NULL, NULL, NULL))) return -1;
+
+    asprintf(&prompt, "Enter new password for %s:", argv[0]);
+
+    new_password = getpass(prompt);
+
+    ret = kerberos_set_password(ads->kdc_server, auth_principal, 
+                               auth_password, argv[0], new_password);
+    if (!ADS_ERR_OK(ret)) {
+       d_printf("Password change failed :-( ...\n");
+       ads_destroy(&ads);
+       free(prompt);
+       return -1;
+    }
+
+    d_printf("Password change for %s completed.\n", argv[0]);
+    ads_destroy(&ads);
+    free(prompt);
+
+    return 0;
+}
+
+
+static int net_ads_change_localhost_pass(int argc, const char **argv)
+{    
+    ADS_STRUCT *ads;
+    extern pstring global_myname;
+    char *host_principal;
+    char *hostname;
+    ADS_STATUS ret;
+
+
+    if (!(ads = ads_init(NULL, NULL, NULL, NULL))) return -1;
+
+    hostname = strdup(global_myname);
+    strlower(hostname);
+    asprintf(&host_principal, "%s@%s", hostname, ads->realm);
+    SAFE_FREE(hostname);
+    d_printf("Changing password for principal: HOST/%s\n", host_principal);
+    
+    ret = ads_change_trust_account_password(ads, host_principal);
+
+    if (!ADS_ERR_OK(ret)) {
+       d_printf("Password change failed :-( ...\n");
+       ads_destroy(&ads);
+       SAFE_FREE(host_principal);
+       return -1;
+    }
+    
+    d_printf("Password change for principal HOST/%s succeeded.\n", host_principal);
+    ads_destroy(&ads);
+    SAFE_FREE(host_principal);
+
+    return 0;
+}
+
+
 int net_ads(int argc, const char **argv)
 {
        struct functable func[] = {
@@ -266,6 +355,8 @@ int net_ads(int argc, const char **argv)
                {"STATUS", net_ads_status},
                {"USER", net_ads_user},
                {"GROUP", net_ads_group},
+               {"PASSWORD", net_ads_password},
+               {"CHOSTPASS", net_ads_change_localhost_pass},
                {NULL, NULL}
        };