summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/auth/auth_domain.c2
-rw-r--r--source3/include/ads.h9
-rw-r--r--source3/libads/kerberos.c8
-rw-r--r--source3/libads/krb5_setpw.c14
-rw-r--r--source3/libads/ldap.c66
-rw-r--r--source3/libads/sasl.c7
-rw-r--r--source3/libads/util.c2
-rw-r--r--source3/libsmb/cliconnect.c2
-rw-r--r--source3/libsmb/clikrb5.c14
-rw-r--r--source3/libsmb/clispnego.c4
-rw-r--r--source3/nsswitch/winbindd_cm.c2
-rw-r--r--source3/utils/net_ads.c26
12 files changed, 113 insertions, 43 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index e8f11bb3d5..2e51a85281 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -48,7 +48,7 @@ static NTSTATUS ads_resolve_dc(fstring remote_machine,
DEBUG(4,("ads_resolve_dc: realm=%s\n", ads->config.realm));
- ads->auth.no_bind = 1;
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
#ifdef HAVE_ADS
/* a full ads_connect() is actually overkill, as we don't srictly need
diff --git a/source3/include/ads.h b/source3/include/ads.h
index 6106eb6b40..875b895e49 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -24,7 +24,8 @@ typedef struct {
char *password;
char *user_name;
char *kdc_server;
- int no_bind;
+ unsigned flags;
+ int time_offset;
} auth;
/* info derived from the servers config */
@@ -32,6 +33,7 @@ typedef struct {
char *realm;
char *bind_path;
char *ldap_server_name;
+ time_t current_time;
} config;
} ADS_STRUCT;
@@ -249,3 +251,8 @@ typedef void **ADS_MODLIST;
/* DomainCntrollerAddressType */
#define ADS_INET_ADDRESS 0x00000001
#define ADS_NETBIOS_ADDRESS 0x00000002
+
+
+/* ads auth control flags */
+#define ADS_AUTH_DISABLE_KERBEROS 1
+#define ADS_AUTH_NO_BIND 2
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 9a486237c9..a80837cf4d 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -50,7 +50,7 @@ kerb_prompter(krb5_context ctx, void *data,
simulate a kinit, putting the tgt in the default cache location
remus@snapserver.com
*/
-int kerberos_kinit_password(const char *principal, const char *password)
+int kerberos_kinit_password(const char *principal, const char *password, int time_offset)
{
krb5_context ctx;
krb5_error_code code = 0;
@@ -60,6 +60,10 @@ int kerberos_kinit_password(const char *principal, const char *password)
if ((code = krb5_init_context(&ctx)))
return code;
+
+ if (time_offset != 0) {
+ krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
+ }
if ((code = krb5_cc_default(ctx, &cc))) {
krb5_free_context(ctx);
@@ -111,7 +115,7 @@ int ads_kinit_password(ADS_STRUCT *ads)
int ret;
asprintf(&s, "%s@%s", ads->auth.user_name, ads->auth.realm);
- ret = kerberos_kinit_password(s, ads->auth.password);
+ ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset);
if (ret) {
DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c
index ec79a8658f..a49b6cbe3b 100644
--- a/source3/libads/krb5_setpw.c
+++ b/source3/libads/krb5_setpw.c
@@ -248,7 +248,8 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
return 0;
}
-ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw)
+ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char *newpw,
+ int time_offset)
{
krb5_context context;
krb5_auth_context auth_context = NULL;
@@ -268,6 +269,10 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
return ADS_ERROR_KRB5(ret);
}
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
ret = krb5_cc_default(context, &ccache);
if (ret) {
krb5_free_context(context);
@@ -452,16 +457,17 @@ ADS_STATUS krb5_set_password(const char *kdc_host, const char *princ, const char
ADS_STATUS kerberos_set_password(const char *kpasswd_server,
const char *auth_principal, const char *auth_password,
- const char *target_principal, const char *new_password)
+ const char *target_principal, const char *new_password,
+ int time_offset)
{
int ret;
- if ((ret = kerberos_kinit_password(auth_principal, auth_password))) {
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset))) {
DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
- return krb5_set_password(kpasswd_server, target_principal, new_password);
+ return krb5_set_password(kpasswd_server, target_principal, new_password, time_offset);
}
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 2f70d3a285..385a9bd93f 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -63,6 +63,7 @@ static BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port)
ads->ldap_port = port;
ads->ldap_ip = *interpret_addr2(srv);
free(srv);
+
return True;
}
@@ -204,7 +205,6 @@ static BOOL ads_try_netbios(ADS_STRUCT *ads)
ADS_STATUS ads_connect(ADS_STRUCT *ads)
{
int version = LDAP_VERSION3;
- int code;
ADS_STATUS status;
ads->last_attempt = time(NULL);
@@ -274,7 +274,7 @@ got_connection:
}
#endif
- if (ads->auth.no_bind) {
+ if (ads->auth.flags & ADS_AUTH_NO_BIND) {
return ADS_SUCCESS;
}
@@ -1416,7 +1416,7 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
*/
asprintf(&principal, "%s$@%s", host, ads->auth.realm);
- status = krb5_set_password(ads->auth.kdc_server, principal, password);
+ status = krb5_set_password(ads->auth.kdc_server, principal, password, ads->auth.time_offset);
free(host);
free(principal);
@@ -1622,6 +1622,26 @@ ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
return ADS_SUCCESS;
}
+/* parse a ADS timestring - typical string is
+ '20020917091222.0Z0' which means 09:12.22 17th September
+ 2002, timezone 0 */
+static time_t ads_parse_time(const char *str)
+{
+ struct tm tm;
+
+ ZERO_STRUCT(tm);
+
+ if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
/**
* Find the servers name and realm - this can be done before authentication
@@ -1632,22 +1652,36 @@ ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
**/
ADS_STATUS ads_server_info(ADS_STRUCT *ads)
{
- const char *attrs[] = {"ldapServiceName", NULL};
+ const char *attrs[] = {"ldapServiceName", "currentTime", NULL};
ADS_STATUS status;
void *res;
- char **values;
+ char *value;
char *p;
+ char *timestr;
+ TALLOC_CTX *ctx;
+
+ if (!(ctx = talloc_init())) {
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
if (!ADS_ERR_OK(status)) return status;
- values = ldap_get_values(ads->ld, res, "ldapServiceName");
- if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ value = ads_pull_string(ads, ctx, res, "ldapServiceName");
+ if (!value) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
+
+ timestr = ads_pull_string(ads, ctx, res, "currentTime");
+ if (!timestr) {
+ return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ }
- p = strchr(values[0], ':');
+ ldap_msgfree(res);
+
+ p = strchr(value, ':');
if (!p) {
- ldap_value_free(values);
- ldap_msgfree(res);
+ talloc_destroy(ctx);
DEBUG(1, ("ads_server_info: returned ldap server name did not contain a ':' so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
}
@@ -1657,8 +1691,7 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
ads->config.ldap_server_name = strdup(p+1);
p = strchr(ads->config.ldap_server_name, '$');
if (!p || p[1] != '@') {
- ldap_value_free(values);
- ldap_msgfree(res);
+ talloc_destroy(ctx);
SAFE_FREE(ads->config.ldap_server_name);
DEBUG(1, ("ads_server_info: returned ldap server name did not contain '$@' so was deemed invalid\n"));
return ADS_ERROR(LDAP_DECODING_ERROR);
@@ -1675,6 +1708,15 @@ ADS_STATUS ads_server_info(ADS_STRUCT *ads)
DEBUG(3,("got ldap server name %s@%s\n",
ads->config.ldap_server_name, ads->config.realm));
+ ads->config.current_time = ads_parse_time(timestr);
+
+ if (ads->config.current_time != 0) {
+ ads->auth.time_offset = ads->config.current_time - time(NULL);
+ DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
+ }
+
+ talloc_destroy(ctx);
+
return ADS_SUCCESS;
}
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 12a5722319..c110c1d2cd 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -122,7 +122,7 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
struct berval cred, *scred;
int rc;
- blob = spnego_gen_negTokenTarg(principal);
+ blob = spnego_gen_negTokenTarg(principal, ads->auth.time_offset);
if (!blob.data) {
return ADS_ERROR(LDAP_OPERATIONS_ERROR);
@@ -144,7 +144,7 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
- struct berval *scred;
+ struct berval *scred=NULL;
int rc, i;
ADS_STATUS status;
DATA_BLOB blob;
@@ -185,7 +185,8 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
}
DEBUG(3,("got principal=%s\n", principal));
- if (got_kerberos_mechanism && ads_kinit_password(ads) == 0) {
+ if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
+ got_kerberos_mechanism && ads_kinit_password(ads) == 0) {
return ads_sasl_spnego_krb5_bind(ads, principal);
}
diff --git a/source3/libads/util.c b/source3/libads/util.c
index b10b130a31..021f2d93e4 100644
--- a/source3/libads/util.c
+++ b/source3/libads/util.c
@@ -40,7 +40,7 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
asprintf(&service_principal, "HOST/%s", host_principal);
ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password,
- service_principal, new_password);
+ service_principal, new_password, ads->auth.time_offset);
if (!secrets_store_machine_password(new_password)) {
DEBUG(1,("Failed to save machine password\n"));
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 6c5c5e0b0e..298b1e52b6 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -431,7 +431,7 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, c
DEBUG(2,("Doing kerberos session setup\n"));
/* generate the encapsulated kerberos5 ticket */
- negTokenTarg = spnego_gen_negTokenTarg(principal);
+ negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
if (!negTokenTarg.data) return False;
diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c
index 1fc400edb0..22bfdc0463 100644
--- a/source3/libsmb/clikrb5.c
+++ b/source3/libsmb/clikrb5.c
@@ -64,6 +64,14 @@ static krb5_error_code krb5_mk_req2(krb5_context context,
goto cleanup_creds;
}
+ /* cope with the ticket being in the future due to clock skew */
+ if ((unsigned)credsp->times.starttime > time(NULL)) {
+ time_t t = time(NULL);
+ int time_offset = (unsigned)credsp->times.starttime - t;
+ DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+ krb5_set_real_time(context, t + time_offset + 1, 0);
+ }
+
in_data.length = 0;
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
&in_data, credsp, outbuf);
@@ -86,7 +94,7 @@ cleanup_princ:
/*
get a kerberos5 ticket for the given service
*/
-DATA_BLOB krb5_get_ticket(char *principal)
+DATA_BLOB krb5_get_ticket(char *principal, time_t time_offset)
{
krb5_error_code retval;
krb5_data packet;
@@ -108,6 +116,10 @@ DATA_BLOB krb5_get_ticket(char *principal)
goto failed;
}
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
if ((retval = krb5_cc_default(context, &ccdef))) {
DEBUG(1,("krb5_cc_default failed (%s)\n",
error_message(retval)));
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 04ec6ed39e..55f49c5987 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -321,13 +321,13 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket)
generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
kerberos session setup
*/
-DATA_BLOB spnego_gen_negTokenTarg(const char *principal)
+DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset)
{
DATA_BLOB tkt, tkt_wrapped, targ;
const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
/* get a kerberos ticket for the service */
- tkt = krb5_get_ticket(principal);
+ tkt = krb5_get_ticket(principal, time_offset);
/* wrap that up in a nice GSS-API wrapping */
tkt_wrapped = spnego_gen_krb5_wrap(tkt);
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index 9ac392a6ba..0b9e38eb1f 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -109,7 +109,7 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
}
/* we don't need to bind, just connect */
- ads->auth.no_bind = 1;
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain));
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 8c85bd82f9..af290ce83c 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -66,7 +66,7 @@ static int net_ads_lookup(int argc, const char **argv)
ads = ads_init(NULL, NULL, opt_host);
if (ads) {
- ads->auth.no_bind = 1;
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
}
ads_connect(ads);
@@ -88,7 +88,7 @@ static int net_ads_info(int argc, const char **argv)
ads = ads_init(NULL, NULL, opt_host);
if (ads) {
- ads->auth.no_bind = 1;
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
}
ads_connect(ads);
@@ -103,6 +103,7 @@ static int net_ads_info(int argc, const char **argv)
d_printf("Realm: %s\n", ads->config.realm);
d_printf("Bind Path: %s\n", ads->config.bind_path);
d_printf("LDAP port: %d\n", ads->ldap_port);
+ d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
return 0;
}
@@ -199,7 +200,7 @@ static int net_ads_workgroup(int argc, const char **argv)
-static void usergrp_display(char *field, void **values, void *data_area)
+static BOOL usergrp_display(char *field, void **values, void *data_area)
{
char **disp_fields = (char **) data_area;
@@ -213,15 +214,16 @@ static void usergrp_display(char *field, void **values, void *data_area)
}
SAFE_FREE(disp_fields[0]);
SAFE_FREE(disp_fields[1]);
- return;
+ return True;
}
if (!values) /* must be new field, indicate string field */
- return;
+ return True;
if (StrCaseCmp(field, "sAMAccountName") == 0) {
disp_fields[0] = strdup((char *) values[0]);
}
if (StrCaseCmp(field, "description") == 0)
disp_fields[1] = strdup((char *) values[0]);
+ return True;
}
static int net_ads_user_usage(int argc, const char **argv)
@@ -270,7 +272,7 @@ static int ads_user_add(int argc, const char **argv)
/* try setting the password */
asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
- status = krb5_set_password(ads->auth.kdc_server, upn, argv[1]);
+ status = krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset);
safe_free(upn);
if (ADS_ERR_OK(status)) {
d_printf("User %s added\n", argv[0]);
@@ -653,7 +655,9 @@ int net_ads_join(int argc, const char **argv)
return -1;
}
- if (ads_kinit_password(ads)) {
+ rc = ads_domain_sid(ads, &dom_sid);
+ if (!ADS_ERR_OK(rc)) {
+ d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
return -1;
}
@@ -663,12 +667,6 @@ int net_ads_join(int argc, const char **argv)
return -1;
}
- rc = ads_domain_sid(ads, &dom_sid);
- if (!ADS_ERR_OK(rc)) {
- d_printf("ads_domain_sid: %s\n", ads_errstr(rc));
- return -1;
- }
-
if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) {
DEBUG(1,("Failed to save domain sid\n"));
return -1;
@@ -885,7 +883,7 @@ static int net_ads_password(int argc, const char **argv)
new_password = getpass(prompt);
ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
- auth_password, argv[0], new_password);
+ auth_password, argv[0], new_password, ads->auth.time_offset);
if (!ADS_ERR_OK(ret)) {
d_printf("Password change failed :-( ...\n");
ads_destroy(&ads);