merge:
authorStefan Metzmacher <metze@samba.org>
Sun, 1 Feb 2004 11:26:25 +0000 (11:26 +0000)
committerStefan Metzmacher <metze@samba.org>
Sun, 1 Feb 2004 11:26:25 +0000 (11:26 +0000)
ldap and krb5 configure tests
libads/*.c and libcli/raw/clikrb5.c from 3.0

metze
(This used to be commit 64b5bfcd73d7626d6f687a641b11e64821144df7)

20 files changed:
source4/Makefile.in
source4/aclocal.m4
source4/configure.in
source4/include/ads.h
source4/include/includes.h
source4/libads/ads_ldap.c
source4/libads/ads_status.c
source4/libads/ads_struct.c
source4/libads/ads_utils.c
source4/libads/config.m4
source4/libads/kerberos_verify.c
source4/libads/krb5_setpw.c
source4/libads/ldap.c
source4/libads/ldap_printer.c
source4/libads/ldap_user.c
source4/libads/ldap_utils.c
source4/libads/sasl.c
source4/libads/util.c
source4/libcli/raw/clikrb5.c
source4/libcli/raw/clispnego.c

index 4c3f216867e357a0c3da2087a251275bbf0a127d..1580814920e79a8065080c2288cd4385fd6aeeb1 100644 (file)
@@ -12,7 +12,7 @@
 prefix=@prefix@
 exec_prefix=@exec_prefix@
 
-LIBS=@LIBS@ 
+LIBS=@LIBS@ @LDAP_LIBS@ @KRB5_LIBS@
 CC=@CC@
 SHLD=@SHLD@
 CFLAGS=@CFLAGS@
index b40152a6ee957a1b4e136a098ad3b098fb7c78ca..21275fea61e3f38cd9958f14fbba47f8e9923525 100644 (file)
@@ -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,
index 567916e8361519f79869249b148e6477f1ddfc93..4c95e7e2a249f5fcc3d270ccb304e0bac4f24ea0 100644 (file)
@@ -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"
index f90983e4052c61c068dc67d14bdea6fd2a99e9ec..410395a71ba9a170868e6ef80da6a669f87333ad 100644 (file)
@@ -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 */
index 2b83d14622557098e99acf04d378d44b35580c22..2391a59b67febfb2da4b1b164dfbe5f9c71cf1f5 100644 (file)
 #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 */
 
index 97f12de0f7f82be6a7084dbcf1cb6f62105a44ac..944cb1599cc97b7b4eb6ed4e9350201cbf4a5a7c 100644 (file)
@@ -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
index 80fdb99eac0567f068c205723788020c3446b868..463f647f9c77fe02ca33a271edae30601953b10f 100644 (file)
@@ -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,14 +69,23 @@ 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?)";
        }
index 652bfe31be8859acf43444626e43a5c007687833..9774968e1214998f2294844a17a514b856b12dc9 100644 (file)
@@ -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;
        }
 
index 626c1779266c9a2f31b35bae8ddcf6a70f7ebd46..1aad0bed547ed553ebc2541eae76e00c344e9ecc 100644 (file)
@@ -88,52 +88,6 @@ uint32 ads_uf2atype(uint32 uf)
        return atype;
 } 
 
-/* 
-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
 */
@@ -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:
index a4ff962a3dd883c18a1ca0a41820ce757cf61722..c0b926b851c5207153da46eca0b2bd5e9999eb5f 100644 (file)
+########################################################
+# 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
index 9367f53539588cdf29ba598ba34ee5a474f7bfd8..8b319ee5544d6783d4bbcd1aabe8195f37b68262 100644 (file)
@@ -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
 
 #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);
@@ -148,26 +352,60 @@ 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 */
index 9d8fb8d24cb9f807fac97896bb488da46a621341..9cf15221a8dd2417ca96415c300d4bdccdd5075f 100644 (file)
@@ -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;
index 0bcd76cb9f761b3e2fd0c184dcd1113a51306544..8039d3d1d407c6fb7151d60d9d91248884feb277 100644 (file)
@@ -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",
index f5cd4f2885d2cdd547069b8b1e61f90554e784bd..1448074ea022d53333b38c42c2c215013b717866 100644 (file)
@@ -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
-
index 7efe5338f371bb7e8b81a6a3a3e0cad3dfbc0511..56a0d8013b2b8ee6ddc32a0d37cc50dcf6907a8c 100644 (file)
@@ -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
 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;
 }
index 907f7c8aff553a75f5a7849c62f43aacbbff65b0..991f16c84544791bd7baa03d16527f5fd438f5d2 100644 (file)
   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, 
index c33255bf56c097e8eedea3ad6e3b3ada969fd53a..1ab71c6ee514fbae1ddd25699ba09fe8b026cd33 100644 (file)
@@ -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);
index 335cabc95261429172f0255b421f05553721292b..f8c9a312bbce59adc09a0486651551e53d03fdeb 100644 (file)
 
 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;
 }
 
 
index 24da1455deb0124269441c07ead182ec876cfa24..1d9c02f7f4e50a21d6045f9b8ce32283e5b33849 100644 (file)
@@ -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
index 53f7eb6e7d9b5218f3d02e61ad3596879553cc60..e6cadc466c17e501e18946913b8dc909511ef5da 100644 (file)
@@ -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;
 }