diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/libads/kerberos.c | 13 | ||||
-rw-r--r-- | source3/libads/krb5_setpw.c | 145 | ||||
-rw-r--r-- | source3/libads/ldap.c | 12 | ||||
-rw-r--r-- | source3/nsswitch/.cvsignore | 1 | ||||
-rw-r--r-- | source3/tdb/.cvsignore | 7 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 91 |
7 files changed, 244 insertions, 27 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index a713d61f36..3fa516b48c 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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 \ diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 8378442885..aba22e023b 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -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", diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c index b46a579263..e15c22091d 100644 --- a/source3/libads/krb5_setpw.c +++ b/source3/libads/krb5_setpw.c @@ -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 @@ -32,12 +33,36 @@ /* 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 diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 3452614315..d2b9f74c4d 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -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; } diff --git a/source3/nsswitch/.cvsignore b/source3/nsswitch/.cvsignore index 5f2a5c4cf7..090b859b37 100644 --- a/source3/nsswitch/.cvsignore +++ b/source3/nsswitch/.cvsignore @@ -1,2 +1,3 @@ *.po *.po32 +diffs diff --git a/source3/tdb/.cvsignore b/source3/tdb/.cvsignore index b0e66acabc..0bc8c1aedf 100644 --- a/source3/tdb/.cvsignore +++ b/source3/tdb/.cvsignore @@ -1,8 +1,9 @@ -tdbtool +*.po +*.po32 +tdbdump tdbtest +tdbtool tdbtorture test.db test.gdbm test.tdb -*.po -*.po32 diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 3bfc9d935c..0853cd3bbf 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -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} }; |