diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-05-08 00:02:31 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:51:48 -0500 |
commit | 0ed08d9398d0ee8d9fdbc0f387415adc32ba675e (patch) | |
tree | 6a1dde58667248156c7fd47fb9e3f5aaa2466dec /source4/rpc_server/samr/dcesrv_samr.c | |
parent | a848b0e3e26a3c572bb32475352d460d247d85ee (diff) | |
download | samba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.tar.gz samba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.tar.bz2 samba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.zip |
r578: initial server side implementation of samr_CreateUser(),
samr_CreateUser2(), samr_LookupNames(), samr_OpenUser(),
and samr_DeleteUser()
this uses a user template in the SAM db, of objectclass "userTemplate"
and dn CN=TemplateUser,CN=Templates,$BASEDN. Using a template allows
an admin to add any default user attributes that they might want to
the user template and all new users will receive those attributes.
(This used to be commit 10b6e0011b5952c98432dc2d4b2058ac89a9cc2d)
Diffstat (limited to 'source4/rpc_server/samr/dcesrv_samr.c')
-rw-r--r-- | source4/rpc_server/samr/dcesrv_samr.c | 410 |
1 files changed, 354 insertions, 56 deletions
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 0b443a7078..bea65dceef 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -56,18 +56,20 @@ struct samr_domain_state { uint32 access_mask; const char *domain_sid; const char *domain_name; + const char *basedn; }; /* - state associated with a open user handle + state associated with a open account handle */ -struct samr_user_state { +struct samr_account_state { struct samr_domain_state *domain_state; void *sam_ctx; TALLOC_CTX *mem_ctx; uint32 access_mask; - const char *user_sid; - const char *user_name; + const char *account_sid; + const char *account_name; + const char *basedn; }; @@ -147,10 +149,11 @@ static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_Close *r) { - struct dcesrv_handle *h = dcesrv_handle_fetch(dce_call->conn, - r->in.handle, - DCESRV_HANDLE_ANY); - DCESRV_CHECK_HANDLE(h); + struct dcesrv_handle *h; + + *r->out.handle = *r->in.handle; + + DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY); /* this causes the callback samr_XXX_destroy() to be called by the handle destroy code which destroys the state associated @@ -209,20 +212,18 @@ static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX struct dom_sid2 *sid; const char *sidstr; - h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, SAMR_HANDLE_CONNECT); + r->out.sid = NULL; - DCESRV_CHECK_HANDLE(h); + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT); state = h->data; - r->out.sid = NULL; - if (r->in.domain->name == NULL) { return NT_STATUS_INVALID_PARAMETER; } sidstr = samdb_search_string(state->sam_ctx, - mem_ctx, "objectSid", + mem_ctx, NULL, "objectSid", "(&(name=%s)(objectclass=domain))", r->in.domain->name); if (sidstr == NULL) { @@ -253,21 +254,19 @@ static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX struct samr_connect_state *state; struct dcesrv_handle *h; struct samr_SamArray *array; - char **domains; + const char **domains; int count, i, start_i; - h = dcesrv_handle_fetch(dce_call->conn, r->in.handle, SAMR_HANDLE_CONNECT); - - DCESRV_CHECK_HANDLE(h); - - state = h->data; - *r->out.resume_handle = 0; r->out.sam = NULL; r->out.num_entries = 0; + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT); + + state = h->data; + count = samdb_search_string_multiple(state->sam_ctx, - mem_ctx, &domains, + mem_ctx, NULL, &domains, "name", "(objectclass=domain)"); if (count == -1) { DEBUG(1,("samdb: no domains found in EnumDomains\n")); @@ -310,11 +309,11 @@ static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX /* - destroy an open domain context + close an open domain context */ -static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h) +static void samr_Domain_close(struct dcesrv_connection *conn, + struct samr_domain_state *state) { - struct samr_domain_state *state = h->data; state->reference_count--; if (state->reference_count == 0) { samr_Connect_close(state->connect_state); @@ -322,6 +321,15 @@ static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_ha } } +/* + destroy an open domain context +*/ +static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h) +{ + struct samr_domain_state *state = h->data; + samr_Domain_close(conn, state); +} + /* samr_OpenDomain */ @@ -329,25 +337,38 @@ static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX * struct samr_OpenDomain *r) { struct dcesrv_handle *h_conn, *h_domain; - char *sidstr, *domain_name; + const char *sidstr, *domain_name; struct samr_connect_state *c_state; struct samr_domain_state *state; TALLOC_CTX *mem_ctx2; + const char * const attrs[2] = { "name", NULL}; + struct ldb_message **msgs; + int ret; + + ZERO_STRUCTP(r->out.domain_handle); - h_conn = dcesrv_handle_fetch(dce_call->conn, r->in.handle, SAMR_HANDLE_CONNECT); - DCESRV_CHECK_HANDLE(h_conn); + DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT); c_state = h_conn->data; + if (r->in.sid == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + sidstr = dom_sid_string(mem_ctx, r->in.sid); if (sidstr == NULL) { return NT_STATUS_INVALID_PARAMETER; } - domain_name = samdb_search_string(c_state->sam_ctx, - mem_ctx, "name", - "(&(objectSid=%s)(objectclass=domain))", - sidstr); + ret = samdb_search(c_state->sam_ctx, + mem_ctx, NULL, &msgs, attrs, + "(&(objectSid=%s)(objectclass=domain))", + sidstr); + if (ret != 1) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + domain_name = ldb_msg_find_string(msgs[0], "name", NULL); if (domain_name == NULL) { return NT_STATUS_NO_SUCH_DOMAIN; } @@ -367,8 +388,13 @@ static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX * 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); + state->domain_sid = talloc_strdup(mem_ctx2, sidstr); + state->domain_name = talloc_strdup(mem_ctx2, domain_name); + state->basedn = talloc_strdup(mem_ctx2, msgs[0]->dn); + if (!state->domain_sid || !state->domain_name || !state->basedn) { + talloc_destroy(mem_ctx2); + return NT_STATUS_NO_MEMORY; + } state->access_mask = r->in.access_mask; h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN); @@ -426,43 +452,140 @@ static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC } +/* + destroy an open account context +*/ +static void samr_Account_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h) +{ + struct samr_account_state *state = h->data; + samr_Domain_close(conn, state->domain_state); + talloc_destroy(state->mem_ctx); +} + + /* samr_CreateUser2 + + TODO: This should do some form of locking, especially around the rid allocation */ 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); + struct samr_account_state *state; + struct dcesrv_handle *h; const char *name; + struct ldb_message msg; + uint32 rid; + const char *username, *sidstr; + time_t now = time(NULL); + TALLOC_CTX *mem_ctx2; + struct dcesrv_handle *u_handle; + int ret; + NTSTATUS status; + + ZERO_STRUCTP(r->out.acct_handle); + *r->out.access_granted = 0; + *r->out.rid = 0; - DCESRV_CHECK_HANDLE(h); + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN); d_state = h->data; - if (r->in.username->name == NULL) { + username = r->in.username->name; + + if (username == 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); + name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->basedn, + "name", "(&(name=%s)(objectclass=user))", username); if (name != NULL) { return NT_STATUS_USER_EXISTS; } - /* read the default user template */ + ZERO_STRUCT(msg); + + /* pull in all the template attributes */ + ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, + "(&(name=TemplateUser)(objectclass=userTemplate))"); + if (ret != 0) { + DEBUG(1,("Failed to load TemplateUser from samdb\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + /* allocate a rid */ - /* create a ldb_message for the user */ + status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, + d_state->basedn, "nextRid", &rid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* and the users SID */ + sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid); + if (!sidstr) { + return NT_STATUS_NO_MEMORY; + } + + /* add core elements to the ldb_message for the user */ + msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", username, d_state->basedn); + if (!msg.dn) { + return NT_STATUS_NO_MEMORY; + } + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username); + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username); + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username); + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user"); + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr); + samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now); + samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now); + /* create the user */ + ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg); + if (ret != 0) { + DEBUG(1,("Failed to create user record %s\n", msg.dn)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + /* create user state and new policy handle */ - + mem_ctx2 = talloc_init("CreateUser(%s)", username); + if (!mem_ctx2) { + return NT_STATUS_NO_MEMORY; + } - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + state = talloc_p(mem_ctx2, struct samr_account_state); + if (!state) { + return NT_STATUS_NO_MEMORY; + } + state->mem_ctx = mem_ctx2; + state->sam_ctx = d_state->sam_ctx; + state->access_mask = r->in.access_mask; + state->domain_state = d_state; + state->basedn = talloc_steal(mem_ctx, mem_ctx2, msg.dn); + state->account_sid = talloc_strdup(mem_ctx2, sidstr); + state->account_name = talloc_strdup(mem_ctx2, username); + if (!state->account_name || !state->account_sid) { + return NT_STATUS_NO_MEMORY; + } + + /* create the policy handle */ + u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER); + if (!u_handle) { + return NT_STATUS_NO_MEMORY; + } + + u_handle->data = state; + u_handle->destroy = samr_Account_destroy; + + /* the domain state is in use one more time */ + d_state->reference_count++; + + *r->out.acct_handle = u_handle->wire_handle; + *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */ + *r->out.rid = rid; + + return NT_STATUS_OK; } @@ -473,7 +596,7 @@ static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX * struct samr_CreateUser *r) { struct samr_CreateUser2 r2; - uint32 access_granted, rid; + uint32 access_granted; /* a simple wrapper around samr_CreateUser2 works nicely */ @@ -483,7 +606,7 @@ static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX * r2.in.access_mask = r->in.access_mask; r2.out.acct_handle = r->out.acct_handle; r2.out.access_granted = &access_granted; - r2.out.rid = &rid; + r2.out.rid = r->out.rid; return samr_CreateUser2(dce_call, mem_ctx, &r2); } @@ -533,9 +656,90 @@ static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALL samr_LookupNames */ static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_LookupNames *r) + struct samr_LookupNames *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct dcesrv_handle *h; + struct samr_domain_state *state; + int i; + NTSTATUS status = NT_STATUS_OK; + const char * const attrs[] = { "sAMAccountType", "objectSid", NULL }; + int count; + + ZERO_STRUCT(r->out.rids); + ZERO_STRUCT(r->out.types); + + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN); + + state = h->data; + + if (r->in.num_names == 0) { + return NT_STATUS_OK; + } + + r->out.rids.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names); + r->out.types.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names); + if (!r->out.rids.ids || !r->out.types.ids) { + return NT_STATUS_NO_MEMORY; + } + r->out.rids.count = r->in.num_names; + r->out.types.count = r->in.num_names; + + for (i=0;i<r->in.num_names;i++) { + struct ldb_message **res; + struct dom_sid2 *sid; + const char *sidstr; + uint32 atype, rtype; + + r->out.rids.ids[i] = 0; + r->out.types.ids[i] = SID_NAME_UNKNOWN; + + count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs, + "sAMAccountName=%s", r->in.names[i].name); + if (count != 1) { + status = STATUS_SOME_UNMAPPED; + continue; + } + + sidstr = samdb_result_string(res[0], "objectSid", NULL); + if (sidstr == NULL) { + status = STATUS_SOME_UNMAPPED; + continue; + } + + sid = dom_sid_parse_talloc(mem_ctx, sidstr); + if (sid == NULL) { + status = STATUS_SOME_UNMAPPED; + continue; + } + + atype = samdb_result_uint(res[0], "sAMAccountType", 0); + if (atype == 0) { + status = STATUS_SOME_UNMAPPED; + continue; + } + + switch (atype & 0xF0000000) { + case ATYPE_ACCOUNT: + rtype = SID_NAME_USER; + break; + case ATYPE_GLOBAL_GROUP: + rtype = SID_NAME_DOM_GRP; + break; + case ATYPE_LOCAL_GROUP: + rtype = SID_NAME_ALIAS; + break; + default: + DEBUG(1,("Unknown sAMAccountType 0x%08x\n", atype)); + status = STATUS_SOME_UNMAPPED; + continue; + } + + r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1]; + r->out.types.ids[i] = rtype; + } + + + return status; } @@ -703,9 +907,86 @@ static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLO samr_OpenUser */ static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_OpenUser *r) + struct samr_OpenUser *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct samr_domain_state *d_state; + struct samr_account_state *state; + struct dcesrv_handle *h; + const char *username, *sidstr; + TALLOC_CTX *mem_ctx2; + struct ldb_message **msgs; + struct dcesrv_handle *u_handle; + const char * const attrs[2] = { "sAMAccountName", NULL }; + int ret; + + ZERO_STRUCTP(r->out.acct_handle); + + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN); + + d_state = h->data; + + /* form the users SID */ + sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid); + if (!sidstr) { + return NT_STATUS_NO_MEMORY; + } + + /* search for the user record */ + ret = samdb_search(d_state->sam_ctx, + mem_ctx, d_state->basedn, &msgs, attrs, + "(&(objectSid=%s)(objectclass=user))", + sidstr); + if (ret == 0) { + return NT_STATUS_NO_SUCH_USER; + } + if (ret != 1) { + DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + username = samdb_result_string(msgs[0], "sAMAccountName", NULL); + if (username == NULL) { + DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* create user state and new policy handle */ + mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid); + if (!mem_ctx2) { + return NT_STATUS_NO_MEMORY; + } + + state = talloc_p(mem_ctx2, struct samr_account_state); + if (!state) { + return NT_STATUS_NO_MEMORY; + } + state->mem_ctx = mem_ctx2; + state->sam_ctx = d_state->sam_ctx; + state->access_mask = r->in.access_mask; + state->domain_state = d_state; + state->basedn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn); + state->account_sid = talloc_strdup(mem_ctx2, sidstr); + state->account_name = talloc_strdup(mem_ctx2, username); + if (!state->account_name || !state->account_sid) { + return NT_STATUS_NO_MEMORY; + } + + /* create the policy handle */ + u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER); + if (!u_handle) { + return NT_STATUS_NO_MEMORY; + } + + u_handle->data = state; + u_handle->destroy = samr_Account_destroy; + + /* the domain state is in use one more time */ + d_state->reference_count++; + + *r->out.acct_handle = u_handle->wire_handle; + + return NT_STATUS_OK; + } @@ -713,9 +994,26 @@ static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *me samr_DeleteUser */ static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_DeleteUser *r) + struct samr_DeleteUser *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct dcesrv_handle *h; + struct samr_account_state *state; + int ret; + + *r->out.handle = *r->in.handle; + + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER); + + state = h->data; + + ret = samdb_delete(state->sam_ctx, mem_ctx, state->basedn); + if (ret != 0) { + return NT_STATUS_UNSUCCESSFUL; + } + + ZERO_STRUCTP(r->out.handle); + + return NT_STATUS_OK; } @@ -919,7 +1217,7 @@ static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX { struct ldb_message **msgs; int ret; - char * const attrs[] = {"minPwdLength", "pwdProperties", NULL }; + const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL }; void *sam_ctx; if (r->in.name == NULL || r->in.name->name == NULL) { @@ -932,7 +1230,7 @@ static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX } ret = samdb_search(sam_ctx, - mem_ctx, &msgs, attrs, + mem_ctx, NULL, &msgs, attrs, "(&(name=%s)(objectclass=domain))", r->in.name->name); if (ret <= 0) { |