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}  	};  | 
