#define DEFAULT_KPASSWD_PORT 464
#define KRB5_KPASSWD_VERS_CHANGEPW 1
-#define KRB5_KPASSWD_VERS_SETPW 2
-#define KRB5_KPASSWD_VERS_SETPW_MS 0xff80
+#define KRB5_KPASSWD_VERS_SETPW 0xff80
+#define KRB5_KPASSWD_VERS_SETPW_ALT 2
#define KRB5_KPASSWD_ACCESSDENIED 5
#define KRB5_KPASSWD_BAD_VERSION 6
#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7
DATA_BLOB ret;
- princ = strdup(principal);
+ princ = SMB_STRDUP(principal);
- if ((c = strchr(princ, '/')) == NULL) {
+ if ((c = strchr_m(princ, '/')) == NULL) {
c = princ;
} else {
*c = '\0';
princ_part2 = c;
- if ((c = strchr(c, '@')) != NULL) {
+ if ((c = strchr_m(c, '@')) != NULL) {
*c = '\0';
c++;
realm = c;
if (pversion == KRB5_KPASSWD_VERS_CHANGEPW)
setpw = data_blob(passwd, strlen(passwd));
else if (pversion == KRB5_KPASSWD_VERS_SETPW ||
- pversion == KRB5_KPASSWD_VERS_SETPW_MS)
+ pversion == KRB5_KPASSWD_VERS_SETPW_ALT)
setpw = encode_krb5_setpw(princ, passwd);
else
return EINVAL;
- encoded_setpw.data = setpw.data;
+ encoded_setpw.data = (char *)setpw.data;
encoded_setpw.length = setpw.length;
ret = krb5_mk_priv(context, auth_context,
return ret;
}
- packet->data = (char *)malloc(ap_req->length + cipherpw.length + 6);
+ packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + 6);
if (!packet->data)
return -1;
{0, NULL}
};
-static krb5_error_code krb5_setpw_result_code_string(krb5_context context,
- int result_code,
- const char **code_string)
+static krb5_error_code setpw_result_code_string(krb5_context context,
+ int result_code,
+ const char **code_string)
{
unsigned int idx = 0;
/* FIXME: According to standard there is only one type of reply */
if (vnum != KRB5_KPASSWD_VERS_SETPW &&
- vnum != KRB5_KPASSWD_VERS_SETPW_MS &&
+ vnum != KRB5_KPASSWD_VERS_SETPW_ALT &&
vnum != KRB5_KPASSWD_VERS_CHANGEPW) {
DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));
return KRB5KDC_ERR_BAD_PVNO;
return 0;
else {
const char *errstr;
- krb5_setpw_result_code_string(context, res_code, &errstr);
+ setpw_result_code_string(context, res_code, &errstr);
DEBUG(1, ("Error changing password: %s\n", errstr));
switch(res_code) {
case KRB5_KPASSWD_ACCESSDENIED:
return KRB5KDC_ERR_BADOPTION;
- break;
case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
return KRB5KDC_ERR_BADOPTION;
/* return KV5M_ALT_METHOD; MIT-only define */
- break;
case KRB5_KPASSWD_ETYPE_NOSUPP:
return KRB5KDC_ERR_ETYPE_NOSUPP;
- break;
case KRB5_KPASSWD_BAD_PRINCIPAL:
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- break;
case KRB5_KPASSWD_POLICY_REJECT:
return KRB5KDC_ERR_POLICY;
- break;
default:
return KRB5KRB_ERR_GENERIC;
- break;
}
}
}
{
krb5_auth_context auth_context = NULL;
krb5_data ap_req, chpw_req, chpw_rep;
- int ret, sock, addr_len;
+ int ret, sock;
+ socklen_t addr_len;
struct sockaddr remote_addr, local_addr;
krb5_address local_kaddr, remote_kaddr;
free(chpw_req.data);
chpw_rep.length = 1500;
- chpw_rep.data = (char *) malloc(chpw_rep.length);
+ chpw_rep.data = (char *) SMB_MALLOC(chpw_rep.length);
if (!chpw_rep.data) {
close(sock);
free(ap_req.data);
return ADS_SUCCESS;
}
-ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw,
- int time_offset)
+ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
+ const char *newpw, int time_offset)
{
ADS_STATUS aret;
- krb5_error_code ret;
- krb5_context context;
- krb5_principal principal;
- char *princ_name;
- char *realm;
- krb5_creds creds, *credsp;
- krb5_ccache ccache;
+ krb5_error_code ret = 0;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+ char *princ_name = NULL;
+ char *realm = NULL;
+ krb5_creds creds, *credsp = NULL;
+#if KRB5_PRINC_REALM_RETURNS_REALM
+ krb5_realm orig_realm;
+#else
+ krb5_data orig_realm;
+#endif
+ krb5_ccache ccache = NULL;
+ ZERO_STRUCT(creds);
+
ret = krb5_init_context(&context);
if (ret) {
DEBUG(1,("Failed to init krb5 context (%s)\n", error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
- ZERO_STRUCT(creds);
-
- realm = strchr(princ, '@');
+ realm = strchr_m(princ, '@');
+ if (!realm) {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ DEBUG(1,("Failed to get realm\n"));
+ return ADS_ERROR_KRB5(-1);
+ }
realm++;
asprintf(&princ_name, "kadmin/changepw@%s", realm);
ret = krb5_parse_name(context, princ_name, &creds.server);
if (ret) {
+ krb5_cc_close(context, ccache);
krb5_free_context(context);
DEBUG(1,("Failed to parse kadmin/changepw (%s)\n", error_message(ret)));
return ADS_ERROR_KRB5(ret);
/* parse the principal we got as a function argument */
ret = krb5_parse_name(context, princ, &principal);
if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_free_principal(context, creds.server);
krb5_free_context(context);
DEBUG(1,("Failed to parse %s (%s)\n", princ_name, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
- krb5_princ_set_realm(context, creds.server,
- krb5_princ_realm(context, principal));
+ /* The creds.server principal takes ownership of this memory.
+ Remember to set back to original value before freeing. */
+ orig_realm = *krb5_princ_realm(context, creds.server);
+ krb5_princ_set_realm(context, creds.server, krb5_princ_realm(context, principal));
ret = krb5_cc_get_principal(context, ccache, &creds.client);
if (ret) {
+ krb5_cc_close(context, ccache);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
krb5_free_context(context);
DEBUG(1,("Failed to get principal from ccache (%s)\n",
ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
if (ret) {
+ krb5_cc_close(context, ccache);
krb5_free_principal(context, creds.client);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
krb5_free_context(context);
DEBUG(1,("krb5_get_credentials failed (%s)\n", error_message(ret)));
/* we might have to call krb5_free_creds(...) from now on ... */
aret = do_krb5_kpasswd_request(context, kdc_host,
- KRB5_KPASSWD_VERS_SETPW_MS,
+ KRB5_KPASSWD_VERS_SETPW,
credsp, princ, newpw);
krb5_free_creds(context, credsp);
krb5_free_principal(context, creds.client);
- krb5_free_principal(context, creds.server);
+ krb5_princ_set_realm(context, creds.server, &orig_realm);
+ krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
+ krb5_cc_close(context, ccache);
krb5_free_context(context);
return aret;
return 0;
}
-ADS_STATUS krb5_chg_password(const char *kdc_host,
- const char *principal,
- const char *oldpw,
- const char *newpw,
- int time_offset)
+static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
+ const char *principal,
+ const char *oldpw,
+ const char *newpw,
+ int time_offset)
{
ADS_STATUS aret;
krb5_error_code ret;
- krb5_context context;
+ krb5_context context = NULL;
krb5_principal princ;
krb5_get_init_creds_opt opts;
krb5_creds creds;
/* We have to obtain an INITIAL changepw ticket for changing password */
asprintf(&chpw_princ, "kadmin/changepw@%s",
(char *) krb5_princ_realm(context, princ));
- password = strdup(oldpw);
+ password = SMB_STRDUP(oldpw);
ret = krb5_get_init_creds_password(context, &creds, princ, password,
kerb_prompter, NULL,
0, chpw_princ, &opts);
{
int ret;
- if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset))) {
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL, NULL))) {
DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
if (!strcmp(auth_principal, target_principal))
- return krb5_chg_password(kpasswd_server, target_principal,
- auth_password, new_password, time_offset);
+ return ads_krb5_chg_password(kpasswd_server, target_principal,
+ auth_password, new_password, time_offset);
else
- return krb5_set_password(kpasswd_server, target_principal,
- new_password, time_offset);
+ return ads_krb5_set_password(kpasswd_server, target_principal,
+ new_password, time_offset);
}
* @return status of password change
**/
ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
- const char *hostname,
+ const char *machine_account,
const char *password)
{
ADS_STATUS status;
- char *host = strdup(hostname);
- char *principal;
-
- strlower(host);
+ char *principal = NULL;
/*
- we need to use the '$' form of the name here, as otherwise the
- server might end up setting the password for a user instead
+ we need to use the '$' form of the name here (the machine account name),
+ as otherwise the server might end up setting the password for a user
+ instead
*/
- asprintf(&principal, "%s$@%s", host, ads->auth.realm);
+ asprintf(&principal, "%s@%s", machine_account, ads->config.realm);
- status = krb5_set_password(ads->auth.kdc_server, principal, password, ads->auth.time_offset);
+ status = ads_krb5_set_password(ads->auth.kdc_server, principal,
+ password, ads->auth.time_offset);
- free(host);
free(principal);
return status;