diff options
Diffstat (limited to 'source4/rpc_server')
-rw-r--r-- | source4/rpc_server/samr/dcesrv_samr.c | 85 | ||||
-rw-r--r-- | source4/rpc_server/samr/samdb.c | 96 |
2 files changed, 138 insertions, 43 deletions
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index af716e5cef..0b443a7078 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -39,6 +39,8 @@ enum samr_handle { state asscoiated with a samr_Connect*() operation */ struct samr_connect_state { + int reference_count; + void *sam_ctx; TALLOC_CTX *mem_ctx; uint32 access_mask; }; @@ -47,6 +49,9 @@ struct samr_connect_state { state associated with a samr_OpenDomain() operation */ struct samr_domain_state { + struct samr_connect_state *connect_state; + int reference_count; + void *sam_ctx; TALLOC_CTX *mem_ctx; uint32 access_mask; const char *domain_sid; @@ -57,6 +62,8 @@ struct samr_domain_state { state associated with a open user handle */ struct samr_user_state { + struct samr_domain_state *domain_state; + void *sam_ctx; TALLOC_CTX *mem_ctx; uint32 access_mask; const char *user_sid; @@ -65,12 +72,24 @@ struct samr_user_state { /* + destroy connection state +*/ +static void samr_Connect_close(struct samr_connect_state *state) +{ + state->reference_count--; + if (state->reference_count == 0) { + samdb_close(state->sam_ctx); + talloc_destroy(state->mem_ctx); + } +} + +/* destroy an open connection. This closes the database connection */ static void samr_Connect_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h) { struct samr_connect_state *state = h->data; - talloc_destroy(state->mem_ctx); + samr_Connect_close(state); } /* @@ -99,7 +118,8 @@ static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem state->mem_ctx = connect_mem_ctx; /* make sure the sam database is accessible */ - if (samdb_connect() != 0) { + state->sam_ctx = samdb_connect(); + if (state->sam_ctx == NULL) { talloc_destroy(state->mem_ctx); return NT_STATUS_INVALID_SYSTEM_SERVICE; } @@ -113,6 +133,7 @@ static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem handle->data = state; handle->destroy = samr_Connect_destroy; + state->reference_count = 1; state->access_mask = r->in.access_mask; *r->out.handle = handle->wire_handle; @@ -183,6 +204,7 @@ static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *me static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_LookupDomain *r) { + struct samr_connect_state *state; struct dcesrv_handle *h; struct dom_sid2 *sid; const char *sidstr; @@ -191,13 +213,16 @@ static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX DCESRV_CHECK_HANDLE(h); + state = h->data; + r->out.sid = NULL; if (r->in.domain->name == NULL) { return NT_STATUS_INVALID_PARAMETER; } - sidstr = samdb_search_string(mem_ctx, "objectSid", + sidstr = samdb_search_string(state->sam_ctx, + mem_ctx, "objectSid", "(&(name=%s)(objectclass=domain))", r->in.domain->name); if (sidstr == NULL) { @@ -225,6 +250,7 @@ static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_EnumDomains *r) { + struct samr_connect_state *state; struct dcesrv_handle *h; struct samr_SamArray *array; char **domains; @@ -234,11 +260,14 @@ static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX DCESRV_CHECK_HANDLE(h); + state = h->data; + *r->out.resume_handle = 0; r->out.sam = NULL; r->out.num_entries = 0; - count = samdb_search_string_multiple(mem_ctx, &domains, + count = samdb_search_string_multiple(state->sam_ctx, + mem_ctx, &domains, "name", "(objectclass=domain)"); if (count == -1) { DEBUG(1,("samdb: no domains found in EnumDomains\n")); @@ -286,7 +315,11 @@ static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h) { struct samr_domain_state *state = h->data; - talloc_destroy(state->mem_ctx); + state->reference_count--; + if (state->reference_count == 0) { + samr_Connect_close(state->connect_state); + talloc_destroy(state->mem_ctx); + } } /* @@ -297,18 +330,22 @@ static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX * { struct dcesrv_handle *h_conn, *h_domain; char *sidstr, *domain_name; + struct samr_connect_state *c_state; struct samr_domain_state *state; TALLOC_CTX *mem_ctx2; h_conn = dcesrv_handle_fetch(dce_call->conn, r->in.handle, SAMR_HANDLE_CONNECT); DCESRV_CHECK_HANDLE(h_conn); + c_state = h_conn->data; + sidstr = dom_sid_string(mem_ctx, r->in.sid); if (sidstr == NULL) { return NT_STATUS_INVALID_PARAMETER; } - domain_name = samdb_search_string(mem_ctx, "name", + domain_name = samdb_search_string(c_state->sam_ctx, + mem_ctx, "name", "(&(objectSid=%s)(objectclass=domain))", sidstr); if (domain_name == NULL) { @@ -326,6 +363,9 @@ static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX * return NT_STATUS_NO_MEMORY; } + state->reference_count = 1; + state->connect_state = c_state; + state->sam_ctx = c_state->sam_ctx; state->mem_ctx = mem_ctx2; state->domain_sid = talloc_steal(mem_ctx, mem_ctx2, sidstr); state->domain_name = talloc_steal(mem_ctx, mem_ctx2, domain_name); @@ -337,6 +377,7 @@ static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX * return NT_STATUS_NO_MEMORY; } + c_state->reference_count++; h_domain->data = state; h_domain->destroy = samr_Domain_destroy; *r->out.domain_handle = h_domain->wire_handle; @@ -391,13 +432,29 @@ static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_CreateUser2 *r) { + struct samr_domain_state *d_state; struct samr_user_state *state; struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, SAMR_HANDLE_DOMAIN); + const char *name; + DCESRV_CHECK_HANDLE(h); + d_state = h->data; + + if (r->in.username->name == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + /* check if the user already exists */ + name = samdb_search_string(d_state->sam_ctx, mem_ctx, "name", + "(&(name=%s)(objectclass=user))", + r->in.username->name); + if (name != NULL) { + return NT_STATUS_USER_EXISTS; + } + /* read the default user template */ /* allocate a rid */ /* create a ldb_message for the user */ @@ -863,27 +920,37 @@ static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX struct ldb_message **msgs; int ret; char * const attrs[] = {"minPwdLength", "pwdProperties", NULL }; + void *sam_ctx; if (r->in.name == NULL || r->in.name->name == NULL) { return NT_STATUS_NO_SUCH_DOMAIN; } - ret = samdb_search(mem_ctx, &msgs, attrs, + sam_ctx = samdb_connect(); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + ret = samdb_search(sam_ctx, + mem_ctx, &msgs, attrs, "(&(name=%s)(objectclass=domain))", r->in.name->name); if (ret <= 0) { + samdb_close(sam_ctx); return NT_STATUS_NO_SUCH_DOMAIN; } if (ret > 1) { - samdb_search_free(mem_ctx, msgs); + samdb_search_free(sam_ctx, mem_ctx, msgs); + samdb_close(sam_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } r->out.info.min_pwd_len = samdb_result_uint(msgs[0], "minPwdLength", 0); r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1); - samdb_search_free(mem_ctx, msgs); + samdb_search_free(sam_ctx, mem_ctx, msgs); + samdb_close(sam_ctx); return NT_STATUS_OK; } diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c index c0e0d12a7b..d384c6ada7 100644 --- a/source4/rpc_server/samr/samdb.c +++ b/source4/rpc_server/samr/samdb.c @@ -22,15 +22,10 @@ #include "includes.h" +struct samdb_context { + struct ldb_context *ldb; +}; -/* - the way that unix fcntl locking works forces us to have a static ldb - handle here rather than a much more sensible approach of having the - ldb handle as part of the samr_Connect() pipe state. Otherwise we - would try to open the ldb more than once, and tdb would rightly - refuse the second open due to the broken nature of unix locking. -*/ -static struct ldb_context *sam_db; /* this is used to catch debug messages from ldb @@ -49,22 +44,48 @@ void samdb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_ /* connect to the SAM database - return 0 on success, -1 on failure + return an opaque context pointer on success, or NULL on failure */ -int samdb_connect(void) +void *samdb_connect(void) { - if (sam_db != NULL) { - return 0; + struct samdb_context *ctx; + /* + the way that unix fcntl locking works forces us to have a + static ldb handle here rather than a much more sensible + approach of having the ldb handle as part of the + samr_Connect() pipe state. Otherwise we would try to open + the ldb more than once, and tdb would rightly refuse the + second open due to the broken nature of unix locking. + */ + static struct ldb_context *static_sam_db; + + if (static_sam_db == NULL) { + static_sam_db = ldb_connect(lp_sam_url(), 0, NULL); + if (static_sam_db == NULL) { + return NULL; + } } - sam_db = ldb_connect(lp_sam_url(), 0, NULL); - if (sam_db == NULL) { - return -1; + ldb_set_debug(static_sam_db, samdb_debug, NULL); + + ctx = malloc_p(struct samdb_context); + if (!ctx) { + errno = ENOMEM; + return NULL; } - ldb_set_debug(sam_db, samdb_debug, NULL); + ctx->ldb = static_sam_db; + + return ctx; +} - return 0; +/* close a connection to the sam */ +void samdb_close(void *ctx) +{ + struct samdb_context *sam_ctx = ctx; + /* we don't actually close due to broken posix locking semantics */ + sam_ctx->ldb = NULL; + free(sam_ctx); } /* @@ -78,12 +99,14 @@ static void *samdb_alloc(void *context, void *ptr, size_t size) /* search the sam for the specified attributes - va_list varient */ -int samdb_search_v(TALLOC_CTX *mem_ctx, +int samdb_search_v(void *ctx, + TALLOC_CTX *mem_ctx, struct ldb_message ***res, char * const *attrs, const char *format, va_list ap) { + struct samdb_context *sam_ctx = ctx; char *expr = NULL; int count; @@ -92,9 +115,9 @@ int samdb_search_v(TALLOC_CTX *mem_ctx, return -1; } - ldb_set_alloc(sam_db, samdb_alloc, mem_ctx); + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); - count = ldb_search(sam_db, NULL, LDB_SCOPE_SUBTREE, expr, attrs, res); + count = ldb_search(sam_ctx->ldb, NULL, LDB_SCOPE_SUBTREE, expr, attrs, res); free(expr); @@ -105,7 +128,8 @@ int samdb_search_v(TALLOC_CTX *mem_ctx, /* search the sam for the specified attributes - varargs varient */ -int samdb_search(TALLOC_CTX *mem_ctx, +int samdb_search(void *ctx, + TALLOC_CTX *mem_ctx, struct ldb_message ***res, char * const *attrs, const char *format, ...) @@ -114,7 +138,7 @@ int samdb_search(TALLOC_CTX *mem_ctx, int count; va_start(ap, format); - count = samdb_search_v(mem_ctx, res, attrs, format, ap); + count = samdb_search_v(ctx, mem_ctx, res, attrs, format, ap); va_end(ap); return count; @@ -123,17 +147,20 @@ int samdb_search(TALLOC_CTX *mem_ctx, /* free up a search result */ -int samdb_search_free(TALLOC_CTX *mem_ctx, struct ldb_message **res) +int samdb_search_free(void *ctx, + TALLOC_CTX *mem_ctx, struct ldb_message **res) { - ldb_set_alloc(sam_db, samdb_alloc, mem_ctx); - return ldb_search_free(sam_db, res); + struct samdb_context *sam_ctx = ctx; + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + return ldb_search_free(sam_ctx->ldb, res); } /* search the sam for a single string attribute in exactly 1 record */ -char *samdb_search_string(TALLOC_CTX *mem_ctx, +char *samdb_search_string(void *ctx, + TALLOC_CTX *mem_ctx, const char *attr_name, const char *format, ...) { @@ -144,7 +171,7 @@ char *samdb_search_string(TALLOC_CTX *mem_ctx, char *str = NULL; va_start(ap, format); - count = samdb_search_v(mem_ctx, &res, attrs, format, ap); + count = samdb_search_v(ctx, mem_ctx, &res, attrs, format, ap); va_end(ap); if (count == 0) { @@ -158,7 +185,7 @@ char *samdb_search_string(TALLOC_CTX *mem_ctx, res[0]->elements[0].values[0].data == NULL) { DEBUG(1,("samdb: search for %s %s not single valued\n", attr_name, format)); - samdb_search_free(mem_ctx, res); + samdb_search_free(ctx, mem_ctx, res); return NULL; } @@ -166,7 +193,7 @@ char *samdb_search_string(TALLOC_CTX *mem_ctx, res[0]->elements[0].values[0].data, res[0]->elements[0].values[0].length); - samdb_search_free(mem_ctx, res); + samdb_search_free(ctx, mem_ctx, res); return str; } @@ -176,7 +203,8 @@ char *samdb_search_string(TALLOC_CTX *mem_ctx, search the sam for multipe records each giving a single string attribute return the number of matches, or -1 on error */ -int samdb_search_string_multiple(TALLOC_CTX *mem_ctx, +int samdb_search_string_multiple(void *ctx, + TALLOC_CTX *mem_ctx, char ***strs, const char *attr_name, const char *format, ...) @@ -187,7 +215,7 @@ int samdb_search_string_multiple(TALLOC_CTX *mem_ctx, struct ldb_message **res = NULL; va_start(ap, format); - count = samdb_search_v(mem_ctx, &res, attrs, format, ap); + count = samdb_search_v(ctx, mem_ctx, &res, attrs, format, ap); va_end(ap); if (count <= 0) { @@ -201,14 +229,14 @@ int samdb_search_string_multiple(TALLOC_CTX *mem_ctx, res[i]->elements[0].values[0].data == NULL) { DEBUG(1,("samdb: search for %s %s not single valued\n", attr_name, format)); - samdb_search_free(mem_ctx, res); + samdb_search_free(ctx, mem_ctx, res); return -1; } } *strs = talloc_array_p(mem_ctx, char *, count+1); if (! *strs) { - samdb_search_free(mem_ctx, res); + samdb_search_free(ctx, mem_ctx, res); return -1; } @@ -219,7 +247,7 @@ int samdb_search_string_multiple(TALLOC_CTX *mem_ctx, } (*strs)[count] = NULL; - samdb_search_free(mem_ctx, res); + samdb_search_free(ctx, mem_ctx, res); return count; } |