diff options
Diffstat (limited to 'source4/libcli/ldap')
-rw-r--r-- | source4/libcli/ldap/ldap_client.c | 131 | ||||
-rw-r--r-- | source4/libcli/ldap/ldap_ldif.c | 58 |
2 files changed, 188 insertions, 1 deletions
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index 71b57e116e..8867344de3 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -548,9 +548,138 @@ struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid, return NULL; } +/* + Write data to a fd +*/ +static ssize_t write_data(int fd, char *buffer, size_t N) +{ + size_t total=0; + ssize_t ret; + + while (total < N) { + ret = sys_write(fd,buffer + total,N - total); + + if (ret == -1) { + DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) )); + return -1; + } + if (ret == 0) + return total; + + total += ret; + } + + return (ssize_t)total; +} + + +/* + Read data from the client, reading exactly N bytes +*/ +static ssize_t read_data(int fd, char *buffer, size_t N) +{ + ssize_t ret; + size_t total=0; + + while (total < N) { + + ret = sys_read(fd,buffer + total,N - total); + + if (ret == 0) { + DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", + (int)(N - total), strerror(errno) )); + return 0; + } + + if (ret == -1) { + DEBUG(0,("read_data: read failure for %d. Error = %s\n", + (int)(N - total), strerror(errno) )); + return -1; + } + total += ret; + } + + return (ssize_t)total; +} + +static struct ldap_message *ldap_transaction_sasl(struct ldap_connection *conn, struct ldap_message *req) +{ + NTSTATUS status; + DATA_BLOB request; + BOOL result; + DATA_BLOB wrapped; + int len; + char length[4]; + struct asn1_data asn1; + struct ldap_message *rep; + + req->messageid = conn->next_msgid++; + + if (!ldap_encode(req, &request)) + return NULL; + + status = gensec_wrap(conn->gensec, + req->mem_ctx, + &request, + &wrapped); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("gensec_wrap: %s\n",nt_errstr(status))); + return NULL; + } + + RSIVAL(length, 0, wrapped.length); + + result = (write_data(conn->sock, length, 4) == 4); + if (!result) + return NULL; + + result = (write_data(conn->sock, wrapped.data, wrapped.length) == wrapped.length); + if (!result) + return NULL; + + wrapped = data_blob(NULL, 0x4000); + data_blob_clear(&wrapped); + + result = (read_data(conn->sock, length, 4) == 4); + if (!result) + return NULL; + + len = RIVAL(length,0); + + result = (read_data(conn->sock, wrapped.data, MIN(wrapped.length,len)) == len); + if (!result) + return NULL; + + wrapped.length = len; + + status = gensec_unwrap(conn->gensec, + req->mem_ctx, + &wrapped, + &request); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("gensec_unwrap: %s\n",nt_errstr(status))); + return NULL; + } + + rep = new_ldap_message(req->mem_ctx); + + asn1_load(&asn1, request); + if (!ldap_decode(&asn1, rep)) { + return NULL; + } + + return rep; +} + struct ldap_message *ldap_transaction(struct ldap_connection *conn, struct ldap_message *request) { + if ((request->type != LDAP_TAG_BindRequest) && conn->gensec && + (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) || + gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN))) { + return ldap_transaction_sasl(conn, request); + } + if (!ldap_send_msg(conn, request, NULL)) return False; @@ -624,7 +753,7 @@ int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds) return result; } - gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL); + gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL); status = gensec_set_credentials(conn->gensec, creds); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/libcli/ldap/ldap_ldif.c b/source4/libcli/ldap/ldap_ldif.c index e5e5cdd6df..c36106e116 100644 --- a/source4/libcli/ldap/ldap_ldif.c +++ b/source4/libcli/ldap/ldap_ldif.c @@ -305,6 +305,53 @@ static BOOL fill_mods(struct ldap_message *msg, char **chunk) return True; } +static BOOL fill_modrdn(struct ldap_message *msg, char **chunk) +{ + struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest; + const char *attr_name; + struct ldap_val value; + + r->newrdn = NULL; + r->deleteolddn = False; + r->newsuperior = NULL; + + if (next_attr(chunk, &attr_name, &value) != 0) { + return False; + } + + if (!strequal(attr_name, "newrdn")) { + return False; + } + + r->newrdn = value.data; + + if (next_attr(chunk, &attr_name, &value) != 0) { + return False; + } + + if (!strequal(attr_name, "deleteoldrdn")) { + return False; + } + + if (value.data && (((char *)value.data)[0] != '0')) { + r->deleteolddn = True; + } + + if (next_attr(chunk, &attr_name, &value) != 0) { + /* newsuperior is optional */ + return True; + } + + if (!strequal(attr_name, "newsuperior")) { + return False; + } + + r->newsuperior = value.data; + + return True; +} + + /* read from a LDIF source, creating a ldap_message */ @@ -381,6 +428,17 @@ static struct ldap_message *ldif_read(TALLOC_CTX *mem_ctx, int (*fgetc_fn)(void return msg; } + if (strequal(value.data, "modrdn")) { + msg->type = LDAP_TAG_ModifyDNRequest; + + msg->r.ModifyDNRequest.dn = dn; + + if (!fill_modrdn(msg, &s)) + goto failed; + + return msg; + } + DEBUG(3, ("changetype %s not supported\n", (char *)value.data)); failed: |