summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/ads.h61
-rw-r--r--source3/libads/sasl_wrapping.c131
2 files changed, 175 insertions, 17 deletions
diff --git a/source3/include/ads.h b/source3/include/ads.h
index 5c15359c41..8404ad907b 100644
--- a/source3/include/ads.h
+++ b/source3/include/ads.h
@@ -15,7 +15,31 @@ enum wb_posix_mapping {
WB_POSIX_MAP_UNIXINFO = 4
};
-typedef struct {
+/* 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;
+ union err_state{
+ int rc;
+ NTSTATUS nt_status;
+ } err;
+ /* 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;
+
+struct ads_struct;
+
+struct ads_saslwrap_ops {
+ const char *name;
+ ADS_STATUS (*wrap)(struct ads_struct *);
+ ADS_STATUS (*unwrap)(struct ads_struct *);
+ ADS_STATUS (*disconnect)(struct ads_struct *);
+};
+
+typedef struct ads_struct {
int is_mine; /* do I own this structure's memory? */
/* info needed to find the server */
@@ -63,6 +87,27 @@ typedef struct {
#ifdef HAVE_LDAP_SASL_WRAPPING
Sockbuf_IO_Desc *sbiod; /* lowlevel state for LDAP wrapping */
+ TALLOC_CTX *mem_ctx;
+ const struct ads_saslwrap_ops *wrap_ops;
+ void *wrap_private_data;
+ struct {
+ uint32 ofs;
+ uint32 needed;
+ uint32 left;
+ uint32 max;
+ uint32 min;
+ uint32 size;
+ uint8 *buf;
+ } in;
+ struct {
+ uint32 ofs;
+ uint32 needed;
+ uint32 left;
+ uint32 max;
+ uint32 min;
+ uint32 size;
+ uint8 *buf;
+ } out;
#endif /* HAVE_LDAP_SASL_WRAPPING */
} ldap;
#endif /* HAVE_LDAP */
@@ -80,20 +125,6 @@ struct posix_schema {
};
-/* 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;
- union err_state{
- int rc;
- NTSTATUS nt_status;
- } err;
- /* 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;
#ifdef HAVE_ADS
typedef LDAPMod **ADS_MODLIST;
diff --git a/source3/libads/sasl_wrapping.c b/source3/libads/sasl_wrapping.c
index 4a26afe740..9617961969 100644
--- a/source3/libads/sasl_wrapping.c
+++ b/source3/libads/sasl_wrapping.c
@@ -37,9 +37,137 @@ static int ads_saslwrap_remove(Sockbuf_IO_Desc *sbiod)
return 0;
}
+static ber_slen_t ads_saslwrap_prepare_inbuf(ADS_STRUCT *ads)
+{
+ ads->ldap.in.ofs = 0;
+ ads->ldap.in.needed = 0;
+ ads->ldap.in.left = 0;
+ ads->ldap.in.size = 4 + ads->ldap.in.min;
+ ads->ldap.in.buf = talloc_array(ads->ldap.mem_ctx,
+ uint8, ads->ldap.in.size);
+ if (!ads->ldap.in.buf) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static ber_slen_t ads_saslwrap_grow_inbuf(ADS_STRUCT *ads)
+{
+ if (ads->ldap.in.size == (4 + ads->ldap.in.needed)) {
+ return 0;
+ }
+
+ ads->ldap.in.size = 4 + ads->ldap.in.needed;
+ ads->ldap.in.buf = talloc_realloc(ads->ldap.mem_ctx,
+ ads->ldap.in.buf,
+ uint8, ads->ldap.in.size);
+ if (!ads->ldap.in.buf) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ads_saslwrap_shrink_inbuf(ADS_STRUCT *ads)
+{
+ talloc_free(ads->ldap.in.buf);
+
+ ads->ldap.in.buf = NULL;
+ ads->ldap.in.size = 0;
+ ads->ldap.in.ofs = 0;
+ ads->ldap.in.needed = 0;
+ ads->ldap.in.left = 0;
+}
+
static ber_slen_t ads_saslwrap_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
- return LBER_SBIOD_READ_NEXT(sbiod, buf, len);
+ ADS_STRUCT *ads = (ADS_STRUCT *)sbiod->sbiod_pvt;
+ ber_slen_t ret;
+
+ /* If ofs < 4 it means we don't have read the length header yet */
+ if (ads->ldap.in.ofs < 4) {
+ ret = ads_saslwrap_prepare_inbuf(ads);
+ if (ret < 0) return ret;
+
+ ret = LBER_SBIOD_READ_NEXT(sbiod,
+ ads->ldap.in.buf + ads->ldap.in.ofs,
+ 4 - ads->ldap.in.ofs);
+ if (ret < 0) return ret;
+ ads->ldap.in.ofs += ret;
+
+ if (ads->ldap.in.ofs < 4) goto eagain;
+
+ ads->ldap.in.needed = RIVAL(ads->ldap.in.buf, 4);
+ if (ads->ldap.in.needed > ads->ldap.in.max) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (ads->ldap.in.needed < ads->ldap.in.min) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = ads_saslwrap_grow_inbuf(ads);
+ if (ret < 0) return ret;
+ }
+
+ /*
+ * if there's more data needed from the remote end,
+ * we need to read more
+ */
+ if (ads->ldap.in.needed > 0) {
+ ret = LBER_SBIOD_READ_NEXT(sbiod,
+ ads->ldap.in.buf + ads->ldap.in.ofs,
+ ads->ldap.in.needed);
+ if (ret < 0) return ret;
+ ads->ldap.in.ofs += ret;
+ ads->ldap.in.needed -= ret;
+
+ if (ads->ldap.in.needed > 0) goto eagain;
+ }
+
+ /*
+ * if we have a complete packet and have not yet unwrapped it
+ * we need to call the mech specific unwrap() hook
+ */
+ if (ads->ldap.in.needed == 0 && ads->ldap.in.left == 0) {
+ ADS_STATUS status;
+ status = ads->ldap.wrap_ops->unwrap(ads);
+ if (!ADS_ERR_OK(status)) {
+ errno = EACCES;
+ return -1;
+ }
+ }
+
+ /*
+ * if we have unwrapped data give it to the caller
+ */
+ if (ads->ldap.in.left > 0) {
+ ret = MIN(ads->ldap.in.left, len);
+ memcpy(buf, ads->ldap.in.buf + ads->ldap.in.ofs, ret);
+ ads->ldap.in.ofs += ret;
+ ads->ldap.in.left -= ret;
+
+ /*
+ * if no more is left shrink the inbuf,
+ * this will trigger reading a new SASL packet
+ * from the remote stream in the next call
+ */
+ if (ads->ldap.in.left == 0) {
+ ads_saslwrap_shrink_inbuf(ads);
+ }
+
+ return ret;
+ }
+
+ /*
+ * if we don't have anything for the caller yet,
+ * tell him to ask again
+ */
+eagain:
+ errno = EAGAIN;
+ return -1;
}
static ber_slen_t ads_saslwrap_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
@@ -47,7 +175,6 @@ static ber_slen_t ads_saslwrap_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_
return LBER_SBIOD_WRITE_NEXT(sbiod, buf, len);
}
-
static int ads_saslwrap_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
{
return LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);