1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-09 08:58:35 +03:00
samba-mirror/source3/libads/kerberos_verify.c
Andrew Tridgell ab9ff0fa73 This fixes a number of ADS problems, particularly with netbiosless
setups.

- split up the ads structure into logical pieces. This makes it much
  easier to keep things like the authentication realm and the server
  realm separate (they can be different).

- allow ads callers to specify that no sasl bind should be performed
(used by "net ads info" for example)

- fix an error with handing ADS_ERROR_SYSTEM() when errno is 0

- completely rewrote the code for finding the LDAP server. Now try DNS
  methods first, and try all DNS servers returned from the SRV DNS
  query, sorted by closeness to our interfaces (using the same sort code
  as we use in replies from WINS servers). This allows us to cope with
  ADS DCs that are down, and ensures we don't pick one that is on the
  other side of the country unless absolutely necessary.

- recognise dnsRecords as binary when displaying them

- cope with the realm not being configured in smb.conf (work it out
  from the LDAP server)

- look at the trustDirection when looking up trusted domains and don't
  include trusts that trust our domains but we don't trust
  theirs.

- use LDAP to query the alternate (netbios) name for a realm, and make
  sure that both and long and short forms of the name are accepted by
  winbindd. Use the short form by default for listing users/groups.

- rescan the list of trusted domains every 5 minutes in case new trust
  relationships are added while winbindd is running

- include transient trust relationships (ie. C trusts B, B trusts A,
  so C trusts A) in winbindd.

- don't do a gratuituous node status lookup when finding an ADS DC (we
  don't need it and it could fail)

- remove unused sid_to_distinguished_name function

- make sure we find the allternate name of our primary domain when
  operating with a netbiosless ADS DC (using LDAP to do the lookup)

- fixed the rpc trusted domain enumeration to support up to approx
  2000 trusted domains (the old limit was 3)

- use the IP for the remote_machine (%m) macro when the client doesn't
  supply us with a name via a netbios session request (eg. port 445)

- if the client uses SPNEGO then use the machine name from the SPNEGO
  auth packet for remote_machine (%m) macro

- add new 'net ads workgroup' command to find the netbios workgroup
  name for a realm
(This used to be commit e358d7b24c86a46d8c361b9e32a25d4f71a6dc00)
2002-08-05 02:47:46 +00:00

152 lines
4.2 KiB
C

/*
Unix SMB/CIFS implementation.
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
the Free Software Foundation; either version 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#ifdef HAVE_KRB5
/*
verify an incoming ticket and parse out the principal name and
authorization_data if available
*/
NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
char **principal, DATA_BLOB *auth_data)
{
krb5_context context;
krb5_auth_context auth_context = NULL;
krb5_keytab keytab = NULL;
krb5_data packet;
krb5_ticket *tkt = NULL;
krb5_data salt;
krb5_encrypt_block eblock;
int ret;
krb5_keyblock * key;
krb5_principal host_princ;
char *host_princ_s;
extern pstring global_myname;
fstring myname;
char *password_s;
krb5_data password;
if (!secrets_init()) {
DEBUG(1,("secrets_init failed\n"));
return NT_STATUS_LOGON_FAILURE;
}
password_s = secrets_fetch_machine_password();
if (!password_s) {
DEBUG(1,("failed to fetch machine password\n"));
return NT_STATUS_LOGON_FAILURE;
}
password.data = password_s;
password.length = strlen(password_s);
ret = krb5_init_context(&context);
if (ret) {
DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
ret = krb5_set_default_realm(context, ads->auth.realm);
if (ret) {
DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
ads_destroy(&ads);
return NT_STATUS_LOGON_FAILURE;
}
/* this whole process is far more complex than I would
like. We have to go through all this to allow us to store
the secret internally, instead of using /etc/krb5.keytab */
ret = krb5_auth_con_init(context, &auth_context);
if (ret) {
DEBUG(1,("krb5_auth_con_init failed (%s)\n", error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
fstrcpy(myname, global_myname);
strlower(myname);
asprintf(&host_princ_s, "HOST/%s@%s", myname, lp_realm());
ret = krb5_parse_name(context, host_princ_s, &host_princ);
if (ret) {
DEBUG(1,("krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
ret = krb5_principal2salt(context, host_princ, &salt);
if (ret) {
DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
return NT_STATUS_NO_MEMORY;
}
krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_MD5);
ret = krb5_string_to_key(context, &eblock, key, &password, &salt);
if (ret) {
DEBUG(1,("krb5_string_to_key failed (%s)\n", error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
krb5_auth_con_setuseruserkey(context, auth_context, key);
packet.length = ticket->length;
packet.data = (krb5_pointer)ticket->data;
#if 0
file_save("/tmp/ticket.dat", ticket->data, ticket->length);
#endif
if ((ret = krb5_rd_req(context, &auth_context, &packet,
NULL, keytab, NULL, &tkt))) {
DEBUG(3,("krb5_rd_req with auth failed (%s)\n",
error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
if (tkt->enc_part2) {
*auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
tkt->enc_part2->authorization_data[0]->length);
}
#if 0
if (tkt->enc_part2) {
file_save("/tmp/authdata.dat",
tkt->enc_part2->authorization_data[0]->contents,
tkt->enc_part2->authorization_data[0]->length);
}
#endif
if ((ret = krb5_unparse_name(context, tkt->enc_part2->client, principal))) {
DEBUG(3,("krb5_unparse_name failed (%s)\n",
error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
return NT_STATUS_OK;
}
#endif