summaryrefslogtreecommitdiffstats
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/Makefile.in2
-rw-r--r--source4/aclocal.m4107
-rw-r--r--source4/configure.in4
-rw-r--r--source4/include/ads.h84
-rw-r--r--source4/include/includes.h31
-rw-r--r--source4/libads/ads_ldap.c95
-rw-r--r--source4/libads/ads_status.c39
-rw-r--r--source4/libads/ads_struct.c7
-rw-r--r--source4/libads/ads_utils.c48
-rw-r--r--source4/libads/config.m4549
-rw-r--r--source4/libads/kerberos_verify.c320
-rw-r--r--source4/libads/krb5_setpw.c119
-rw-r--r--source4/libads/ldap.c598
-rw-r--r--source4/libads/ldap_printer.c25
-rw-r--r--source4/libads/ldap_user.c10
-rw-r--r--source4/libads/ldap_utils.c34
-rw-r--r--source4/libads/sasl.c41
-rw-r--r--source4/libads/util.c49
-rw-r--r--source4/libcli/raw/clikrb5.c96
-rw-r--r--source4/libcli/raw/clispnego.c20
20 files changed, 1504 insertions, 774 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in
index 4c3f216867e..1580814920e 100644
--- a/source4/Makefile.in
+++ b/source4/Makefile.in
@@ -12,7 +12,7 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
-LIBS=@LIBS@
+LIBS=@LIBS@ @LDAP_LIBS@ @KRB5_LIBS@
CC=@CC@
SHLD=@SHLD@
CFLAGS=@CFLAGS@
diff --git a/source4/aclocal.m4 b/source4/aclocal.m4
index b40152a6ee9..21275fea61e 100644
--- a/source4/aclocal.m4
+++ b/source4/aclocal.m4
@@ -135,6 +135,113 @@ AC_DEFUN(AC_LIBTESTFUNC,
esac
])
+# AC_CHECK_LIB_EXT(LIBRARY, [EXT_LIBS], [FUNCTION],
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND],
+# [ADD-ACTION-IF-FOUND],[OTHER-LIBRARIES])
+# ------------------------------------------------------
+#
+# Use a cache variable name containing both the library and function name,
+# because the test really is for library $1 defining function $3, not
+# just for library $1. Separate tests with the same $1 and different $3s
+# may have different results.
+#
+# Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$3])
+# is asking for trouble, since AC_CHECK_LIB($lib, fun) would give
+# ac_cv_lib_$lib_fun, which is definitely not what was meant. Hence
+# the AS_LITERAL_IF indirection.
+#
+# FIXME: This macro is extremely suspicious. It DEFINEs unconditionally,
+# whatever the FUNCTION, in addition to not being a *S macro. Note
+# that the cache does depend upon the function we are looking for.
+#
+# It is on purpose we used `ac_check_lib_ext_save_LIBS' and not just
+# `ac_save_LIBS': there are many macros which don't want to see `LIBS'
+# changed but still want to use AC_CHECK_LIB_EXT, so they save `LIBS'.
+# And ``ac_save_LIBS' is too tempting a name, so let's leave them some
+# freedom.
+AC_DEFUN([AC_CHECK_LIB_EXT],
+[
+AH_CHECK_LIB_EXT([$1])
+ac_check_lib_ext_save_LIBS=$LIBS
+LIBS="-l$1 $$2 $7 $LIBS"
+AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1])],
+ [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1''])])dnl
+
+m4_ifval([$3],
+ [
+ AH_CHECK_FUNC_EXT([$3])
+ AS_LITERAL_IF([$1],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1_$3])],
+ [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1''_$3])])dnl
+ AC_CACHE_CHECK([for $3 in -l$1], ac_Lib_func,
+ [AC_TRY_LINK_FUNC($3,
+ [AS_VAR_SET(ac_Lib_func, yes);
+ AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_func, no);
+ AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ AS_IF([test AS_VAR_GET(ac_Lib_func) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$3))])dnl
+ AS_VAR_POPDEF([ac_Lib_func])dnl
+ ],[
+ AC_CACHE_CHECK([for -l$1], ac_Lib_ext,
+ [AC_TRY_LINK_FUNC([main],
+ [AS_VAR_SET(ac_Lib_ext, yes)],
+ [AS_VAR_SET(ac_Lib_ext, no)])
+ ])
+ ])
+LIBS=$ac_check_lib_ext_save_LIBS
+
+AS_IF([test AS_VAR_GET(ac_Lib_ext) = yes],
+ [m4_default([$4],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
+ case "$$2" in
+ *-l$1*)
+ ;;
+ *)
+ $2="-l$1 $$2"
+ ;;
+ esac])
+ [$6]
+ ],
+ [$5])dnl
+AS_VAR_POPDEF([ac_Lib_ext])dnl
+])# AC_CHECK_LIB_EXT
+
+# AH_CHECK_LIB_EXT(LIBNAME)
+# ---------------------
+m4_define([AH_CHECK_LIB_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_LIB$1),
+ [Define to 1 if you have the `]$1[' library (-l]$1[).])])
+
+# AC_CHECK_FUNCS_EXT(FUNCTION, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -----------------------------------------------------------------
+dnl check for a function in a $LIBS and $OTHER_LIBS libraries variable.
+dnl AC_CHECK_FUNC_EXT(func,OTHER_LIBS,IF-TRUE,IF-FALSE)
+AC_DEFUN([AC_CHECK_FUNC_EXT],
+[
+ AH_CHECK_FUNC_EXT($1)
+ ac_check_func_ext_save_LIBS=$LIBS
+ LIBS="$2 $LIBS"
+ AS_VAR_PUSHDEF([ac_var], [ac_cv_func_ext_$1])dnl
+ AC_CACHE_CHECK([for $1], ac_var,
+ [AC_LINK_IFELSE([AC_LANG_FUNC_LINK_TRY([$1])],
+ [AS_VAR_SET(ac_var, yes)],
+ [AS_VAR_SET(ac_var, no)])])
+ LIBS=$ac_check_func_ext_save_LIBS
+ AS_IF([test AS_VAR_GET(ac_var) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1])) $3],
+ [$4])dnl
+AS_VAR_POPDEF([ac_var])dnl
+])# AC_CHECK_FUNC
+
+# AH_CHECK_FUNC_EXT(FUNCNAME)
+# ---------------------
+m4_define([AH_CHECK_FUNC_EXT],
+[AH_TEMPLATE(AS_TR_CPP(HAVE_$1),
+ [Define to 1 if you have the `]$1[' function.])])
+
dnl Define an AC_DEFINE with ifndef guard.
dnl AC_N_DEFINE(VARIABLE [, VALUE])
define(AC_N_DEFINE,
diff --git a/source4/configure.in b/source4/configure.in
index 567916e8361..4c95e7e2a24 100644
--- a/source4/configure.in
+++ b/source4/configure.in
@@ -462,7 +462,7 @@ AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/i
AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h)
AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h)
AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h)
-AC_CHECK_HEADERS(security/pam_modules.h security/_pam_macros.h ldap.h lber.h dlfcn.h)
+AC_CHECK_HEADERS(security/pam_modules.h security/_pam_macros.h dlfcn.h)
AC_CHECK_HEADERS(sys/syslog.h syslog.h)
#
@@ -1815,7 +1815,7 @@ AC_SEARCH_LIBS(crypt, [crypt],
## check checking for truncated salt. Wrapped by the
## $with_pam_for_crypt variable as above --jerry
##
-if test $with_pam_for_crypt = no; then
+if test x"$with_pam_for_crypt" != x"yes"; then
AC_CACHE_CHECK([for a crypt that needs truncated salt],samba_cv_HAVE_TRUNCATED_SALT,[
crypt_LIBS="$LIBS"
LIBS="$AUTHLIBS $LIBS"
diff --git a/source4/include/ads.h b/source4/include/ads.h
index f90983e4052..410395a71ba 100644
--- a/source4/include/ads.h
+++ b/source4/include/ads.h
@@ -1,9 +1,28 @@
-/*
- header for ads (active directory) library routines
-
- basically this is a wrapper around ldap
+/*
+ Unix SMB/CIFS implementation.
+ header for ads (active directory) library routines
+ basically this is a wrapper around ldap
+
+ Copyright (C) Andrew Tridgell 2001-2003
+
+ 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.
*/
+#ifndef _ADS_H
+#define _ADS_H
+
typedef struct {
void *ld; /* the active ldap structure */
struct in_addr ldap_ip; /* the ip of the active connection, if any */
@@ -38,9 +57,9 @@ typedef struct {
} config;
} ADS_STRUCT;
-/* there are 4 possible types of errors the ads subsystem can produce */
-enum ads_error_type {ADS_ERROR_KRB5, ADS_ERROR_GSS,
- ADS_ERROR_LDAP, ADS_ERROR_SYSTEM, ADS_ERROR_NT};
+/* there are 5 possible types of errors the ads subsystem can produce */
+enum ads_error_type {ENUM_ADS_ERROR_KRB5, ENUM_ADS_ERROR_GSS,
+ ENUM_ADS_ERROR_LDAP, ENUM_ADS_ERROR_SYSTEM, ENUM_ADS_ERROR_NT};
typedef struct {
enum ads_error_type error_type;
@@ -48,7 +67,7 @@ typedef struct {
int rc;
NTSTATUS nt_status;
} err;
- /* For error_type = ADS_ERROR_GSS minor_status describe GSS API error */
+ /* For error_type = ENUM_ADS_ERROR_GSS minor_status describe GSS API error */
/* Where rc represents major_status of GSS API error */
int minor_status;
} ADS_STATUS;
@@ -61,13 +80,13 @@ typedef void **ADS_MODLIST;
/* macros to simplify error returning */
#define ADS_ERROR(rc) ADS_ERROR_LDAP(rc)
-#define ADS_ERROR_LDAP(rc) ads_build_error(ADS_ERROR_LDAP, rc, 0)
-#define ADS_ERROR_SYSTEM(rc) ads_build_error(ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)
-#define ADS_ERROR_KRB5(rc) ads_build_error(ADS_ERROR_KRB5, rc, 0)
-#define ADS_ERROR_GSS(rc, minor) ads_build_error(ADS_ERROR_GSS, rc, minor)
-#define ADS_ERROR_NT(rc) ads_build_nt_error(ADS_ERROR_NT,rc)
+#define ADS_ERROR_LDAP(rc) ads_build_error(ENUM_ADS_ERROR_LDAP, rc, 0)
+#define ADS_ERROR_SYSTEM(rc) ads_build_error(ENUM_ADS_ERROR_SYSTEM, rc?rc:EINVAL, 0)
+#define ADS_ERROR_KRB5(rc) ads_build_error(ENUM_ADS_ERROR_KRB5, rc, 0)
+#define ADS_ERROR_GSS(rc, minor) ads_build_error(ENUM_ADS_ERROR_GSS, rc, minor)
+#define ADS_ERROR_NT(rc) ads_build_nt_error(ENUM_ADS_ERROR_NT,rc)
-#define ADS_ERR_OK(status) ((status.error_type == ADS_ERROR_NT) ? NT_STATUS_IS_OK(status.err.nt_status):(status.err.rc == 0))
+#define ADS_ERR_OK(status) ((status.error_type == ENUM_ADS_ERROR_NT) ? NT_STATUS_IS_OK(status.err.nt_status):(status.err.rc == 0))
#define ADS_SUCCESS ADS_ERROR(0)
/* time between reconnect attempts */
@@ -205,7 +224,11 @@ typedef void **ADS_MODLIST;
#define ADS_AUTH_NO_BIND 0x02
#define ADS_AUTH_ANON_BIND 0x04
#define ADS_AUTH_SIMPLE_BIND 0x08
+#define ADS_AUTH_ALLOW_NTLMSSP 0x10
+/***************************************
+ Some krb5 compat stuff
+***************************************/
/* Kerberos environment variable names */
#define KRB5_ENV_CCNAME "KRB5CCNAME"
@@ -213,3 +236,36 @@ typedef void **ADS_MODLIST;
#if defined(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5)
#define ENCTYPE_ARCFOUR_HMAC ENCTYPE_ARCFOUR_HMAC_MD5
#endif
+
+/* The older versions of heimdal that don't have this
+ define don't seem to use it anyway. I'm told they
+ always use a subkey */
+#ifndef HAVE_AP_OPTS_USE_SUBKEY
+#define AP_OPTS_USE_SUBKEY 0
+#endif
+#if defined(HAVE_KRB5)
+
+#ifndef HAVE_KRB5_SET_REAL_TIME
+krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds);
+#endif
+
+#ifndef HAVE_KRB5_SET_DEFAULT_TGS_KTYPES
+krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc);
+#endif
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock);
+#endif
+
+/* Samba wrapper function for krb5 functionality. */
+void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr);
+int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype);
+void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt);
+krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt);
+krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
+krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes);
+void free_kerberos_etypes(krb5_context context, krb5_enctype *enctypes);
+BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote);
+#endif /* HAVE_KRB5 */
+
+#endif /* _ADS_H */
diff --git a/source4/include/includes.h b/source4/include/includes.h
index 2b83d146225..2391a59b67f 100644
--- a/source4/include/includes.h
+++ b/source4/include/includes.h
@@ -339,10 +339,6 @@
#include <stropts.h>
#endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-
#ifdef HAVE_SYS_CAPABILITY_H
#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H)
@@ -721,7 +717,6 @@ extern int errno;
#include "../tdb/tdbutil.h"
#include "talloc.h"
#include "nt_status.h"
-#include "ads.h"
#include "interfaces.h"
#include "trans2.h"
#include "ioctl.h"
@@ -734,6 +729,7 @@ extern int errno;
#include "version.h"
#include "smb.h"
+#include "ads.h"
#include "nameserv.h"
#include "secrets.h"
@@ -1147,30 +1143,5 @@ time_t timegm(struct tm *tm);
#define VXFS_QUOTA
#endif
-#if defined(HAVE_KRB5)
-
-#ifndef KRB5_SET_REAL_TIME
-krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds);
-#endif
-
-#ifndef HAVE_KRB5_SET_DEFAULT_TGS_KTYPES
-krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc);
-#endif
-
-#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
-krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock);
-#endif
-
-/* Samba wrapper function for krb5 functionality. */
-void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr);
-int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype);
-void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt);
-krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt);
-krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
-krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes);
-void free_kerberos_etypes(krb5_context context, krb5_enctype *enctypes);
-BOOL krb5_get_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16]);
-#endif /* HAVE_KRB5 */
-
#endif /* _INCLUDES_H */
diff --git a/source4/libads/ads_ldap.c b/source4/libads/ads_ldap.c
index 97f12de0f7f..944cb1599cc 100644
--- a/source4/libads/ads_ldap.c
+++ b/source4/libads/ads_ldap.c
@@ -34,7 +34,7 @@ NTSTATUS ads_name_to_sid(ADS_STRUCT *ads,
int count;
ADS_STATUS rc;
void *res = NULL;
- char *exp;
+ char *ldap_exp;
uint32 t;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
char *escaped_name = escape_ldap_string_alloc(name);
@@ -45,15 +45,15 @@ NTSTATUS ads_name_to_sid(ADS_STRUCT *ads,
goto done;
}
- if (asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",
+ if (asprintf(&ldap_exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",
escaped_name, escaped_name, escaped_realm) == -1) {
DEBUG(1,("ads_name_to_sid: asprintf failed!\n"));
status = NT_STATUS_NO_MEMORY;
goto done;
}
- rc = ads_search_retry(ads, &res, exp, attrs);
- free(exp);
+ rc = ads_search_retry(ads, &res, ldap_exp, attrs);
+ free(ldap_exp);
if (!ADS_ERR_OK(rc)) {
DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc)));
goto done;
@@ -102,7 +102,7 @@ NTSTATUS ads_sid_to_name(ADS_STRUCT *ads,
"sAMAccountType", NULL};
ADS_STATUS rc;
void *msg = NULL;
- char *exp = NULL;
+ char *ldap_exp = NULL;
char *sidstr = NULL;
uint32 atype;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
@@ -113,13 +113,13 @@ NTSTATUS ads_sid_to_name(ADS_STRUCT *ads,
goto done;
}
- if (asprintf(&exp, "(objectSid=%s)", sidstr) == -1) {
+ if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
DEBUG(1,("ads_sid_to_name: asprintf failed!\n"));
status = NT_STATUS_NO_MEMORY;
goto done;
}
- rc = ads_search_retry(ads, &msg, exp, attrs);
+ rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
if (!ADS_ERR_OK(rc)) {
status = ads_ntstatus(rc);
DEBUG(1,("ads_sid_to_name ads_search: %s\n", ads_errstr(rc)));
@@ -146,10 +146,89 @@ NTSTATUS ads_sid_to_name(ADS_STRUCT *ads,
done:
if (msg) ads_msgfree(ads, msg);
- SAFE_FREE(exp);
+ SAFE_FREE(ldap_exp);
SAFE_FREE(sidstr);
return status;
}
+
+/* convert a sid to a DN */
+
+ADS_STATUS ads_sid_to_dn(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **dn)
+{
+ ADS_STATUS rc;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
+ char *ldap_exp;
+ char *sidstr = NULL;
+ int count;
+ char *dn2 = NULL;
+
+ const char *attr[] = {
+ "dn",
+ NULL
+ };
+
+ if (!(sidstr = sid_binstring(sid))) {
+ DEBUG(1,("ads_sid_to_dn: sid_binstring failed!\n"));
+ rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ if(!(ldap_exp = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr))) {
+ DEBUG(1,("ads_sid_to_dn: talloc_asprintf failed!\n"));
+ rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ rc = ads_search_retry(ads, (void **)&msg, ldap_exp, attr);
+
+ if (!ADS_ERR_OK(rc)) {
+ DEBUG(1,("ads_sid_to_dn ads_search: %s\n", ads_errstr(rc)));
+ goto done;
+ }
+
+ if ((count = ads_count_replies(ads, msg)) != 1) {
+ fstring sid_string;
+ DEBUG(1,("ads_sid_to_dn (sid=%s): Not found (count=%d)\n",
+ sid_to_string(sid_string, sid), count));
+ rc = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+ goto done;
+ }
+
+ entry = ads_first_entry(ads, msg);
+
+ dn2 = ads_get_dn(ads, entry);
+
+ if (!dn2) {
+ rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ *dn = talloc_strdup(mem_ctx, dn2);
+
+ if (!*dn) {
+ ads_memfree(ads, dn2);
+ rc = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto done;
+ }
+
+ rc = ADS_ERROR_NT(NT_STATUS_OK);
+
+ DEBUG(3,("ads sid_to_dn mapped %s\n", dn2));
+
+ SAFE_FREE(dn2);
+done:
+ if (msg) ads_msgfree(ads, msg);
+ if (dn2) ads_memfree(ads, dn2);
+
+ SAFE_FREE(sidstr);
+
+ return rc;
+}
+
#endif
diff --git a/source4/libads/ads_status.c b/source4/libads/ads_status.c
index 80fdb99eac0..463f647f9c7 100644
--- a/source4/libads/ads_status.c
+++ b/source4/libads/ads_status.c
@@ -31,10 +31,10 @@ ADS_STATUS ads_build_error(enum ads_error_type etype,
{
ADS_STATUS ret;
- if (etype == ADS_ERROR_NT) {
- DEBUG(0,("don't use ads_build_error with ADS_ERROR_NT!\n"));
+ if (etype == ENUM_ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_error with ENUM_ADS_ERROR_NT!\n"));
ret.err.rc = -1;
- ret.error_type = ADS_ERROR_SYSTEM;
+ ret.error_type = ENUM_ADS_ERROR_SYSTEM;
ret.minor_status = 0;
return ret;
}
@@ -50,10 +50,10 @@ ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
{
ADS_STATUS ret;
- if (etype != ADS_ERROR_NT) {
- DEBUG(0,("don't use ads_build_nt_error without ADS_ERROR_NT!\n"));
+ if (etype != ENUM_ADS_ERROR_NT) {
+ DEBUG(0,("don't use ads_build_nt_error without ENUM_ADS_ERROR_NT!\n"));
ret.err.rc = -1;
- ret.error_type = ADS_ERROR_SYSTEM;
+ ret.error_type = ENUM_ADS_ERROR_SYSTEM;
ret.minor_status = 0;
return ret;
}
@@ -69,15 +69,24 @@ ADS_STATUS ads_build_nt_error(enum ads_error_type etype,
*/
NTSTATUS ads_ntstatus(ADS_STATUS status)
{
- if (status.error_type == ADS_ERROR_NT){
+ if (status.error_type == ENUM_ADS_ERROR_NT){
return status.err.nt_status;
}
#ifdef HAVE_LDAP
- if ((status.error_type == ADS_ERROR_LDAP)
+ if ((status.error_type == ENUM_ADS_ERROR_LDAP)
&& (status.err.rc == LDAP_NO_MEMORY)) {
return NT_STATUS_NO_MEMORY;
}
#endif
+#ifdef HAVE_KRB5
+ if (status.error_type == ENUM_ADS_ERROR_KRB5) {
+ if (status.err.rc == KRB5KDC_ERR_PREAUTH_FAILED) {
+ return NT_STATUS_LOGON_FAILURE;
+ } else if (status.err.rc == KRB5_KDC_UNREACH) {
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+ }
+#endif
if (ADS_ERR_OK(status)) return NT_STATUS_OK;
return NT_STATUS_UNSUCCESSFUL;
}
@@ -87,25 +96,25 @@ NTSTATUS ads_ntstatus(ADS_STATUS status)
*/
const char *ads_errstr(ADS_STATUS status)
{
- int msg_ctx;
+ uint32 msg_ctx;
static char *ret;
SAFE_FREE(ret);
msg_ctx = 0;
switch (status.error_type) {
- case ADS_ERROR_SYSTEM:
+ case ENUM_ADS_ERROR_SYSTEM:
return strerror(status.err.rc);
#ifdef HAVE_LDAP
- case ADS_ERROR_LDAP:
+ case ENUM_ADS_ERROR_LDAP:
return ldap_err2string(status.err.rc);
#endif
#ifdef HAVE_KRB5
- case ADS_ERROR_KRB5:
+ case ENUM_ADS_ERROR_KRB5:
return error_message(status.err.rc);
#endif
#ifdef HAVE_GSSAPI
- case ADS_ERROR_GSS:
+ case ENUM_ADS_ERROR_GSS:
{
uint32 minor;
@@ -122,8 +131,8 @@ const char *ads_errstr(ADS_STATUS status)
return ret;
}
#endif
- case ADS_ERROR_NT:
- return nt_errstr(ads_ntstatus(status));
+ case ENUM_ADS_ERROR_NT:
+ return get_friendly_nt_error_msg(ads_ntstatus(status));
default:
return "Unknown ADS error type!? (not compiled in?)";
}
diff --git a/source4/libads/ads_struct.c b/source4/libads/ads_struct.c
index 652bfe31be8..9774968e121 100644
--- a/source4/libads/ads_struct.c
+++ b/source4/libads/ads_struct.c
@@ -94,12 +94,11 @@ ADS_STRUCT *ads_init(const char *realm,
ads->server.workgroup = workgroup ? strdup(workgroup) : NULL;
ads->server.ldap_server = ldap_server? strdup(ldap_server) : NULL;
- /* we need to know if this is a foreign realm to know if we can
- use lp_ads_server() */
- if (realm && *realm && strcasecmp(lp_realm(), realm) != 0) {
+ /* we need to know if this is a foreign realm */
+ if (realm && *realm && !strequal(lp_realm(), realm)) {
ads->server.foreign = 1;
}
- if (workgroup && *workgroup && strcasecmp(lp_workgroup(), workgroup) != 0) {
+ if (workgroup && *workgroup && !strequal(lp_workgroup(), workgroup)) {
ads->server.foreign = 1;
}
diff --git a/source4/libads/ads_utils.c b/source4/libads/ads_utils.c
index 626c1779266..1aad0bed547 100644
--- a/source4/libads/ads_utils.c
+++ b/source4/libads/ads_utils.c
@@ -89,52 +89,6 @@ uint32 ads_uf2atype(uint32 uf)
}
/*
-translated the GROUP_CTRL Flags to GroupType (groupType)
-*/
-uint32 ads_gcb2gtype(uint16 gcb)
-{
- uint32 gtype = 0x00000000;
-
- if (gcb & GCB_ALIAS_GROUP) gtype |= GTYPE_SECURITY_BUILTIN_LOCAL_GROUP;
- else if(gcb & GCB_LOCAL_GROUP) gtype |= GTYPE_SECURITY_DOMAIN_LOCAL_GROUP;
- if (gcb & GCB_GLOBAL_GROUP) gtype |= GTYPE_SECURITY_GLOBAL_GROUP;
-
- return gtype;
-}
-
-/*
-translated the GroupType (groupType) to GROUP_CTRL Flags
-*/
-uint16 ads_gtype2gcb(uint32 gtype)
-{
- uint16 gcb = 0x0000;
-
- switch(gtype) {
- case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
- gcb = GCB_ALIAS_GROUP;
- break;
- case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
- gcb = GCB_LOCAL_GROUP;
- break;
- case GTYPE_SECURITY_GLOBAL_GROUP:
- gcb = GCB_GLOBAL_GROUP;
- break;
-
- case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
- gcb = GCB_GLOBAL_GROUP;
- break;
- case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
- gcb = GCB_LOCAL_GROUP;
- break;
- case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
- gcb = GCB_GLOBAL_GROUP;
- break;
- }
-
- return gcb;
-}
-
-/*
get the accountType from the groupType
*/
uint32 ads_gtype2atype(uint32 gtype)
@@ -172,6 +126,8 @@ enum SID_NAME_USE ads_atype_map(uint32 atype)
switch (atype & 0xF0000000) {
case ATYPE_GLOBAL_GROUP:
return SID_NAME_DOM_GRP;
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ return SID_NAME_ALIAS;
case ATYPE_ACCOUNT:
return SID_NAME_USER;
default:
diff --git a/source4/libads/config.m4 b/source4/libads/config.m4
index a4ff962a3dd..c0b926b851c 100644
--- a/source4/libads/config.m4
+++ b/source4/libads/config.m4
@@ -1,34 +1,139 @@
+########################################################
+# Compile with LDAP support?
+
+LDAP_LIBS=""
+AC_SUBST(LDAP_LIBS)
+with_ldap_support=auto
+AC_MSG_CHECKING([for LDAP support])
+
+AC_ARG_WITH(ldap,
+[ --with-ldap LDAP support (default yes)],
+[ case "$withval" in
+ yes|no)
+ with_ldap_support=$withval
+ ;;
+ esac ])
+
+AC_MSG_RESULT($with_ldap_support)
+
+if test x"$with_ldap_support" != x"no"; then
+
+ ##################################################################
+ # first test for ldap.h and lber.h
+ # (ldap.h is required for this test)
+ AC_CHECK_HEADERS(ldap.h lber.h)
+
+ if test x"$ac_cv_header_ldap_h" != x"yes"; then
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(ldap.h is needed for LDAP support)
+ else
+ AC_MSG_WARN(ldap.h is needed for LDAP support)
+ fi
+
+ with_ldap_support=no
+ fi
+fi
+
+if test x"$with_ldap_support" != x"no"; then
+ ac_save_LIBS=$LIBS
+
+ ##################################################################
+ # we might need the lber lib on some systems. To avoid link errors
+ # this test must be before the libldap test
+ AC_CHECK_LIB_EXT(lber, LDAP_LIBS, ber_scanf)
+
+ ########################################################
+ # now see if we can find the ldap libs in standard paths
+ AC_CHECK_LIB_EXT(ldap, LDAP_LIBS, ldap_init)
+
+ AC_CHECK_FUNC_EXT(ldap_domain2hostlist,$LDAP_LIBS)
+
+ ########################################################
+ # If we have LDAP, does it's rebind procedure take 2 or 3 arguments?
+ # Check found in pam_ldap 145.
+ AC_CHECK_FUNC_EXT(ldap_set_rebind_proc,$LDAP_LIBS)
+
+ LIBS="$LIBS $LDAP_LIBS"
+ AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, smb_ldap_cv_ldap_set_rebind_proc, [
+ AC_TRY_COMPILE([
+ #include <lber.h>
+ #include <ldap.h>],
+ [ldap_set_rebind_proc(0, 0, 0);],
+ [smb_ldap_cv_ldap_set_rebind_proc=3],
+ [smb_ldap_cv_ldap_set_rebind_proc=2]
+ )
+ ])
+
+ AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc])
+
+ AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS)
+
+ if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes" -a x"$ac_cv_func_ext_ldap_domain2hostlist" = x"yes"; then
+ AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])
+ SMB_MODULE_DEFAULT(STATIC,pdb_ldap)
+ with_ldap_support=yes
+ AC_MSG_CHECKING(whether LDAP support is used)
+ AC_MSG_RESULT(yes)
+ else
+ if test x"$with_ldap_support" = x"yes"; then
+ AC_MSG_ERROR(libldap is needed for LDAP support)
+ else
+ AC_MSG_WARN(libldap is needed for LDAP support)
+ fi
+
+ LDAP_LIBS=""
+ with_ldap_support=no
+ fi
+ LIBS=$ac_save_LIBS
+fi
+
+
#################################################
# active directory support
-with_ads_support=yes
-AC_MSG_CHECKING([whether to use Active Directory])
+KRB5_LIBS=""
+AC_SUBST(KRB5_LIBS)
+with_ads_support=auto
+AC_MSG_CHECKING([for Active Directory and krb5 support])
AC_ARG_WITH(ads,
-[ --with-ads Active Directory support (default yes)],
+[ --with-ads Active Directory support (default auto)],
[ case "$withval" in
- no)
- with_ads_support=no
+ yes|no)
+ with_ads_support="$withval"
;;
esac ])
-if test x"$with_ads_support" = x"yes"; then
- AC_DEFINE(WITH_ADS,1,[Whether to include Active Directory support])
-fi
-
AC_MSG_RESULT($with_ads_support)
-FOUND_KRB5=no
-if test x"$with_ads_support" = x"yes"; then
+if test x"$with_ldap_support" != x"yes"; then
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(Active Directory Support requires LDAP support)
+ elif test x"$with_ads_support" != x"no"; then
+ AC_MSG_WARN(Active Directory Support requires LDAP support)
+ fi
+ with_ads_support=no
+fi
+
+if test x"$with_ads_support" != x"no"; then
+ FOUND_KRB5=no
+ # Do no harm to the values of CFLAGS and LIBS while testing for
+ # Kerberos support.
#################################################
# check for krb5-config from recent MIT and Heimdal kerberos 5
AC_PATH_PROG(KRB5_CONFIG, krb5-config)
AC_MSG_CHECKING(for working krb5-config)
if test -x "$KRB5_CONFIG"; then
- LIBS="$LIBS `$KRB5_CONFIG --libs`"
- CFLAGS="$CFLAGS `$KRB5_CONFIG --cflags`"
- CPPFLAGS="$CPPFLAGS `$KRB5_CONFIG --cflags`"
+ ac_save_CFLAGS=$CFLAGS
+ CFLAGS="";export CFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
+ LDFLAGS="";export LDFLAGS
+ KRB5_LIBS="`$KRB5_CONFIG --libs gssapi`"
+ KRB5_CFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ KRB5_CPPFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ CFLAGS=$ac_save_CFLAGS;export CFLAGS
+ LDFLAGS=$ac_save_LDFLAGS;export LDFLAGS
FOUND_KRB5=yes
AC_MSG_RESULT(yes)
else
@@ -36,193 +141,303 @@ if test x"$with_ads_support" = x"yes"; then
fi
if test x$FOUND_KRB5 = x"no"; then
- #################################################
- # check for location of Kerberos 5 install
- AC_MSG_CHECKING(for kerberos 5 install path)
- AC_ARG_WITH(krb5,
- [ --with-krb5=base-dir Locate Kerberos 5 support (default=/usr)],
- [ case "$withval" in
- no)
+ #################################################
+ # check for location of Kerberos 5 install
+ AC_MSG_CHECKING(for kerberos 5 install path)
+ AC_ARG_WITH(krb5,
+ [ --with-krb5=base-dir Locate Kerberos 5 support (default=/usr)],
+ [ case "$withval" in
+ no)
+ AC_MSG_RESULT(no krb5-path given)
+ ;;
+ yes)
+ AC_MSG_RESULT(/usr)
+ FOUND_KRB5=yes
+ ;;
+ *)
+ AC_MSG_RESULT($withval)
+ KRB5_CFLAGS="-I$withval/include"
+ KRB5_CPPFLAGS="-I$withval/include"
+ KRB5_LDFLAGS="-L$withval/lib"
+ FOUND_KRB5=yes
+ ;;
+ esac ],
+ AC_MSG_RESULT(no krb5-path given)
+ )
+ fi
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # see if this box has the SuSE location for the heimdal krb implementation
+ AC_MSG_CHECKING(for /usr/include/heimdal)
+ if test -d /usr/include/heimdal; then
+ if test -f /usr/lib/heimdal/lib/libkrb5.a; then
+ KRB5_CFLAGS="-I/usr/include/heimdal"
+ KRB5_CPPFLAGS="-I/usr/include/heimdal"
+ KRB5_LDFLAGS="-L/usr/lib/heimdal/lib"
+ AC_MSG_RESULT(yes)
+ else
+ KRB5_CFLAGS="-I/usr/include/heimdal"
+ KRB5_CPPFLAGS="-I/usr/include/heimdal"
+ AC_MSG_RESULT(yes)
+ fi
+ else
AC_MSG_RESULT(no)
- ;;
- *)
+ fi
+ fi
+
+ if test x$FOUND_KRB5 = x"no"; then
+ #################################################
+ # see if this box has the RedHat location for kerberos
+ AC_MSG_CHECKING(for /usr/kerberos)
+ if test -d /usr/kerberos -a -f /usr/kerberos/lib/libkrb5.a; then
+ KRB5_LDFLAGS="-L/usr/kerberos/lib"
+ KRB5_CFLAGS="-I/usr/kerberos/include"
+ KRB5_CPPFLAGS="-I/usr/kerberos/include"
AC_MSG_RESULT(yes)
- LIBS="$LIBS -lkrb5"
- CFLAGS="$CFLAGS -I$withval/include"
- CPPFLAGS="$CPPFLAGS -I$withval/include"
- LDFLAGS="$LDFLAGS -L$withval/lib"
- FOUND_KRB5=yes
- ;;
- esac ],
- AC_MSG_RESULT(no)
- )
- fi
-
-if test x$FOUND_KRB5 = x"no"; then
-#################################################
-# see if this box has the SuSE location for the heimdal kerberos implementation
-AC_MSG_CHECKING(for /usr/include/heimdal)
-if test -d /usr/include/heimdal; then
- if test -f /usr/lib/heimdal/lib/libkrb5.a; then
- LIBS="$LIBS -lkrb5"
- CFLAGS="$CFLAGS -I/usr/include/heimdal"
- CPPFLAGS="$CPPFLAGS -I/usr/include/heimdal"
- LDFLAGS="$LDFLAGS -L/usr/lib/heimdal/lib"
- AC_MSG_RESULT(yes)
else
- LIBS="$LIBS -lkrb5"
- CFLAGS="$CFLAGS -I/usr/include/heimdal"
- CPPFLAGS="$CPPFLAGS -I/usr/include/heimdal"
- AC_MSG_RESULT(yes)
-
+ AC_MSG_RESULT(no)
fi
-else
- AC_MSG_RESULT(no)
-fi
-fi
+ fi
+ ac_save_CFLAGS=$CFLAGS
+ ac_save_CPPFLAGS=$CPPFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
-if test x$FOUND_KRB5 = x"no"; then
-#################################################
-# see if this box has the RedHat location for kerberos
-AC_MSG_CHECKING(for /usr/kerberos)
-if test -d /usr/kerberos -a -f /usr/kerberos/lib/libkrb5.a; then
- LIBS="$LIBS -lkrb5"
- LDFLAGS="$LDFLAGS -L/usr/kerberos/lib"
- CFLAGS="$CFLAGS -I/usr/kerberos/include"
- CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include"
- AC_MSG_RESULT(yes)
-else
- AC_MSG_RESULT(no)
-fi
-fi
+ CFLAGS="$CFLAGS $KRB5_CFLAGS"
+ CPPFLAGS="$CPPFLAGS $KRB5_CPPFLAGS"
+ LDFLAGS="$LDFLAGS $KRB5_LDFLAGS"
+
+ KRB5_LIBS="$KRB5_LDFLAGS $KRB5_LIBS"
# now check for krb5.h. Some systems have the libraries without the headers!
# note that this check is done here to allow for different kerberos
# include paths
AC_CHECK_HEADERS(krb5.h)
+ if test x"$ac_cv_header_krb5_h" = x"no"; then
+
+ # Give a warning if AD support was not explicitly requested,
+ # i.e with_ads_support = auto, otherwise die with an error.
+
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR([Active Directory cannot be supported without krb5.h])
+ else
+ AC_MSG_WARN([Active Directory cannot be supported without krb5.h])
+ fi
+
+ # Turn off AD support and restore CFLAGS and LIBS variables
+
+ with_ads_support="no"
+
+ CFLAGS=$ac_save_CFLAGS
+ CPPFLAGS=$ac_save_CPPFLAGS
+ LDFLAGS=$ac_save_LDFLAGS
+ fi
+fi
+
+# Now we have determined whether we really want ADS support
+
+if test x"$with_ads_support" != x"no"; then
+ ac_save_LIBS=$LIBS
+
# now check for gssapi headers. This is also done here to allow for
# different kerberos include paths
AC_CHECK_HEADERS(gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h com_err.h)
##################################################################
# we might need the k5crypto and com_err libraries on some systems
- AC_CHECK_LIB(com_err, _et_list, [LIBS="$LIBS -lcom_err"])
- AC_CHECK_LIB(k5crypto, krb5_encrypt_data, [LIBS="$LIBS -lk5crypto"])
- # Heimdal checks.
- AC_CHECK_LIB(crypto, des_set_key, [LIBS="$LIBS -lcrypto"])
- AC_CHECK_LIB(asn1, copy_Authenticator, [LIBS="$LIBS -lasn1 -lroken"])
- # Heimdal checks. On static Heimdal gssapi must be linked before krb5.
- AC_CHECK_LIB(gssapi, gss_display_status, [LIBS="$LIBS -lgssapi -lkrb5 -lasn1";
- AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available])])
-
- AC_CHECK_LIB(krb5, krb5_set_real_time, [AC_DEFINE(HAVE_KRB5_SET_REAL_TIME,1,[Whether krb5_set_real_time is available])])
- AC_CHECK_LIB(krb5, krb5_set_default_in_tkt_etypes, [AC_DEFINE(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES,1,[Whether krb5_set_default_in_tkt_etypes, is available])])
- AC_CHECK_LIB(krb5, krb5_set_default_tgs_ktypes, [AC_DEFINE(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES,1,[Whether krb5_set_default_tgs_ktypes is available])])
-
- AC_CHECK_LIB(krb5, krb5_principal2salt, [AC_DEFINE(HAVE_KRB5_PRINCIPAL2SALT,1,[Whether krb5_principal2salt is available])])
- AC_CHECK_LIB(krb5, krb5_use_enctype, [AC_DEFINE(HAVE_KRB5_USE_ENCTYPE,1,[Whether krb5_use_enctype is available])])
- AC_CHECK_LIB(krb5, krb5_string_to_key, [AC_DEFINE(HAVE_KRB5_STRING_TO_KEY,1,[Whether krb5_string_to_key is available])])
- AC_CHECK_LIB(krb5, krb5_get_pw_salt, [AC_DEFINE(HAVE_KRB5_GET_PW_SALT,1,[Whether krb5_get_pw_salt is available])])
- AC_CHECK_LIB(krb5, krb5_string_to_key_salt, [AC_DEFINE(HAVE_KRB5_STRING_TO_KEY_SALT,1,[Whether krb5_string_to_key_salt is available])])
- AC_CHECK_LIB(krb5, krb5_auth_con_setkey, [AC_DEFINE(HAVE_KRB5_AUTH_CON_SETKEY,1,[Whether krb5_auth_con_setkey is available])])
- AC_CHECK_LIB(krb5, krb5_auth_con_setuseruserkey, [AC_DEFINE(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY,1,[Whether krb5_auth_con_setuseruserkey is available])])
- AC_CHECK_LIB(krb5, krb5_locate_kdc, [AC_DEFINE(HAVE_KRB5_LOCATE_KDC,1,[Whether krb5_locate_kdc is available])])
- AC_CHECK_LIB(krb5, krb5_get_permitted_enctypes, [AC_DEFINE(HAVE_KRB5_GET_PERMITTED_ENCTYPES,1,[Whether krb5_get_permitted_enctypes is available])])
- AC_CHECK_LIB(krb5, krb5_get_default_in_tkt_etypes, [AC_DEFINE(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES,1,[Whether krb5_get_default_in_tkt_etypes is available])])
- AC_CHECK_LIB(krb5, krb5_free_ktypes, [AC_DEFINE(HAVE_KRB5_FREE_KTYPES,1,[Whether krb5_free_ktypes is available])])
-
-AC_CACHE_CHECK([for addrtype in krb5_address],samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS,[
-AC_TRY_COMPILE([#include <krb5.h>],
-[krb5_address kaddr; kaddr.addrtype = ADDRTYPE_INET;],
-samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=yes,samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=no)])
-if test x"$samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS" = x"yes"; then
- AC_DEFINE(HAVE_ADDRTYPE_IN_KRB5_ADDRESS,1,[Whether the krb5_address struct has a addrtype property])
-fi
-
-AC_CACHE_CHECK([for addr_type in krb5_address],samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,[
-AC_TRY_COMPILE([#include <krb5.h>],
-[krb5_address kaddr; kaddr.addr_type = KRB5_ADDRESS_INET;],
-samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=yes,samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=no)])
-if test x"$samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS" = x"yes"; then
- AC_DEFINE(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,1,[Whether the krb5_address struct has a addr_type property])
-fi
+ AC_CHECK_LIB_EXT(com_err, KRB5_LIBS, _et_list)
+ AC_CHECK_LIB_EXT(k5crypto, KRB5_LIBS, krb5_encrypt_data)
-AC_CACHE_CHECK([for enc_part2 in krb5_ticket],samba_cv_HAVE_KRB5_TKT_ENC_PART2,[
-AC_TRY_COMPILE([#include <krb5.h>],
-[krb5_ticket tkt; tkt.enc_part2->authorization_data[0]->contents = NULL;],
-samba_cv_HAVE_KRB5_TKT_ENC_PART2=yes,samba_cv_HAVE_KRB5_TKT_ENC_PART2=no)])
-if test x"$samba_cv_HAVE_KRB5_TKT_ENC_PART2" = x"yes"; then
- AC_DEFINE(HAVE_KRB5_TKT_ENC_PART2,1,[Whether the krb5_ticket struct has a enc_part2 property])
-fi
-
-AC_CACHE_CHECK([for keyvalue in krb5_keyblock],samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE,[
-AC_TRY_COMPILE([#include <krb5.h>],
-[krb5_keyblock key; key.keyvalue.data = NULL;],
-samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=yes,samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=no)])
-if test x"$samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE" = x"yes"; then
- AC_DEFINE(HAVE_KRB5_KEYBLOCK_KEYVALUE,1,[Whether the krb5_keyblock struct has a keyvalue property])
-fi
+ # Heimdal checks.
+ AC_CHECK_LIB_EXT(crypto, KRB5_LIBS, des_set_key)
+ AC_CHECK_LIB_EXT(asn1, KRB5_LIBS, copy_Authenticator)
+ AC_CHECK_LIB_EXT(roken, KRB5_LIBS, roken_getaddrinfo_hostspec)
-AC_CACHE_CHECK([for ENCTYPE_ARCFOUR_HMAC_MD5],samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,[
-AC_TRY_COMPILE([#include <krb5.h>],
-[krb5_enctype enctype; enctype = ENCTYPE_ARCFOUR_HMAC_MD5;],
-samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=yes,samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=no)])
-if test x"$samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5" = x"yes"; then
- AC_DEFINE(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,1,[Whether the ENCTYPE_ARCFOUR_HMAC_MD5 key type is available])
-fi
+ # Heimdal checks. On static Heimdal gssapi must be linked before krb5.
+ AC_CHECK_LIB_EXT(gssapi, KRB5_LIBS, gss_display_status,[],[],
+ AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available]))
########################################################
# now see if we can find the krb5 libs in standard paths
# or as specified above
- AC_CHECK_LIB(krb5, krb5_mk_req_extended, [LIBS="$LIBS -lkrb5";
- AC_DEFINE(HAVE_KRB5,1,[Whether KRB5 is available])])
+ AC_CHECK_LIB_EXT(krb5, KRB5_LIBS, krb5_mk_req_extended)
########################################################
# now see if we can find the gssapi libs in standard paths
- AC_CHECK_LIB(gssapi_krb5, gss_display_status, [LIBS="$LIBS -lgssapi_krb5";
- AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available])])
+ AC_CHECK_LIB_EXT(gssapi_krb5, KRB5_LIBS,gss_display_status,[],[],
+ AC_DEFINE(HAVE_GSSAPI,1,[Whether GSSAPI is available]))
-fi
+ AC_CHECK_FUNC_EXT(krb5_set_real_time, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_set_default_in_tkt_etypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_set_default_tgs_ktypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_principal2salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_use_enctype, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_string_to_key, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_pw_salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_string_to_key_salt, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_auth_con_setkey, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_auth_con_setuseruserkey, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_locate_kdc, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_permitted_enctypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_get_default_in_tkt_etypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_ktypes, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_free_data_contents, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_principal_get_comp_string, $KRB5_LIBS)
-########################################################
-# Compile with LDAP support?
+ LIBS="$LIBS $KRB5_LIBS"
+
+ AC_CACHE_CHECK([for addrtype in krb5_address],
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_address kaddr; kaddr.addrtype = ADDRTYPE_INET;],
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=yes,
+ samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS=no)])
-with_ldap_support=yes
-AC_MSG_CHECKING([whether to use LDAP])
+ if test x"$samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS" = x"yes"; then
+ AC_DEFINE(HAVE_ADDRTYPE_IN_KRB5_ADDRESS,1,
+ [Whether the krb5_address struct has a addrtype property])
+ fi
-AC_ARG_WITH(ldap,
-[ --with-ldap LDAP support (default yes)],
-[ case "$withval" in
- no)
- with_ldap_support=no
- ;;
- esac ])
+ AC_CACHE_CHECK([for addr_type in krb5_address],
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_address kaddr; kaddr.addr_type = KRB5_ADDRESS_INET;],
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=yes,
+ samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS=no)])
-AC_MSG_RESULT($with_ldap_support)
+ if test x"$samba_cv_HAVE_ADDR_TYPE_IN_KRB5_ADDRESS" = x"yes"; then
+ AC_DEFINE(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS,1,
+ [Whether the krb5_address struct has a addr_type property])
+ fi
-if test x"$with_ldap_support" = x"yes"; then
+ AC_CACHE_CHECK([for enc_part2 in krb5_ticket],
+ samba_cv_HAVE_KRB5_TKT_ENC_PART2,
+ [AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_ticket tkt; tkt.enc_part2->authorization_data[0]->contents = NULL;],
+ samba_cv_HAVE_KRB5_TKT_ENC_PART2=yes,samba_cv_HAVE_KRB5_TKT_ENC_PART2=no)])
- ##################################################################
- # we might need the lber lib on some systems. To avoid link errors
- # this test must be before the libldap test
- AC_CHECK_LIB(lber, ber_scanf, [LIBS="$LIBS -llber"])
+ if test x"$samba_cv_HAVE_KRB5_TKT_ENC_PART2" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_TKT_ENC_PART2,1,
+ [Whether the krb5_ticket struct has a enc_part2 property])
+ fi
- ########################################################
- # now see if we can find the ldap libs in standard paths
- if test x$have_ldap != xyes; then
- AC_CHECK_LIB(ldap, ldap_domain2hostlist, [LIBS="$LIBS -lldap";
- AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])])
-
- ########################################################
- # If we have LDAP, does it's rebind procedure take 2 or 3 arguments?
- # Check found in pam_ldap 145.
- AC_CHECK_FUNCS(ldap_set_rebind_proc)
- AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, pam_ldap_cv_ldap_set_rebind_proc, [
- AC_TRY_COMPILE([
- #include <lber.h>
- #include <ldap.h>], [ldap_set_rebind_proc(0, 0, 0);], [pam_ldap_cv_ldap_set_rebind_proc=3], [pam_ldap_cv_ldap_set_rebind_proc=2]) ])
- AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $pam_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc])
+ AC_CACHE_CHECK([for keyvalue in krb5_keyblock],
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keyblock key; key.keyvalue.data = NULL;],
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=yes,
+ samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYBLOCK_KEYVALUE,1,
+ [Whether the krb5_keyblock struct has a keyvalue property])
+ fi
+
+ AC_CACHE_CHECK([for ENCTYPE_ARCFOUR_HMAC_MD5],
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_enctype enctype; enctype = ENCTYPE_ARCFOUR_HMAC_MD5;],
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=yes,
+ samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5=no)])
+ AC_CACHE_CHECK([for KEYTYPE_ARCFOUR_56],
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytype keytype; keytype = KEYTYPE_ARCFOUR_56;],
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56=yes,
+ samba_cv_HAVE_KEYTYPE_ARCFOUR_56=no)])
+# Heimdals with KEYTYPE_ARCFOUR but not KEYTYPE_ARCFOUR_56 are broken
+# w.r.t. arcfour and windows, so we must not enable it here
+ if test x"$samba_cv_HAVE_ENCTYPE_ARCFOUR_HMAC_MD5" = x"yes" -a\
+ x"$samba_cv_HAVE_KEYTYPE_ARCFOUR_56" = x"yes"; then
+ AC_DEFINE(HAVE_ENCTYPE_ARCFOUR_HMAC_MD5,1,
+ [Whether the ENCTYPE_ARCFOUR_HMAC_MD5 key type is available])
+ fi
+
+ AC_CACHE_CHECK([for AP_OPTS_USE_SUBKEY],
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_flags ap_options; ap_options = AP_OPTS_USE_SUBKEY;],
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY=yes,
+ samba_cv_HAVE_AP_OPTS_USE_SUBKEY=no)])
+
+ if test x"$samba_cv_HAVE_AP_OPTS_USE_SUBKEY" = x"yes"; then
+ AC_DEFINE(HAVE_AP_OPTS_USE_SUBKEY,1,
+ [Whether the AP_OPTS_USE_SUBKEY ap option is available])
+ fi
+
+ AC_CACHE_CHECK([for the krb5_princ_component macro],
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT,[
+ AC_TRY_LINK([#include <krb5.h>],
+ [const krb5_data *pkdata; krb5_context context; krb5_principal principal; pkdata = krb5_princ_component(context, principal, 0);],
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT=yes,
+ samba_cv_HAVE_KRB5_PRINC_COMPONENT=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_PRINC_COMPONENT" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_PRINC_COMPONENT,1,
+ [Whether krb5_princ_component is available])
+ fi
+
+ AC_CACHE_CHECK([for memory keytab support],
+ samba_cv_HAVE_MEMORY_KEYTAB,[
+ AC_TRY_RUN([
+#include<krb5.h>
+ main()
+ {
+ krb5_context context;
+ krb5_keytab keytab;
+
+ krb5_init_context(&context);
+ if (krb5_kt_resolve(context, "MEMORY:", &keytab))
+ exit(1);
+ exit(0);
+ }],
+ samba_cv_HAVE_MEMORY_KEYTAB=yes,
+ samba_cv_HAVE_MEMORY_KEYTAB=no)])
+
+ if test x"$samba_cv_HAVE_MEMORY_KEYTAB" = x"yes"; then
+ AC_DEFINE(HAVE_MEMORY_KEYTAB,1,
+ [Whether in-memory keytabs are supported])
+ fi
+
+ AC_CACHE_CHECK([for key in krb5_keytab_entry],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; krb5_keyblock e; entry.key = e;],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY=yes,
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEY" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYTAB_ENTRY_KEY,1,
+ [Whether krb5_keytab_entry has key member])
+ fi
+
+ AC_CACHE_CHECK([for keyblock in krb5_keytab_entry],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_keytab_entry entry; entry.keyblock.keytype = 0;],
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK=yes,
+ samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK,1,
+ [Whether krb5_keytab_entry has keyblock member])
+ fi
+
+ if test x"$ac_cv_lib_ext_krb5_krb5_mk_req_extended" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5,1,[Whether to have KRB5 support])
+ AC_DEFINE(WITH_ADS,1,[Whether to include Active Directory support])
+ AC_MSG_CHECKING(whether Active Directory and KRB5 support is used)
+ AC_MSG_RESULT(yes)
+ else
+ if test x"$with_ads_support" = x"yes"; then
+ AC_MSG_ERROR(libkrb5 is needed for Active Directory support)
+ else
+ AC_MSG_WARN(libkrb5 is needed for Active Directory support)
+ fi
+ KRB5_LIBS=""
+ with_ads_support=no
fi
+ LIBS="$ac_save_LIBS"
fi
diff --git a/source4/libads/kerberos_verify.c b/source4/libads/kerberos_verify.c
index 9367f535395..8b319ee5544 100644
--- a/source4/libads/kerberos_verify.c
+++ b/source4/libads/kerberos_verify.c
@@ -4,6 +4,8 @@
Copyright (C) Andrew Tridgell 2001
Copyright (C) Remus Koos 2001
Copyright (C) Luke Howard 2003
+ Copyright (C) Guenther Deschner 2003
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
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
@@ -24,38 +26,181 @@
#ifdef HAVE_KRB5
+static void free_keytab(krb5_context context, krb5_keytab keytab)
+{
+ int ret=0;
+
+ if (keytab)
+ ret = krb5_kt_close(context, keytab);
+ if (ret) {
+ DEBUG(3, ("krb5_kt_close failed (%s)\n",
+ error_message(ret)));
+ }
+}
+
+#ifdef HAVE_MEMORY_KEYTAB
+static krb5_error_code create_keytab(krb5_context context,
+ krb5_principal host_princ,
+ char *host_princ_s,
+ krb5_data password,
+ krb5_enctype *enctypes,
+ krb5_keytab *keytab,
+ char *keytab_name)
+{
+ krb5_keytab_entry entry;
+ krb5_kvno kvno = 1;
+ krb5_error_code ret;
+ krb5_keyblock *key;
+ int i;
+
+ DEBUG(10,("creating keytab: %s\n", keytab_name));
+ ret = krb5_kt_resolve(context, keytab_name, keytab);
+ if (ret)
+ return ret;
+
+ if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
+ return ENOMEM;
+ }
+
+ /* add keytab entries for all encryption types */
+ for ( i=0; enctypes[i]; i++ ) {
+
+ if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) {
+ continue;
+ }
+
+ entry.principal = host_princ;
+ entry.vno = kvno;
+
+#if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)
+#error krb5_keytab_entry has no key or keyblock member
+#endif
+
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
+ entry.key = *key;
+#endif
+
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
+ entry.keyblock = *key;
+#endif
+
+ DEBUG(10,("adding keytab-entry for (%s) with encryption type (%d)\n",
+ host_princ_s, enctypes[i]));
+ ret = krb5_kt_add_entry(context, *keytab, &entry);
+ if (ret) {
+ DEBUG(1,("adding entry to keytab failed (%s)\n",
+ error_message(ret)));
+ free_keytab(context, *keytab);
+ return ret;
+ }
+ }
+ krb5_free_keyblock(context, key);
+
+ return 0;
+}
+#endif
+
+static BOOL setup_keytab(krb5_context context,
+ krb5_principal host_princ,
+ char *host_princ_s,
+ krb5_data password,
+ krb5_enctype *enctypes,
+ krb5_keytab *keytab)
+{
+ char *keytab_name = NULL;
+ krb5_error_code ret;
+
+ /* check if we have to setup a keytab - not currently enabled
+ I've put this in so that the else block below functions
+ the same way that it will when this code is turned on */
+ if (0 /* will later be *lp_keytab() */) {
+
+ /* use a file-keytab */
+ asprintf(&keytab_name, "%s:%s",
+ ""
+ /* KRB5_KT_FILE_PREFIX, "FILE" or
+ "WRFILE" depending on HEeimdal or MIT */,
+ "" /* will later be lp_keytab() */);
+
+ DEBUG(10,("will use filebased keytab: %s\n", keytab_name));
+ ret = krb5_kt_resolve(context, keytab_name, keytab);
+ if (ret) {
+ DEBUG(3,("cannot resolve keytab name %s (%s)\n",
+ keytab_name,
+ error_message(ret)));
+ SAFE_FREE(keytab_name);
+ return False;
+ }
+
+ }
+
+#if defined(HAVE_MEMORY_KEYTAB)
+ else {
+
+ /* setup a in-memory-keytab */
+ asprintf(&keytab_name, "MEMORY:");
+
+ ret = create_keytab(context, host_princ, host_princ_s, password, enctypes,
+ keytab, keytab_name);
+ if (ret) {
+ DEBUG(3,("unable to create MEMORY: keytab (%s)\n",
+ error_message(ret)));
+ SAFE_FREE(keytab_name);
+ return False;
+ }
+ }
+#endif
+ SAFE_FREE(keytab_name);
+ return True;
+}
+
+
/*
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,
+NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
char **principal, DATA_BLOB *auth_data,
DATA_BLOB *ap_rep,
- uint8 session_key[16])
+ DATA_BLOB *session_key)
{
- krb5_context context;
+ NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
+ krb5_context context = NULL;
krb5_auth_context auth_context = NULL;
krb5_keytab keytab = NULL;
krb5_data packet;
krb5_ticket *tkt = NULL;
+ krb5_rcache rcache = NULL;
int ret, i;
- krb5_keyblock * key;
+ krb5_keyblock *key = NULL;
+
krb5_principal host_princ;
- char *host_princ_s;
+ char *host_princ_s = NULL;
+ BOOL free_host_princ = False;
+
fstring myname;
- char *password_s;
+ char *password_s = NULL;
krb5_data password;
krb5_enctype *enctypes = NULL;
+#if 0
+ krb5_address local_addr;
+ krb5_address remote_addr;
+#endif
BOOL auth_ok = False;
+ ZERO_STRUCT(packet);
+ ZERO_STRUCT(password);
+ ZERO_STRUCTP(auth_data);
+ ZERO_STRUCTP(ap_rep);
+
if (!secrets_init()) {
- DEBUG(1,("secrets_init failed\n"));
+ DEBUG(1,("ads_verify_ticket: secrets_init failed\n"));
return NT_STATUS_LOGON_FAILURE;
}
- password_s = secrets_fetch_machine_password();
+ password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
if (!password_s) {
- DEBUG(1,("failed to fetch machine password\n"));
+ DEBUG(1,("ads_verify_ticket: failed to fetch machine password\n"));
return NT_STATUS_LOGON_FAILURE;
}
@@ -64,83 +209,142 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
ret = krb5_init_context(&context);
if (ret) {
- DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
+ DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
return NT_STATUS_LOGON_FAILURE;
}
- ret = krb5_set_default_realm(context, ads->auth.realm);
+ ret = krb5_set_default_realm(context, realm);
if (ret) {
- DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
- return NT_STATUS_LOGON_FAILURE;
+ DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
- /* this whole process is far more complex than I would
+ /* 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;
+ DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
- fstrcpy(myname, lp_netbios_name());
- strlower(myname);
+ fstrcpy(myname, global_myname());
+ strlower_m(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;
+ DEBUG(1,("ads_verify_ticket: krb5_parse_name(%s) failed (%s)\n",
+ host_princ_s, error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
- if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
- return NT_STATUS_NO_MEMORY;
+ free_host_princ = True;
+
+ /*
+ * JRA. We must set the rcache here. This will prevent replay attacks.
+ */
+
+ ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
-
+
+ ret = krb5_auth_con_setrcache(context, auth_context, rcache);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ /* CIFS doesn't use addresses in tickets. This would breat NAT. JRA */
+
if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) {
- DEBUG(1,("krb5_get_permitted_enctypes failed (%s)\n",
+ DEBUG(1,("ads_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n",
error_message(ret)));
- return NT_STATUS_LOGON_FAILURE;
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
- /* we need to setup a auth context with each possible encoding type in turn */
+ /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
+ * code surrounding the replay cache... */
+
+ if (!grab_server_mutex("replay cache mutex")) {
+ DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n"));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ if (!setup_keytab(context, host_princ, host_princ_s, password,
+ enctypes, &keytab)) {
+ DEBUG(3,("ads_verify_ticket: unable to setup keytab\n"));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ /* We need to setup a auth context with each possible encoding type in turn. */
for (i=0;enctypes[i];i++) {
+ if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
+ sret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) {
continue;
}
krb5_auth_con_setuseruserkey(context, auth_context, key);
+ krb5_free_keyblock(context, key);
+
packet.length = ticket->length;
packet.data = (krb5_pointer)ticket->data;
if (!(ret = krb5_rd_req(context, &auth_context, &packet,
- NULL, keytab, NULL, &tkt))) {
- free_kerberos_etypes(context, enctypes);
+#ifdef HAVE_MEMORY_KEYTAB
+ host_princ,
+#else
+ NULL,
+#endif
+ keytab, NULL, &tkt))) {
+ DEBUG(10,("ads_verify_ticket: enc type [%u] decrypted message !\n",
+ (unsigned int)enctypes[i] ));
auth_ok = True;
break;
}
+
+ DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
+ ("ads_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
+ (unsigned int)enctypes[i], error_message(ret)));
}
+ release_server_mutex();
+
if (!auth_ok) {
- DEBUG(3,("krb5_rd_req with auth failed (%s)\n",
+ DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n",
error_message(ret)));
- return NT_STATUS_LOGON_FAILURE;
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
ret = krb5_mk_rep(context, auth_context, &packet);
if (ret) {
- DEBUG(3,("Failed to generate mutual authentication reply (%s)\n",
+ DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
error_message(ret)));
- krb5_auth_con_free(context, auth_context);
- return NT_STATUS_LOGON_FAILURE;
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
}
*ap_rep = data_blob(packet.data, packet.length);
free(packet.data);
- krb5_get_smb_session_key(context, auth_context, session_key);
- DEBUG(0,("SMB session key (from ticket) follows:\n"));
- dump_data(0, session_key, 16);
+ get_krb5_smb_session_key(context, auth_context, session_key, True);
+ dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);
#if 0
file_save("/tmp/ticket.dat", ticket->data, ticket->length);
@@ -149,25 +353,59 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket,
get_auth_data_from_tkt(auth_data, tkt);
#if 0
+ {
+ TALLOC_CTX *ctx = talloc_init("pac data");
+ decode_pac_data(auth_data, ctx);
+ talloc_destroy(ctx);
+ }
+#endif
+
+#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
+
+ /* get rid of all resources associated with the keytab */
+ if (keytab) free_keytab(context, keytab);
+
if ((ret = krb5_unparse_name(context, get_principal_from_tkt(tkt),
principal))) {
- DEBUG(3,("krb5_unparse_name failed (%s)\n",
+ DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n",
error_message(ret)));
+ sret = NT_STATUS_LOGON_FAILURE;
+ goto out;
+ }
+
+ sret = NT_STATUS_OK;
+
+ out:
+
+ if (!NT_STATUS_IS_OK(sret))
data_blob_free(auth_data);
+
+ if (!NT_STATUS_IS_OK(sret))
data_blob_free(ap_rep);
+
+ if (free_host_princ)
+ krb5_free_principal(context, host_princ);
+
+ if (tkt != NULL)
+ krb5_free_ticket(context, tkt);
+ free_kerberos_etypes(context, enctypes);
+ SAFE_FREE(password_s);
+ SAFE_FREE(host_princ_s);
+
+ if (auth_context)
krb5_auth_con_free(context, auth_context);
- return NT_STATUS_LOGON_FAILURE;
- }
- krb5_auth_con_free(context, auth_context);
+ if (context)
+ krb5_free_context(context);
- return NT_STATUS_OK;
+ return sret;
}
#endif /* HAVE_KRB5 */
diff --git a/source4/libads/krb5_setpw.c b/source4/libads/krb5_setpw.c
index 9d8fb8d24cb..9cf15221a8d 100644
--- a/source4/libads/krb5_setpw.c
+++ b/source4/libads/krb5_setpw.c
@@ -143,7 +143,7 @@ static krb5_error_code build_kpasswd_request(uint16 pversion,
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,
@@ -178,47 +178,39 @@ static krb5_error_code build_kpasswd_request(uint16 pversion,
return 0;
}
-static krb5_error_code krb5_setpw_result_code_string(krb5_context context,
- int result_code,
- char **code_string)
+static const struct kpasswd_errors {
+ int result_code;
+ const char *error_string;
+} kpasswd_errors[] = {
+ {KRB5_KPASSWD_MALFORMED, "Malformed request error"},
+ {KRB5_KPASSWD_HARDERROR, "Server error"},
+ {KRB5_KPASSWD_AUTHERROR, "Authentication error"},
+ {KRB5_KPASSWD_SOFTERROR, "Password change rejected"},
+ {KRB5_KPASSWD_ACCESSDENIED, "Client does not have proper authorization"},
+ {KRB5_KPASSWD_BAD_VERSION, "Protocol version not supported"},
+ {KRB5_KPASSWD_INITIAL_FLAG_NEEDED, "Authorization ticket must have initial flag set"},
+ {KRB5_KPASSWD_POLICY_REJECT, "Password rejected due to policy requirements"},
+ {KRB5_KPASSWD_BAD_PRINCIPAL, "Target principal does not exist"},
+ {KRB5_KPASSWD_ETYPE_NOSUPP, "Unsupported encryption type"},
+ {0, NULL}
+};
+
+static krb5_error_code setpw_result_code_string(krb5_context context,
+ int result_code,
+ const char **code_string)
{
- switch (result_code) {
- case KRB5_KPASSWD_MALFORMED:
- *code_string = "Malformed request error";
- break;
- case KRB5_KPASSWD_HARDERROR:
- *code_string = "Server error";
- break;
- case KRB5_KPASSWD_AUTHERROR:
- *code_string = "Authentication error";
- break;
- case KRB5_KPASSWD_SOFTERROR:
- *code_string = "Password change rejected";
- break;
- case KRB5_KPASSWD_ACCESSDENIED:
- *code_string = "Client does not have proper authorization";
- break;
- case KRB5_KPASSWD_BAD_VERSION:
- *code_string = "Protocol version not supported";
- break;
- case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
- *code_string = "Authorization ticket must have initial flag set";
- break;
- case KRB5_KPASSWD_POLICY_REJECT:
- *code_string = "Password rejected due to policy requirements";
- break;
- case KRB5_KPASSWD_BAD_PRINCIPAL:
- *code_string = "Target principal does not exist";
- break;
- case KRB5_KPASSWD_ETYPE_NOSUPP:
- *code_string = "Unsupported encryption type";
- break;
- default:
- *code_string = "Password change failed";
- break;
- }
-
- return(0);
+ unsigned int idx = 0;
+
+ while (kpasswd_errors[idx].error_string != NULL) {
+ if (kpasswd_errors[idx].result_code ==
+ result_code) {
+ *code_string = kpasswd_errors[idx].error_string;
+ return 0;
+ }
+ idx++;
+ }
+ *code_string = "Password change failed";
+ return (0);
}
static krb5_error_code parse_setpw_reply(krb5_context context,
@@ -318,8 +310,8 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
if(res_code == KRB5_KPASSWD_SUCCESS)
return 0;
else {
- char *errstr;
- krb5_setpw_result_code_string(context, res_code, &errstr);
+ const char *errstr;
+ setpw_result_code_string(context, res_code, &errstr);
DEBUG(1, ("Error changing password: %s\n", errstr));
switch(res_code) {
@@ -465,8 +457,8 @@ static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
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;
@@ -546,7 +538,6 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
krb5_free_creds(context, credsp);
krb5_free_principal(context, creds.client);
- krb5_free_principal(context, creds.server);
krb5_free_principal(context, principal);
krb5_free_context(context);
@@ -579,11 +570,11 @@ kerb_prompter(krb5_context ctx, void *data,
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;
@@ -657,11 +648,11 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server,
}
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);
}
@@ -673,24 +664,22 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server,
* @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;
diff --git a/source4/libads/ldap.c b/source4/libads/ldap.c
index 0bcd76cb9f7..8039d3d1d40 100644
--- a/source4/libads/ldap.c
+++ b/source4/libads/ldap.c
@@ -3,7 +3,7 @@
ads (active directory) utility library
Copyright (C) Andrew Tridgell 2001
Copyright (C) Remus Koos 2001
- Copyright (C) Jim McDonough 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
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
@@ -41,6 +41,9 @@
/*
try a connection to a given ldap server, returning True and setting the servers IP
in the ads struct if successful
+
+ TODO : add a negative connection cache in here leveraged off of the one
+ found in the rpc code. --jerry
*/
static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
{
@@ -90,133 +93,94 @@ static BOOL ads_try_connect_uri(ADS_STRUCT *ads)
return False;
}
-/* used by the IP comparison function */
-struct ldap_ip {
- struct in_addr ip;
- unsigned port;
-};
+/**********************************************************************
+ Try to find an AD dc using our internal name resolution routines
+ Try the realm first and then then workgroup name if netbios is not
+ disabled
+**********************************************************************/
-/* compare 2 ldap IPs by nearness to our interfaces - used in qsort */
-static int ldap_ip_compare(struct ldap_ip *ip1, struct ldap_ip *ip2)
-{
- return ip_compare(&ip1->ip, &ip2->ip);
-}
-
-/* try connecting to a ldap server via DNS */
-static BOOL ads_try_dns(ADS_STRUCT *ads)
+static BOOL ads_find_dc(ADS_STRUCT *ads)
{
const char *c_realm;
- const char *ptr;
- char *realm;
- char *list = NULL;
- pstring tok;
- struct ldap_ip *ip_list;
int count, i=0;
+ struct ip_service *ip_list;
+ pstring realm;
+ BOOL got_realm = False;
+ BOOL use_own_domain = False;
+
+ /* if the realm and workgroup are both empty, assume they are ours */
+ /* realm */
c_realm = ads->server.realm;
- if (!c_realm || !*c_realm) {
- c_realm = lp_realm();
+
+ if ( !c_realm || !*c_realm ) {
+ /* special case where no realm and no workgroup means our own */
+ if ( !ads->server.workgroup || !*ads->server.workgroup ) {
+ use_own_domain = True;
+ c_realm = lp_realm();
+ }
}
- if (!c_realm || !*c_realm) {
+
+ if (c_realm && *c_realm)
+ got_realm = True;
+
+again:
+ /* we need to try once with the realm name and fallback to the
+ netbios domain name if we fail (if netbios has not been disabled */
+
+ if ( !got_realm && !lp_disable_netbios() ) {
c_realm = ads->server.workgroup;
- }
- if (!c_realm || !*c_realm) {
- c_realm = lp_workgroup();
- }
- if (!c_realm) {
- return False;
- }
- realm = smb_xstrdup(c_realm);
-
- DEBUG(6,("ads_try_dns: looking for realm '%s'\n", realm));
- if (ldap_domain2hostlist(realm, &list) != LDAP_SUCCESS) {
- SAFE_FREE(realm);
- return False;
- }
-
- DEBUG(6,("ads_try_dns: ldap realm '%s' host list '%s'\n", realm, list));
- SAFE_FREE(realm);
-
- count = count_chars(list, ' ') + 1;
- ip_list = malloc(count * sizeof(struct ldap_ip));
- if (!ip_list) {
- return False;
- }
-
- ptr = list;
- while (next_token(&ptr, tok, " ", sizeof(tok))) {
- unsigned port = LDAP_PORT;
- char *p = strchr(tok, ':');
- if (p) {
- *p = 0;
- port = atoi(p+1);
+ if (!c_realm || !*c_realm) {
+ if ( use_own_domain )
+ c_realm = lp_workgroup();
}
- ip_list[i].ip = *interpret_addr2(tok);
- ip_list[i].port = port;
- if (!is_zero_ip(ip_list[i].ip)) {
- i++;
+
+ if ( !c_realm || !*c_realm ) {
+ DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
+ return False;
}
}
- free(list);
+
+ pstrcpy( realm, c_realm );
- count = i;
+ DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
+ (got_realm ? "realm" : "domain"), realm));
- /* we sort the list of addresses by closeness to our interfaces. This
- tries to prevent us using a DC on the other side of the country */
- if (count > 1) {
- qsort(ip_list, count, sizeof(struct ldap_ip),
- QSORT_CAST ldap_ip_compare);
+ if ( !get_sorted_dc_list(realm, &ip_list, &count, got_realm) ) {
+ /* fall back to netbios if we can */
+ if ( got_realm && !lp_disable_netbios() ) {
+ got_realm = False;
+ goto again;
+ }
+
+ return False;
}
-
- for (i=0;i<count;i++) {
- if (ads_try_connect(ads, inet_ntoa(ip_list[i].ip), ip_list[i].port)) {
- free(ip_list);
+
+ /* if we fail this loop, then giveup since all the IP addresses returned were dead */
+ for ( i=0; i<count; i++ ) {
+ /* since this is an ads conection request, default to LDAP_PORT is not set */
+ int port = (ip_list[i].port!=PORT_NONE) ? ip_list[i].port : LDAP_PORT;
+ fstring server;
+
+ fstrcpy( server, inet_ntoa(ip_list[i].ip) );
+
+ if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
+ continue;
+
+ if ( ads_try_connect(ads, server, port) ) {
+ SAFE_FREE(ip_list);
return True;
}
+
+ /* keep track of failures */
+ add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
}
SAFE_FREE(ip_list);
+
return False;
}
-/* try connecting to a ldap server via netbios */
-static BOOL ads_try_netbios(ADS_STRUCT *ads)
-{
- struct in_addr *ip_list, pdc_ip;
- int count;
- int i;
- const char *workgroup = ads->server.workgroup;
- BOOL list_ordered;
-
- if (!workgroup) {
- workgroup = lp_workgroup();
- }
-
- DEBUG(6,("ads_try_netbios: looking for workgroup '%s'\n", workgroup));
-
- /* try the PDC first */
- if (get_pdc_ip(workgroup, &pdc_ip)) {
- DEBUG(6,("ads_try_netbios: trying server '%s'\n",
- inet_ntoa(pdc_ip)));
- if (ads_try_connect(ads, inet_ntoa(pdc_ip), LDAP_PORT))
- return True;
- }
-
- /* now any DC, including backups */
- if (get_dc_list(workgroup, &ip_list, &count, &list_ordered)) {
- for (i=0;i<count;i++) {
- DEBUG(6,("ads_try_netbios: trying server '%s'\n",
- inet_ntoa(ip_list[i])));
- if (ads_try_connect(ads, inet_ntoa(ip_list[i]), LDAP_PORT)) {
- free(ip_list);
- return True;
- }
- }
- free(ip_list);
- }
-
- return False;
-}
/**
* Connect to the LDAP server
@@ -244,20 +208,7 @@ ADS_STATUS ads_connect(ADS_STRUCT *ads)
goto got_connection;
}
- /* try with a smb.conf ads server setting if we are connecting
- to the primary workgroup or realm */
- if (!ads->server.foreign &&
- ads_try_connect(ads, lp_ads_server(), LDAP_PORT)) {
- goto got_connection;
- }
-
- /* try via DNS */
- if (ads_try_dns(ads)) {
- goto got_connection;
- }
-
- /* try via netbios lookups */
- if (!lp_disable_netbios() && ads_try_netbios(ads)) {
+ if (ads_find_dc(ads)) {
goto got_connection;
}
@@ -277,8 +228,8 @@ got_connection:
if (!ads->auth.user_name) {
/* by default use the machine account */
fstring myname;
- fstrcpy(myname, lp_netbios_name());
- strlower(myname);
+ fstrcpy(myname, global_myname());
+ strlower_m(myname);
asprintf(&ads->auth.user_name, "HOST/%s", myname);
}
@@ -400,8 +351,8 @@ static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
* again when the entire search is complete
* @param ads connection to ads server
* @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression - specified in local charset
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
* @param attrs Attributes to retrieve - specified in utf8 or ascii
* @param res ** which will contain results - free res* with ads_msgfree()
* @param count Number of entries retrieved on this page
@@ -409,12 +360,12 @@ static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
* @return status of search
**/
ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
- int scope, const char *exp,
+ int scope, const char *expr,
const char **attrs, void **res,
int *count, void **cookie)
{
int rc, i, version;
- char *utf8_exp, *utf8_path, **search_attrs;
+ char *utf8_expr, *utf8_path, **search_attrs;
LDAPControl PagedResults, NoReferrals, *controls[3], **rcontrols;
BerElement *cookie_be = NULL;
struct berval *cookie_bv= NULL;
@@ -428,7 +379,7 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
/* 0 means the conversion worked but the result was empty
so we only fail if it's -1. In any case, it always
at least nulls out the dest */
- if ((push_utf8_talloc(ctx, &utf8_exp, exp) == (size_t)-1) ||
+ if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
(push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
rc = LDAP_NO_MEMORY;
goto done;
@@ -489,7 +440,7 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
*/
ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
- rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_exp,
+ rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_expr,
search_attrs, 0, controls,
NULL, NULL, LDAP_NO_LIMIT, (LDAPMessage **)res);
@@ -497,7 +448,7 @@ ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
ber_bvfree(cookie_bv);
if (rc) {
- DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", exp, ldap_err2string(rc)));
+ DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", expr, ldap_err2string(rc)));
goto done;
}
@@ -540,21 +491,21 @@ done:
* all entries in a large search.
* @param ads connection to ads server
* @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
* @param attrs Attributes to retrieve
* @param res ** which will contain results - free res* with ads_msgfree()
* @return status of search
**/
ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
- int scope, const char *exp,
+ int scope, const char *expr,
const char **attrs, void **res)
{
void *cookie = NULL;
int count = 0;
ADS_STATUS status;
- status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, res,
+ status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, res,
&count, &cookie);
if (!ADS_ERR_OK(status)) return status;
@@ -564,7 +515,7 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
ADS_STATUS status2;
LDAPMessage *msg, *next;
- status2 = ads_do_paged_search(ads, bind_path, scope, exp,
+ status2 = ads_do_paged_search(ads, bind_path, scope, expr,
attrs, &res2, &count, &cookie);
if (!ADS_ERR_OK(status2)) break;
@@ -587,15 +538,15 @@ ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
* runs the function as each page is returned, using ads_process_results()
* @param ads connection to ads server
* @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression - specified in local charset
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression - specified in local charset
* @param attrs Attributes to retrieve - specified in UTF-8 or ascii
* @param fn Function which takes attr name, values list, and data_area
* @param data_area Pointer which is passed to function on each call
* @return status of search
**/
ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
- int scope, const char *exp, const char **attrs,
+ int scope, const char *expr, const char **attrs,
BOOL(*fn)(char *, void **, void *),
void *data_area)
{
@@ -604,7 +555,7 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
ADS_STATUS status;
void *res;
- status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, &res,
+ status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, &res,
&count, &cookie);
if (!ADS_ERR_OK(status)) return status;
@@ -613,7 +564,7 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
ads_msgfree(ads, res);
while (cookie) {
- status = ads_do_paged_search(ads, bind_path, scope, exp, attrs,
+ status = ads_do_paged_search(ads, bind_path, scope, expr, attrs,
&res, &count, &cookie);
if (!ADS_ERR_OK(status)) break;
@@ -629,19 +580,19 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
* Do a search with a timeout.
* @param ads connection to ads server
* @param bind_path Base dn for the search
- * @param scope Scope of search (LDAP_BASE | LDAP_ONE | LDAP_SUBTREE)
- * @param exp Search expression
+ * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
+ * @param expr Search expression
* @param attrs Attributes to retrieve
* @param res ** which will contain results - free res* with ads_msgfree()
* @return status of search
**/
ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
- const char *exp,
+ const char *expr,
const char **attrs, void **res)
{
struct timeval timeout;
int rc;
- char *utf8_exp, *utf8_path, **search_attrs = NULL;
+ char *utf8_expr, *utf8_path, **search_attrs = NULL;
TALLOC_CTX *ctx;
if (!(ctx = talloc_init("ads_do_search"))) {
@@ -652,7 +603,7 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
/* 0 means the conversion worked but the result was empty
so we only fail if it's negative. In any case, it always
at least nulls out the dest */
- if ((push_utf8_talloc(ctx, &utf8_exp, exp) == (size_t)-1) ||
+ if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
(push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
DEBUG(1,("ads_do_search: push_utf8_talloc() failed!"));
rc = LDAP_NO_MEMORY;
@@ -679,7 +630,7 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
/* see the note in ads_do_paged_search - we *must* disable referrals */
ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
- rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_exp,
+ rc = ldap_search_ext_s(ads->ld, utf8_path, scope, utf8_expr,
search_attrs, 0, NULL, NULL,
&timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
@@ -698,16 +649,16 @@ ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
* Do a general ADS search
* @param ads connection to ads server
* @param res ** which will contain results - free res* with ads_msgfree()
- * @param exp Search expression
+ * @param expr Search expression
* @param attrs Attributes to retrieve
* @return status of search
**/
ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
- const char *exp,
+ const char *expr,
const char **attrs)
{
return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
- exp, attrs, res);
+ expr, attrs, res);
}
/**
@@ -749,15 +700,25 @@ void ads_memfree(ADS_STRUCT *ads, void *mem)
/**
* Get a dn from search results
* @param ads connection to ads server
- * @param res Search results
+ * @param msg Search result
* @return dn string
**/
-char *ads_get_dn(ADS_STRUCT *ads, void *res)
+char *ads_get_dn(ADS_STRUCT *ads, void *msg)
{
char *utf8_dn, *unix_dn;
- utf8_dn = ldap_get_dn(ads->ld, res);
- pull_utf8_allocate((void **) &unix_dn, utf8_dn);
+ utf8_dn = ldap_get_dn(ads->ld, msg);
+
+ if (!utf8_dn) {
+ DEBUG (5, ("ads_get_dn: ldap_get_dn failed\n"));
+ return NULL;
+ }
+
+ if (pull_utf8_allocate(&unix_dn, utf8_dn) == (size_t)-1) {
+ DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n",
+ utf8_dn ));
+ return NULL;
+ }
ldap_memfree(utf8_dn);
return unix_dn;
}
@@ -772,18 +733,18 @@ char *ads_get_dn(ADS_STRUCT *ads, void *res)
ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
{
ADS_STATUS status;
- char *exp;
+ char *expr;
const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
/* the easiest way to find a machine account anywhere in the tree
is to look for hostname$ */
- if (asprintf(&exp, "(samAccountName=%s$)", host) == -1) {
+ if (asprintf(&expr, "(samAccountName=%s$)", host) == -1) {
DEBUG(1, ("asprintf failed!\n"));
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- status = ads_search(ads, res, exp, attrs);
- free(exp);
+ status = ads_search(ads, res, expr, attrs);
+ free(expr);
return status;
}
@@ -998,7 +959,7 @@ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- ret = ldap_delete(ads->ld, utf8_dn);
+ ret = ldap_delete_s(ads->ld, utf8_dn);
return ADS_ERROR(ret);
}
@@ -1011,7 +972,7 @@ ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
**/
char *ads_ou_string(const char *org_unit)
{
- if (!org_unit || !*org_unit || strcasecmp(org_unit, "Computers") == 0) {
+ if (!org_unit || !*org_unit || strequal(org_unit, "Computers")) {
return strdup("cn=Computers");
}
@@ -1024,6 +985,7 @@ char *ads_ou_string(const char *org_unit)
add a machine account to the ADS server
*/
static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
+ uint32 account_type,
const char *org_unit)
{
ADS_STATUS ret, status;
@@ -1036,6 +998,14 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
const char *servicePrincipalName[5] = {NULL, NULL, NULL, NULL, NULL};
char *psp, *psp2;
unsigned acct_control;
+ unsigned exists=0;
+ LDAPMessage *res;
+
+ status = ads_find_machine_acct(ads, (void **)&res, hostname);
+ if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
+ DEBUG(0, ("Host account for %s already exists - modifying old account\n", hostname));
+ exists=1;
+ }
if (!(ctx = talloc_init("machine_account")))
return ADS_ERROR(LDAP_NO_MEMORY);
@@ -1057,13 +1027,13 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
psp = talloc_asprintf(ctx, "HOST/%s.%s",
hostname,
ads->config.realm);
- strlower(&psp[5]);
+ strlower_m(&psp[5]);
servicePrincipalName[1] = psp;
servicePrincipalName[2] = talloc_asprintf(ctx, "CIFS/%s", hostname);
psp2 = talloc_asprintf(ctx, "CIFS/%s.%s",
hostname,
ads->config.realm);
- strlower(&psp2[5]);
+ strlower_m(&psp2[5]);
servicePrincipalName[3] = psp2;
free(ou_str);
@@ -1073,27 +1043,33 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
goto done;
- acct_control = UF_WORKSTATION_TRUST_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
+ acct_control = account_type | UF_DONT_EXPIRE_PASSWD;
#ifndef ENCTYPE_ARCFOUR_HMAC
acct_control |= UF_USE_DES_KEY_ONLY;
#endif
+
if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control)))
goto done;
if (!(mods = ads_init_mods(ctx)))
goto done;
-
- ads_mod_str(ctx, &mods, "cn", hostname);
- ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
- ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
+
+ if (!exists) {
+ ads_mod_str(ctx, &mods, "cn", hostname);
+ ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
+ ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
+ ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
+ }
+ ads_mod_str(ctx, &mods, "dNSHostName", hostname);
ads_mod_str(ctx, &mods, "userPrincipalName", host_upn);
ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
- ads_mod_str(ctx, &mods, "dNSHostName", hostname);
- ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
ads_mod_str(ctx, &mods, "operatingSystem", "Samba");
- ads_mod_str(ctx, &mods, "operatingSystemVersion", VERSION);
+ ads_mod_str(ctx, &mods, "operatingSystemVersion", SAMBA_VERSION_STRING);
- ret = ads_gen_add(ads, new_dn, mods);
+ if (!exists)
+ ret = ads_gen_add(ads, new_dn, mods);
+ else
+ ret = ads_gen_mod(ads, new_dn, mods);
if (!ADS_ERR_OK(ret))
goto done;
@@ -1102,11 +1078,13 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
* it shouldn't be mandatory and probably we just
* don't have enough rights to do it.
*/
- status = ads_set_machine_sd(ads, hostname, new_dn);
-
- if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
- ads_errstr(status)));
+ if (!exists) {
+ status = ads_set_machine_sd(ads, hostname, new_dn);
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(0, ("Warning: ads_set_machine_sd: %s\n",
+ ads_errstr(status)));
+ }
}
done:
talloc_destroy(ctx);
@@ -1139,14 +1117,10 @@ static void dump_guid(const char *field, struct berval **values)
{
int i;
GUID guid;
- TALLOC_CTX *mem_ctx;
- mem_ctx = talloc_init("dump_guid");
- if (!mem_ctx) return;
for (i=0; values[i]; i++) {
memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
- printf("%s: %s\n", field, uuid_string(mem_ctx, guid));
+ printf("%s: %s\n", field, smb_uuid_string_static(guid));
}
- talloc_destroy(mem_ctx);
}
/*
@@ -1339,7 +1313,8 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
* @param org_unit Organizational unit to place machine in
* @return status of join
**/
-ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
+ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname,
+ uint32 account_type, const char *org_unit)
{
ADS_STATUS status;
LDAPMessage *res;
@@ -1347,8 +1322,9 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
/* hostname must be lowercase */
host = strdup(hostname);
- strlower(host);
+ strlower_m(host);
+ /*
status = ads_find_machine_acct(ads, (void **)&res, host);
if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
DEBUG(0, ("Host account for %s already exists - deleting old account\n", host));
@@ -1359,8 +1335,9 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
return status;
}
}
+ */
- status = ads_add_machine_acct(ads, host, org_unit);
+ status = ads_add_machine_acct(ads, host, account_type, org_unit);
if (!ADS_ERR_OK(status)) {
DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
return status;
@@ -1386,13 +1363,13 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org
ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
{
ADS_STATUS status;
- void *res;
+ void *res, *msg;
char *hostnameDN, *host;
int rc;
/* hostname must be lowercase */
host = strdup(hostname);
- strlower(host);
+ strlower_m(host);
status = ads_find_machine_acct(ads, &res, host);
if (!ADS_ERR_OK(status)) {
@@ -1400,7 +1377,12 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
return status;
}
- hostnameDN = ads_get_dn(ads, (LDAPMessage *)res);
+ msg = ads_first_entry(ads, res);
+ if (!msg) {
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
+
+ hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg);
rc = ldap_delete_s(ads->ld, hostnameDN);
ads_memfree(ads, hostnameDN);
if (rc != LDAP_SUCCESS) {
@@ -1428,7 +1410,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
{
const char *attrs[] = {"nTSecurityDescriptor", "objectSid", 0};
- char *exp = 0;
+ char *expr = 0;
size_t sd_size = 0;
struct berval bval = {0, NULL};
prs_struct ps_wire;
@@ -1456,7 +1438,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- if (asprintf(&exp, "(samAccountName=%s$)", escaped_hostname) == -1) {
+ if (asprintf(&expr, "(samAccountName=%s$)", escaped_hostname) == -1) {
DEBUG(1, ("ads_set_machine_sd: asprintf failed!\n"));
SAFE_FREE(escaped_hostname);
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
@@ -1464,7 +1446,7 @@ ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
SAFE_FREE(escaped_hostname);
- ret = ads_search(ads, (void *) &res, exp, attrs);
+ ret = ads_search(ads, (void *) &res, expr, attrs);
if (!ADS_ERR_OK(ret)) return ret;
@@ -1597,27 +1579,26 @@ char *ads_pull_string(ADS_STRUCT *ads,
* @return Result strings in talloc context
**/
char **ads_pull_strings(ADS_STRUCT *ads,
- TALLOC_CTX *mem_ctx, void *msg, const char *field)
+ TALLOC_CTX *mem_ctx, void *msg, const char *field,
+ size_t *num_values)
{
char **values;
char **ret = NULL;
- int i, n;
+ int i;
values = ldap_get_values(ads->ld, msg, field);
if (!values)
return NULL;
- for (i=0;values[i];i++)
- /* noop */ ;
- n = i;
+ *num_values = ldap_count_values(values);
- ret = talloc(mem_ctx, sizeof(char *) * (n+1));
+ ret = talloc(mem_ctx, sizeof(char *) * (*num_values+1));
if (!ret) {
ldap_value_free(values);
return NULL;
}
- for (i=0;i<n;i++) {
+ for (i=0;i<*num_values;i++) {
if (pull_utf8_talloc(mem_ctx, &ret[i], values[i]) == -1) {
ldap_value_free(values);
return NULL;
@@ -1629,6 +1610,131 @@ char **ads_pull_strings(ADS_STRUCT *ads,
return ret;
}
+/**
+ * pull an array of strings from a ADS result
+ * (handle large multivalue attributes with range retrieval)
+ * @param ads connection to ads server
+ * @param mem_ctx TALLOC_CTX to use for allocating result string
+ * @param msg Results of search
+ * @param field Attribute to retrieve
+ * @param current_strings strings returned by a previous call to this function
+ * @param next_attribute The next query should ask for this attribute
+ * @param num_values How many values did we get this time?
+ * @param more_values Are there more values to get?
+ * @return Result strings in talloc context
+ **/
+char **ads_pull_strings_range(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ void *msg, const char *field,
+ char **current_strings,
+ const char **next_attribute,
+ size_t *num_strings,
+ BOOL *more_strings)
+{
+ char *attr;
+ char *expected_range_attrib, *range_attr;
+ BerElement *ptr = NULL;
+ char **strings;
+ char **new_strings;
+ size_t num_new_strings;
+ unsigned long int range_start;
+ unsigned long int range_end;
+
+ /* we might have been given the whole lot anyway */
+ if ((strings = ads_pull_strings(ads, mem_ctx, msg, field, num_strings))) {
+ *more_strings = False;
+ return strings;
+ }
+
+ expected_range_attrib = talloc_asprintf(mem_ctx, "%s;Range=", field);
+
+ /* look for Range result */
+ for (attr = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &ptr);
+ attr;
+ attr = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, ptr)) {
+ /* we ignore the fact that this is utf8, as all attributes are ascii... */
+ if (strnequal(attr, expected_range_attrib, strlen(expected_range_attrib))) {
+ range_attr = attr;
+ break;
+ }
+ ldap_memfree(attr);
+ }
+ if (!attr) {
+ ber_free(ptr, 0);
+ /* nothing here - this feild is just empty */
+ *more_strings = False;
+ return NULL;
+ }
+
+ if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-%lu",
+ &range_start, &range_end) == 2) {
+ *more_strings = True;
+ } else {
+ if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-*",
+ &range_start) == 1) {
+ *more_strings = False;
+ } else {
+ DEBUG(1, ("ads_pull_strings_range: Cannot parse Range attriubte (%s)\n",
+ range_attr));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+ }
+
+ if ((*num_strings) != range_start) {
+ DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu"
+ " - aborting range retreival\n",
+ range_attr, *num_strings + 1, range_start));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ new_strings = ads_pull_strings(ads, mem_ctx, msg, range_attr, &num_new_strings);
+
+ if (*more_strings && ((*num_strings + num_new_strings) != (range_end + 1))) {
+ DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
+ "strings in this bunch, but we only got %lu - aborting range retreival\n",
+ range_attr, (unsigned long int)range_end - range_start + 1,
+ (unsigned long int)num_new_strings));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ strings = talloc_realloc(mem_ctx, current_strings,
+ sizeof(*current_strings) *
+ (*num_strings + num_new_strings));
+
+ if (strings == NULL) {
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+
+ memcpy(&strings[*num_strings], new_strings,
+ sizeof(*new_strings) * num_new_strings);
+
+ (*num_strings) += num_new_strings;
+
+ if (*more_strings) {
+ *next_attribute = talloc_asprintf(mem_ctx,
+ "member;range=%d-*",
+ *num_strings);
+
+ if (!*next_attribute) {
+ DEBUG(1, ("talloc_asprintf for next attribute failed!\n"));
+ ldap_memfree(range_attr);
+ *more_strings = False;
+ return NULL;
+ }
+ }
+
+ ldap_memfree(range_attr);
+
+ return strings;
+}
/**
* pull a single uint32 from a ADS result
@@ -1821,8 +1927,9 @@ ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
ADS_STATUS status;
void *res;
- status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
- if (!ADS_ERR_OK(status)) return status;
+ status = ads_do_search_retry(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
+ if (!ADS_ERR_OK(status))
+ return status;
if (ads_count_replies(ads, res) != 1) {
return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
@@ -1893,7 +2000,8 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
p = strchr(value, ':');
if (!p) {
talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' so was deemed invalid\n"));
+ DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' "
+ "so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
}
@@ -1903,7 +2011,8 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
p = strchr(ads->config.ldap_server_name, '$');
if (!p || p[1] != '@') {
talloc_destroy(ctx);
- DEBUG(1, ("ads_server_info: returned ldap server name (%s) does not contain '$@' so was deemed invalid\n", ads->config.ldap_server_name));
+ DEBUG(1, ("ads_server_info: returned ldap server name (%s) does not contain '$@'"
+ " so was deemed invalid\n", ads->config.ldap_server_name));
SAFE_FREE(ads->config.ldap_server_name);
return ADS_ERROR(LDAP_DECODING_ERROR);
}
@@ -1932,77 +2041,6 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
return ADS_SUCCESS;
}
-
-/**
- * find the list of trusted domains
- * @param ads connection to ads server
- * @param mem_ctx TALLOC_CTX for allocating results
- * @param num_trusts pointer to number of trusts
- * @param names pointer to trusted domain name list
- * @param sids pointer to list of sids of trusted domains
- * @return the count of SIDs pulled
- **/
-ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
- int *num_trusts,
- char ***names,
- char ***alt_names,
- DOM_SID **sids)
-{
- const char *attrs[] = {"name", "flatname", "securityIdentifier",
- "trustDirection", NULL};
- ADS_STATUS status;
- void *res, *msg;
- int count, i;
-
- *num_trusts = 0;
-
- status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
- if (!ADS_ERR_OK(status)) return status;
-
- count = ads_count_replies(ads, res);
- if (count == 0) {
- ads_msgfree(ads, res);
- return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- }
-
- (*names) = talloc(mem_ctx, sizeof(char *) * count);
- (*alt_names) = talloc(mem_ctx, sizeof(char *) * count);
- (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
- if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
-
- for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
- uint32 direction;
-
- /* direction is a 2 bit bitfield, 1 means they trust us
- but we don't trust them, so we should not list them
- as users from that domain can't login */
- if (ads_pull_uint32(ads, msg, "trustDirection", &direction) &&
- direction == 1) {
- continue;
- }
-
- (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "name");
- (*alt_names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatname");
-
- if ((*alt_names)[i] && (*alt_names)[i][0]) {
- /* we prefer the flatname as the primary name
- for consistency with RPC */
- char *name = (*alt_names)[i];
- (*alt_names)[i] = (*names)[i];
- (*names)[i] = name;
- }
- if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {
- i++;
- }
- }
-
- ads_msgfree(ads, res);
-
- *num_trusts = i;
-
- return ADS_SUCCESS;
-}
-
/**
* find the domain sid for our domain
* @param ads connection to ads server
@@ -2015,7 +2053,7 @@ ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
void *res;
ADS_STATUS rc;
- rc = ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
+ rc = ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
attrs, &res);
if (!ADS_ERR_OK(rc)) return rc;
if (!ads_pull_sid(ads, res, "objectSid", sid)) {
@@ -2038,9 +2076,9 @@ bin/net -Uadministrator%XXXXX ads search '(&(objectclass=crossref)(dnsroot=VNET3
but you need to force the bind path to match the configurationNamingContext from the rootDSE
*/
-ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workgroup)
+ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **workgroup)
{
- char *exp;
+ char *expr;
ADS_STATUS rc;
char **principles;
char *prefix;
@@ -2048,19 +2086,21 @@ ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workg
int i;
void *res;
const char *attrs[] = {"servicePrincipalName", NULL};
+ int num_principals;
(*workgroup) = NULL;
- asprintf(&exp, "(&(objectclass=computer)(dnshostname=%s.%s))",
+ asprintf(&expr, "(&(objectclass=computer)(dnshostname=%s.%s))",
ads->config.ldap_server_name, ads->config.realm);
- rc = ads_search(ads, &res, exp, attrs);
- free(exp);
+ rc = ads_search(ads, &res, expr, attrs);
+ free(expr);
if (!ADS_ERR_OK(rc)) {
return rc;
}
- principles = ads_pull_strings(ads, mem_ctx, res, "servicePrincipalName");
+ principles = ads_pull_strings(ads, mem_ctx, res,
+ "servicePrincipalName", &num_principals);
ads_msgfree(ads, res);
@@ -2075,8 +2115,8 @@ ADS_STATUS ads_workgroup_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **workg
prefix_length = strlen(prefix);
for (i=0;principles[i]; i++) {
- if (strncasecmp(principles[i], prefix, prefix_length) == 0 &&
- strcasecmp(ads->config.realm, principles[i]+prefix_length) != 0 &&
+ if (strnequal(principles[i], prefix, prefix_length) &&
+ !strequal(ads->config.realm, principles[i]+prefix_length) &&
!strchr(principles[i]+prefix_length, '.')) {
/* found an alternate (short) name for the domain. */
DEBUG(3,("Found alternate name '%s' for realm '%s'\n",
diff --git a/source4/libads/ldap_printer.c b/source4/libads/ldap_printer.c
index f5cd4f2885d..1448074ea02 100644
--- a/source4/libads/ldap_printer.c
+++ b/source4/libads/ldap_printer.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
ads (active directory) printer utility library
- Copyright (C) Jim McDonough 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
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
@@ -31,7 +31,7 @@ ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res,
const char *printer, const char *servername)
{
ADS_STATUS status;
- char *srv_dn, **srv_cn, *exp;
+ char *srv_dn, **srv_cn, *s;
const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
status = ads_find_machine_acct(ads, res, servername);
@@ -44,15 +44,29 @@ ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res,
srv_cn = ldap_explode_dn(srv_dn, 1);
ads_msgfree(ads, *res);
- asprintf(&exp, "(cn=%s-%s)", srv_cn[0], printer);
- status = ads_search(ads, res, exp, attrs);
+ asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer);
+ status = ads_search(ads, res, s, attrs);
ldap_memfree(srv_dn);
ldap_value_free(srv_cn);
- free(exp);
+ free(s);
return status;
}
+ADS_STATUS ads_find_printers(ADS_STRUCT *ads, void **res)
+{
+ char *ldap_expr;
+ const char *attrs[] = { "objectClass", "printerName", "location", "driverName",
+ "serverName", "description", NULL };
+
+ /* For the moment only display all printers */
+
+ ldap_expr = "(&(!(showInAdvancedViewOnly=TRUE))(uncName=*)"
+ "(objectCategory=printQueue))";
+
+ return ads_search(ads, res, ldap_expr, attrs);
+}
+
/*
modify a printer entry in the directory
*/
@@ -338,4 +352,3 @@ BOOL get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
}
#endif
-
diff --git a/source4/libads/ldap_user.c b/source4/libads/ldap_user.c
index 7efe5338f37..56a0d8013b2 100644
--- a/source4/libads/ldap_user.c
+++ b/source4/libads/ldap_user.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
ads (active directory) utility library
- Copyright (C) Jim McDonough 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
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
@@ -28,16 +28,16 @@
ADS_STATUS ads_find_user_acct(ADS_STRUCT *ads, void **res, const char *user)
{
ADS_STATUS status;
- char *exp;
+ char *ldap_exp;
const char *attrs[] = {"*", NULL};
char *escaped_user = escape_ldap_string_alloc(user);
if (!escaped_user) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
- asprintf(&exp, "(samAccountName=%s)", escaped_user);
- status = ads_search(ads, res, exp, attrs);
- SAFE_FREE(exp);
+ asprintf(&ldap_exp, "(samAccountName=%s)", escaped_user);
+ status = ads_search(ads, res, ldap_exp, attrs);
+ SAFE_FREE(ldap_exp);
SAFE_FREE(escaped_user);
return status;
}
diff --git a/source4/libads/ldap_utils.c b/source4/libads/ldap_utils.c
index 907f7c8aff5..991f16c8454 100644
--- a/source4/libads/ldap_utils.c
+++ b/source4/libads/ldap_utils.c
@@ -28,13 +28,15 @@
this is supposed to catch dropped connections and auto-reconnect
*/
ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
- const char *exp,
+ const char *expr,
const char **attrs, void **res)
{
ADS_STATUS status;
int count = 3;
char *bp;
+ *res = NULL;
+
if (!ads->ld &&
time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) {
return ADS_ERROR(LDAP_SERVER_DOWN);
@@ -42,48 +44,58 @@ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope
bp = strdup(bind_path);
- if (!bp)
+ if (!bp) {
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
while (count--) {
- status = ads_do_search_all(ads, bp, scope, exp, attrs, res);
+ *res = NULL;
+ status = ads_do_search_all(ads, bp, scope, expr, attrs, res);
if (ADS_ERR_OK(status)) {
DEBUG(5,("Search for %s gave %d replies\n",
- exp, ads_count_replies(ads, *res)));
- free(bp);
+ expr, ads_count_replies(ads, *res)));
+ SAFE_FREE(bp);
return status;
}
- if (*res) ads_msgfree(ads, *res);
+ if (*res)
+ ads_msgfree(ads, *res);
*res = NULL;
+
DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n",
ads->config.realm, ads_errstr(status)));
+
if (ads->ld) {
ldap_unbind(ads->ld);
}
+
ads->ld = NULL;
status = ads_connect(ads);
+
if (!ADS_ERR_OK(status)) {
DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
ads_errstr(status)));
ads_destroy(&ads);
- free(bp);
+ SAFE_FREE(bp);
return status;
}
}
- free(bp);
+ SAFE_FREE(bp);
+
+ if (!ADS_ERR_OK(status))
+ DEBUG(1,("ads reopen failed after error %s\n",
+ ads_errstr(status)));
- DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(status)));
return status;
}
ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
- const char *exp,
+ const char *expr,
const char **attrs)
{
return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
- exp, attrs, res);
+ expr, attrs, res);
}
ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, void **res,
diff --git a/source4/libads/sasl.c b/source4/libads/sasl.c
index c33255bf56c..1ab71c6ee51 100644
--- a/source4/libads/sasl.c
+++ b/source4/libads/sasl.c
@@ -60,7 +60,7 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
msg1 = gen_negTokenTarg(mechs, blob);
data_blob_free(&blob);
- cred.bv_val = msg1.data;
+ cred.bv_val = (char *)msg1.data;
cred.bv_len = msg1.length;
rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
@@ -96,7 +96,7 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
nthash, 24,
lp_workgroup(),
ads->auth.user_name,
- lp_netbios_name(),
+ global_myname(),
sess_key, 16,
neg_flags);
@@ -106,7 +106,7 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
data_blob_free(&blob);
/* now send the auth packet and we should be done */
- cred.bv_val = auth.data;
+ cred.bv_val = (char *)auth.data;
cred.bv_len = auth.length;
rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
@@ -124,21 +124,23 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
{
DATA_BLOB blob;
struct berval cred, *scred;
+ DATA_BLOB session_key;
int rc;
- blob = spnego_gen_negTokenTarg(principal, ads->auth.time_offset);
+ rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key);
- if (!blob.data) {
- return ADS_ERROR(LDAP_OPERATIONS_ERROR);
+ if (rc) {
+ return ADS_ERROR_KRB5(rc);
}
/* now send the auth packet and we should be done */
- cred.bv_val = blob.data;
+ cred.bv_val = (char *)blob.data;
cred.bv_len = blob.length;
rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
data_blob_free(&blob);
+ data_blob_free(&session_key);
return ADS_ERROR(rc);
}
@@ -165,6 +167,8 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
blob = data_blob(scred->bv_val, scred->bv_len);
+ ber_bvfree(scred);
+
#if 0
file_save("sasl_spnego.dat", blob.data, blob.length);
#endif
@@ -195,11 +199,18 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
status = ads_sasl_spnego_krb5_bind(ads, principal);
if (ADS_ERR_OK(status))
return status;
- if (ads_kinit_password(ads) == 0) {
+
+ status = ADS_ERROR_KRB5(ads_kinit_password(ads));
+
+ if (ADS_ERR_OK(status)) {
status = ads_sasl_spnego_krb5_bind(ads, principal);
}
- if (ADS_ERR_OK(status))
+
+ /* only fallback to NTLMSSP if allowed */
+ if (ADS_ERR_OK(status) ||
+ !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
return status;
+ }
}
#endif
@@ -223,13 +234,13 @@ failed:
*/
static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
{
- int minor_status;
+ uint32 minor_status;
gss_name_t serv_name;
gss_buffer_desc input_name;
gss_ctx_id_t context_handle;
gss_OID mech_type = GSS_C_NULL_OID;
gss_buffer_desc output_token, input_token;
- OM_uint32 ret_flags, conf_state;
+ uint32 ret_flags, conf_state;
struct berval cred;
struct berval *scred;
int i=0;
@@ -324,7 +335,7 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
gss_release_name(&minor_status, &serv_name);
gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
- &conf_state,NULL);
+ (int *)&conf_state,NULL);
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
goto failed;
@@ -349,13 +360,13 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
*p++ = max_msg_size>>16;
*p++ = max_msg_size>>8;
*p++ = max_msg_size;
- snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
- p += strlen(p);
+ snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
+ p += strlen((const char *)p);
output_token.length = PTR_DIFF(p, output_token.value);
gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
- &output_token, &conf_state,
+ &output_token, (int *)&conf_state,
&input_token);
if (gss_rc) {
status = ADS_ERROR_GSS(gss_rc, minor_status);
diff --git a/source4/libads/util.c b/source4/libads/util.c
index 335cabc9526..f8c9a312bbc 100644
--- a/source4/libads/util.c
+++ b/source4/libads/util.c
@@ -24,35 +24,42 @@
ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
{
- char *tmp_password;
- char *password;
- char *new_password;
- char *service_principal;
- ADS_STATUS ret;
+ char *tmp_password;
+ char *password;
+ char *new_password;
+ char *service_principal = NULL;
+ ADS_STATUS ret;
+ uint32 sec_channel_type;
- if ((password = secrets_fetch_machine_password()) == NULL) {
- DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
- return ADS_ERROR_SYSTEM(ENOENT);
- }
+ if ((password = secrets_fetch_machine_password(lp_workgroup(), NULL, &sec_channel_type)) == NULL) {
+ DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
- tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
- new_password = strdup(tmp_password);
- asprintf(&service_principal, "HOST/%s", host_principal);
+ tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ new_password = strdup(tmp_password);
- ret = kerberos_set_password(ads->auth.kdc_server, service_principal, password, service_principal, new_password, ads->auth.time_offset);
+ asprintf(&service_principal, "HOST/%s", host_principal);
- if (!ADS_ERR_OK(ret)) goto failed;
+ if (!service_principal) {
+ DEBUG(1,("asprintf() failed principal %s\n", host_principal));
+ return ADS_ERROR_SYSTEM(ENOMEM);
+ }
- if (!secrets_store_machine_password(new_password)) {
- DEBUG(1,("Failed to save machine password\n"));
- return ADS_ERROR_SYSTEM(EACCES);
- }
+ ret = kerberos_set_password(ads->auth.kdc_server, service_principal, password, service_principal, new_password, ads->auth.time_offset);
+
+ if (!ADS_ERR_OK(ret)) goto failed;
+
+ if (!secrets_store_machine_password(new_password, lp_workgroup(), sec_channel_type)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ return ADS_ERROR_SYSTEM(EACCES);
+ }
failed:
- SAFE_FREE(service_principal);
- SAFE_FREE(new_password);
+ SAFE_FREE(service_principal);
+ SAFE_FREE(new_password);
- return ret;
+ return ret;
}
diff --git a/source4/libcli/raw/clikrb5.c b/source4/libcli/raw/clikrb5.c
index 24da1455deb..1d9c02f7f4e 100644
--- a/source4/libcli/raw/clikrb5.c
+++ b/source4/libcli/raw/clikrb5.c
@@ -97,7 +97,9 @@
return ret;
}
krb5_use_enctype(context, &eblock, enctype);
- return krb5_string_to_key(context, &eblock, key, password, &salt);
+ ret = krb5_string_to_key(context, &eblock, key, password, &salt);
+ SAFE_FREE(salt.data);
+ return ret;
}
#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
int create_kerberos_key_from_string(krb5_context context,
@@ -235,12 +237,12 @@ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
/*
we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
-static krb5_error_code krb5_mk_req2(krb5_context context,
- krb5_auth_context *auth_context,
- const krb5_flags ap_req_options,
- const char *principal,
- krb5_ccache ccache,
- krb5_data *outbuf)
+static krb5_error_code ads_krb5_mk_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
{
krb5_error_code retval;
krb5_principal server;
@@ -255,7 +257,7 @@ static krb5_error_code krb5_mk_req2(krb5_context context,
}
/* obtain ticket & session key */
- memset((char *)&creds, 0, sizeof(creds));
+ ZERO_STRUCT(creds);
if ((retval = krb5_copy_principal(context, server, &creds.server))) {
DEBUG(1,("krb5_copy_principal failed (%s)\n",
error_message(retval)));
@@ -305,14 +307,14 @@ cleanup_princ:
/*
get a kerberos5 ticket for the given service
*/
-DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
+int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5)
{
krb5_error_code retval;
krb5_data packet;
krb5_ccache ccdef;
krb5_context context;
krb5_auth_context auth_context = NULL;
- DATA_BLOB ret;
krb5_enctype enc_types[] = {
#ifdef ENCTYPE_ARCFOUR_HMAC
ENCTYPE_ARCFOUR_HMAC,
@@ -344,56 +346,76 @@ DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
goto failed;
}
- if ((retval = krb5_mk_req2(context,
- &auth_context,
- 0,
- principal,
- ccdef, &packet))) {
+ if ((retval = ads_krb5_mk_req(context,
+ &auth_context,
+ AP_OPTS_USE_SUBKEY,
+ principal,
+ ccdef, &packet))) {
goto failed;
}
- ret = data_blob(packet.data, packet.length);
+ get_krb5_smb_session_key(context, auth_context, session_key_krb5, False);
+
+ *ticket = data_blob(packet.data, packet.length);
+
/* Hmm, heimdal dooesn't have this - what's the correct call? */
-/* krb5_free_data_contents(context, &packet); */
- krb5_free_context(context);
- return ret;
+#ifdef HAVE_KRB5_FREE_DATA_CONTENTS
+ krb5_free_data_contents(context, &packet);
+#endif
failed:
if ( context )
krb5_free_context(context);
- return data_blob(NULL, 0);
+ return retval;
}
- BOOL krb5_get_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16])
+ BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
{
-#ifdef ENCTYPE_ARCFOUR_HMAC
krb5_keyblock *skey;
-#endif
+ krb5_error_code err;
BOOL ret = False;
memset(session_key, 0, 16);
-#ifdef ENCTYPE_ARCFOUR_HMAC
- if (krb5_auth_con_getremotesubkey(context, auth_context, &skey) == 0 && skey != NULL) {
- if (KRB5_KEY_TYPE(skey) ==
- ENCTYPE_ARCFOUR_HMAC
- && KRB5_KEY_LENGTH(skey) == 16) {
- memcpy(session_key, KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
- ret = True;
- }
+ if (remote)
+ err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
+ else
+ err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
+ if (err == 0 && skey != NULL) {
+ DEBUG(10, ("Got KRB5 session key of length %d\n", KRB5_KEY_LENGTH(skey)));
+ *session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
+ dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
+
+ ret = True;
+
krb5_free_keyblock(context, skey);
+ } else {
+ DEBUG(10, ("KRB5 error getting session key %d\n", err));
}
-#endif /* ENCTYPE_ARCFOUR_HMAC */
return ret;
}
+
+
+#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
+ const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i )
+{
+ static krb5_data kdata;
+
+ kdata.data = krb5_principal_get_comp_string(context, principal, i);
+ kdata.length = strlen(kdata.data);
+ return &kdata;
+}
+#endif
+
#else /* HAVE_KRB5 */
- /* this saves a few linking headaches */
-DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
- {
+/* this saves a few linking headaches */
+int cli_krb5_get_ticket(const char *principal, time_t time_offset,
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5)
+{
DEBUG(0,("NO KERBEROS SUPPORT\n"));
- return data_blob(NULL, 0);
- }
+ return 1;
+}
#endif
diff --git a/source4/libcli/raw/clispnego.c b/source4/libcli/raw/clispnego.c
index 53f7eb6e7d9..e6cadc466c1 100644
--- a/source4/libcli/raw/clispnego.c
+++ b/source4/libcli/raw/clispnego.c
@@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple kerberos5/SPNEGO routines
Copyright (C) Andrew Tridgell 2001
- Copyright (C) Jim McDonough 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
Copyright (C) Luke Howard 2003
This program is free software; you can redistribute it and/or modify
@@ -323,24 +323,30 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
kerberos session setup
*/
-DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset)
+int spnego_gen_negTokenTarg(const char *principal, int time_offset,
+ DATA_BLOB *targ,
+ DATA_BLOB *session_key_krb5)
{
- DATA_BLOB tkt, tkt_wrapped, targ;
+ int retval;
+ DATA_BLOB tkt, tkt_wrapped;
const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
- /* get a kerberos ticket for the service */
- tkt = krb5_get_ticket(principal, time_offset);
+ /* get a kerberos ticket for the service and extract the session key */
+ retval = cli_krb5_get_ticket(principal, time_offset, &tkt, session_key_krb5);
+
+ if (retval)
+ return retval;
/* wrap that up in a nice GSS-API wrapping */
tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
/* and wrap that in a shiny SPNEGO wrapper */
- targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
+ *targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
data_blob_free(&tkt_wrapped);
data_blob_free(&tkt);
- return targ;
+ return retval;
}