diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/libads/util.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | source3/libads/util.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/source3/libads/util.c b/source3/libads/util.c new file mode 100644 index 0000000..a1e33fd --- /dev/null +++ b/source3/libads/util.c @@ -0,0 +1,236 @@ +/* + Unix SMB/CIFS implementation. + krb5 set password implementation + 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "ads.h" +#include "secrets.h" +#include "librpc/gen_ndr/ndr_secrets.h" + +#ifdef HAVE_KRB5 +ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal) +{ + const char *password = NULL; + const char *new_password = NULL; + ADS_STATUS ret; + const char *domain = lp_workgroup(); + struct secrets_domain_info1 *info = NULL; + struct secrets_domain_info1_change *prev = NULL; + const DATA_BLOB *cleartext_blob = NULL; + DATA_BLOB pw_blob = data_blob_null; + DATA_BLOB new_pw_blob = data_blob_null; + NTSTATUS status; + struct timeval tv = timeval_current(); + NTTIME now = timeval_to_nttime(&tv); + int role = lp_server_role(); + bool ok; + + if (role != ROLE_DOMAIN_MEMBER) { + DBG_ERR("Machine account password change only supported on a DOMAIN_MEMBER.\n"); + return ADS_ERROR_NT(NT_STATUS_INVALID_SERVER_STATE); + } + + new_password = trust_pw_new_value(talloc_tos(), SEC_CHAN_WKSTA, SEC_ADS); + if (new_password == NULL) { + ret = ADS_ERROR_SYSTEM(errno); + DEBUG(1,("Failed to generate machine password\n")); + return ret; + } + + status = secrets_prepare_password_change(domain, + ads->auth.kdc_server, + new_password, + talloc_tos(), + &info, &prev); + if (!NT_STATUS_IS_OK(status)) { + return ADS_ERROR_NT(status); + } + if (prev != NULL) { + status = NT_STATUS_REQUEST_NOT_ACCEPTED; + secrets_failed_password_change("localhost", + status, + NT_STATUS_NOT_COMMITTED, + info); + return ADS_ERROR_NT(status); + } + + cleartext_blob = &info->password->cleartext_blob; + ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX, + cleartext_blob->data, + cleartext_blob->length, + (void **)&pw_blob.data, + &pw_blob.length); + if (!ok) { + status = NT_STATUS_UNMAPPABLE_CHARACTER; + if (errno == ENOMEM) { + status = NT_STATUS_NO_MEMORY; + } + DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) " + "failed for password of %s - %s\n", + domain, nt_errstr(status)); + return ADS_ERROR_NT(status); + } + password = (const char *)pw_blob.data; + + cleartext_blob = &info->next_change->password->cleartext_blob; + ok = convert_string_talloc(talloc_tos(), CH_UTF16MUNGED, CH_UNIX, + cleartext_blob->data, + cleartext_blob->length, + (void **)&new_pw_blob.data, + &new_pw_blob.length); + if (!ok) { + status = NT_STATUS_UNMAPPABLE_CHARACTER; + if (errno == ENOMEM) { + status = NT_STATUS_NO_MEMORY; + } + DBG_ERR("convert_string_talloc(CH_UTF16MUNGED, CH_UNIX) " + "failed for new_password of %s - %s\n", + domain, nt_errstr(status)); + secrets_failed_password_change("localhost", + status, + NT_STATUS_NOT_COMMITTED, + info); + return ADS_ERROR_NT(status); + } + talloc_keep_secret(new_pw_blob.data); + new_password = (const char *)new_pw_blob.data; + + ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset); + + if (!ADS_ERR_OK(ret)) { + status = ads_ntstatus(ret); + DBG_ERR("kerberos_set_password(%s, %s) " + "failed for new_password of %s - %s\n", + ads->auth.kdc_server, host_principal, + domain, nt_errstr(status)); + secrets_failed_password_change(ads->auth.kdc_server, + NT_STATUS_NOT_COMMITTED, + status, + info); + return ret; + } + + status = secrets_finish_password_change(ads->auth.kdc_server, now, info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("Failed to save machine password\n")); + return ADS_ERROR_NT(status); + } + + return ADS_SUCCESS; +} +#endif + +/** +* @brief Parses windows style SPN service/host:port/servicename +* serviceclass - A string that identifies the general class of service +* e.g. 'http' +* host - A netbios name or fully-qualified DNS name +* port - An optional TCP or UDP port number +* servicename - An optional distinguished name, GUID, DNS name or +* DNS name of an SRV or MX record. (not needed for host +* based services) +* +* @param[in] ctx - Talloc context. +* @param[in] srvprinc - The service principal +* +* @return - struct spn_struct containing the fields parsed or NULL +* if srvprinc could not be parsed. +*/ +struct spn_struct *parse_spn(TALLOC_CTX *ctx, const char *srvprinc) +{ + struct spn_struct * result = NULL; + char *tmp = NULL; + char *port_str = NULL; + char *host_str = NULL; + + result = talloc_zero(ctx, struct spn_struct); + if (result == NULL) { + DBG_ERR("Out of memory\n"); + return NULL; + } + + result->serviceclass = talloc_strdup(result, srvprinc); + if (result->serviceclass == NULL) { + DBG_ERR("Out of memory\n"); + goto fail; + } + result->port = -1; + + tmp = strchr_m(result->serviceclass, '/'); + if (tmp == NULL) { + /* illegal */ + DBG_ERR("Failed to parse spn %s, no host definition\n", + srvprinc); + goto fail; + } + + /* terminate service principal */ + *tmp = '\0'; + tmp++; + host_str = tmp; + + tmp = strchr_m(host_str, ':'); + if (tmp != NULL) { + *tmp = '\0'; + tmp++; + port_str = tmp; + } else { + tmp = host_str; + } + + tmp = strchr_m(tmp, '/'); + if (tmp != NULL) { + *tmp = '\0'; + tmp++; + result->servicename = tmp; + } + + if (strlen(host_str) == 0) { + /* illegal */ + DBG_ERR("Failed to parse spn %s, illegal host definition\n", + srvprinc); + goto fail; + } + result->host = host_str; + + if (result->servicename != NULL && (strlen(result->servicename) == 0)) { + DBG_ERR("Failed to parse spn %s, empty servicename " + "definition\n", srvprinc); + goto fail; + } + if (port_str != NULL) { + if (strlen(port_str) == 0) { + DBG_ERR("Failed to parse spn %s, empty port " + "definition\n", srvprinc); + goto fail; + } + result->port = (int32_t)strtol(port_str, NULL, 10); + if (result->port <= 0 + || result->port > 65535 + || errno == ERANGE) { + DBG_ERR("Failed to parse spn %s, port number " + "conversion failed\n", srvprinc); + errno = 0; + goto fail; + } + } + return result; +fail: + TALLOC_FREE(result); + return NULL; +} |