r8721: Further work on libnet_rpc_usermod function. Now it can change
[jra/samba/.git] / source4 / libnet / userman.c
index 51bcdc885e08b13a0c206ad456a9659aeb869bb2..37b3d1e7233f6ea055e6180cf024b4d210d6233d 100644 (file)
@@ -25,6 +25,7 @@
 #include "includes.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
+#include "libcli/composite/monitor.h"
 #include "librpc/gen_ndr/ndr_samr.h"
 #include "libnet/composite.h"
 
@@ -71,10 +72,13 @@ static void useradd_handler(struct rpc_request *req)
 {
        struct composite_context *c = req->async.private;
        struct useradd_state *s = talloc_get_type(c->private, struct useradd_state);
+       struct monitor_msg msg;
        
        switch (s->stage) {
        case USERADD_CREATE:
                c->status = useradd_create(c, s);
+               msg.type = rpc_create_user;
+               msg.data.rpc_create_user.rid = *s->createuser.out.rid;
                break;
        }
 
@@ -82,6 +86,10 @@ static void useradd_handler(struct rpc_request *req)
                c->state = SMBCLI_REQUEST_ERROR;
        }
 
+       if (c->monitor_fn) {
+               c->monitor_fn(&msg);
+       }
+
        if (c->state >= SMBCLI_REQUEST_DONE &&
            c->async.fn) {
                c->async.fn(c);
@@ -96,12 +104,12 @@ static void useradd_handler(struct rpc_request *req)
  * @param io arguments and results of the call
  */
 
-struct composite_context *rpc_composite_useradd_send(struct dcerpc_pipe *p,
-                                                    struct rpc_composite_useradd *io)
+struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
+                                                 struct libnet_rpc_useradd *io,
+                                                 void (*monitor)(struct monitor_msg*))
 {
        struct composite_context *c;
        struct useradd_state *s;
-       struct dom_sid *sid;
        
        c = talloc_zero(p, struct composite_context);
        if (c == NULL) goto failure;
@@ -112,13 +120,14 @@ struct composite_context *rpc_composite_useradd_send(struct dcerpc_pipe *p,
        s->domain_handle = io->in.domain_handle;
        s->pipe          = p;
        
-       c->state     = SMBCLI_REQUEST_SEND;
-       c->private   = s;
-       c->event_ctx = dcerpc_event_context(p);
+       c->state       = SMBCLI_REQUEST_SEND;
+       c->private     = s;
+       c->event_ctx   = dcerpc_event_context(p);
+       c->monitor_fn  = monitor;
 
        /* preparing parameters to send rpc request */
        s->createuser.in.domain_handle         = &io->in.domain_handle;
-       s->createuser.in.account_name          = talloc_zero(c, struct samr_String);
+       s->createuser.in.account_name          = talloc_zero(c, struct lsa_String);
        s->createuser.in.account_name->string  = talloc_strdup(c, io->in.username);
        s->createuser.out.user_handle          = &s->user_handle;
        s->createuser.out.rid                  = &s->user_rid;
@@ -148,8 +157,8 @@ failure:
  * @return nt status code of execution
  */
 
-NTSTATUS rpc_composite_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
-                                   struct rpc_composite_useradd *io)
+NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                                   struct libnet_rpc_useradd *io)
 {
        NTSTATUS status;
        struct useradd_state *s;
@@ -176,12 +185,12 @@ NTSTATUS rpc_composite_useradd_recv(struct composite_context *c, TALLOC_CTX *mem
  * @return nt status code of execution
  */
 
-NTSTATUS rpc_composite_useradd(struct dcerpc_pipe *pipe,
+NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *pipe,
                               TALLOC_CTX *mem_ctx,
-                              struct rpc_composite_useradd *io)
+                              struct libnet_rpc_useradd *io)
 {
-       struct composite_context *c = rpc_composite_useradd_send(pipe, io);
-       return rpc_composite_useradd_recv(c, mem_ctx, io);
+       struct composite_context *c = libnet_rpc_useradd_send(pipe, io, NULL);
+       return libnet_rpc_useradd_recv(c, mem_ctx, io);
 }
 
 
@@ -237,9 +246,6 @@ static NTSTATUS userdel_lookup(struct composite_context *c,
        s->stage = USERDEL_OPEN;
        
        return NT_STATUS_OK;
-failure:
-       talloc_free(c);
-       return status;
 }
 
 
@@ -249,8 +255,6 @@ failure:
 static NTSTATUS userdel_open(struct composite_context *c,
                             struct userdel_state *s)
 {
-       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       
        c->status = dcerpc_ndr_request_recv(s->req);
        NT_STATUS_NOT_OK_RETURN(c->status);
        
@@ -273,8 +277,6 @@ static NTSTATUS userdel_open(struct composite_context *c,
 static NTSTATUS userdel_delete(struct composite_context *c,
                               struct userdel_state *s)
 {
-       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       
        c->status = dcerpc_ndr_request_recv(s->req);
        NT_STATUS_NOT_OK_RETURN(c->status);
        
@@ -294,6 +296,7 @@ static void userdel_handler(struct rpc_request *req)
 {
        struct composite_context *c = req->async.private;
        struct userdel_state *s = talloc_get_type(c->private, struct userdel_state);
+       struct monitor_msg msg;
        
        switch (s->stage) {
        case USERDEL_LOOKUP:
@@ -311,6 +314,10 @@ static void userdel_handler(struct rpc_request *req)
                c->state = SMBCLI_REQUEST_ERROR;
        }
 
+       if (c->monitor_fn) {
+               c->monitor_fn(&msg);
+       }
+
        if (c->state >= SMBCLI_REQUEST_DONE &&
            c->async.fn) {
                c->async.fn(c);
@@ -325,8 +332,8 @@ static void userdel_handler(struct rpc_request *req)
  * @param io arguments and results of the call
  */
 
-struct composite_context *rpc_composite_userdel_send(struct dcerpc_pipe *p,
-                                                    struct rpc_composite_userdel *io)
+struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
+                                                 struct libnet_rpc_userdel *io)
 {
        struct composite_context *c;
        struct userdel_state *s;
@@ -347,7 +354,7 @@ struct composite_context *rpc_composite_userdel_send(struct dcerpc_pipe *p,
        /* preparing parameters to send rpc request */
        s->lookupname.in.domain_handle = &io->in.domain_handle;
        s->lookupname.in.num_names     = 1;
-       s->lookupname.in.names         = talloc_zero(s, struct samr_String);
+       s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
        s->lookupname.in.names->string = io->in.username;
 
        /* send the request */
@@ -375,8 +382,8 @@ failure:
  * @return nt status code of execution
  */
 
-NTSTATUS rpc_composite_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
-                                   struct rpc_composite_userdel *io)
+NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                                struct libnet_rpc_userdel *io)
 {
        NTSTATUS status;
        struct userdel_state *s;
@@ -393,10 +400,225 @@ NTSTATUS rpc_composite_userdel_recv(struct composite_context *c, TALLOC_CTX *mem
 }
 
 
-NTSTATUS rpc_composite_userdel(struct dcerpc_pipe *pipe,
-                              TALLOC_CTX *mem_ctx,
-                              struct rpc_composite_userdel *io)
+/**
+ * Synchronous version of userdel call
+ *
+ * @param pipe dce/rpc call pipe
+ * @param mem_ctx memory context for the call
+ * @param io arguments and results of the call
+ * @return nt status code of execution
+ */
+
+NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *pipe,
+                           TALLOC_CTX *mem_ctx,
+                           struct libnet_rpc_userdel *io)
+{
+       struct composite_context *c = libnet_rpc_userdel_send(pipe, io);
+       return libnet_rpc_userdel_recv(c, mem_ctx, io);
+}
+
+
+static void usermod_handler(struct rpc_request*);
+
+enum usermod_stage { USERMOD_LOOKUP, USERMOD_OPEN, USERMOD_MODIFY };
+
+struct usermod_state {
+       enum usermod_stage        stage;
+       struct dcerpc_pipe        *pipe;
+       struct rpc_request        *req;
+       struct policy_handle      domain_handle;
+       struct policy_handle      user_handle;
+       struct usermod_change     change;
+       union  samr_UserInfo      info;
+       struct samr_LookupNames   lookupname;
+       struct samr_OpenUser      openuser;
+       struct samr_SetUserInfo   setuser;
+};
+
+
+static NTSTATUS usermod_lookup(struct composite_context *c,
+                              struct usermod_state *s)
+{
+       NTSTATUS status;
+
+       c->status = dcerpc_ndr_request_recv(s->req);
+       NT_STATUS_NOT_OK_RETURN(c->status);
+
+       if (!s->lookupname.out.rids.count) {
+               /* TODO: no such user */
+               status = NT_STATUS_NO_SUCH_USER;
+
+       } else if (!s->lookupname.out.rids.count > 1) {
+               /* TODO: ambiguous username */
+               status = NT_STATUS_INVALID_ACCOUNT_NAME;
+       }
+
+       s->openuser.in.domain_handle = &s->domain_handle;
+       s->openuser.in.rid           = s->lookupname.out.rids.ids[0];
+       s->openuser.in.access_mask   = SEC_FLAG_MAXIMUM_ALLOWED;
+       s->openuser.out.user_handle  = &s->user_handle;
+
+       s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
+
+       s->req->async.callback = usermod_handler;
+       s->req->async.private  = c;
+       s->stage = USERMOD_OPEN;
+       
+       return NT_STATUS_OK;
+}
+
+
+static NTSTATUS usermod_open(struct composite_context *c,
+                            struct usermod_state *s)
+{
+       union samr_UserInfo *i = &s->info;
+       uint16_t level;
+
+       c->status = dcerpc_ndr_request_recv(s->req);
+       NT_STATUS_NOT_OK_RETURN(c->status);
+
+       s->setuser.in.user_handle  = &s->user_handle;
+
+       /* Prepare UserInfo level and data based on bitmask field */
+       if (s->change.fields) {
+               if (s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) {
+                       level = 7;
+                       i->info7.account_name.length = 2*strlen_m(s->change.account_name);
+                       i->info7.account_name.size   = 2*strlen_m(s->change.account_name);
+                       i->info7.account_name.string = s->change.account_name;
+
+                       s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
+
+               } else if (s->change.fields & USERMOD_FIELD_FULL_NAME) {
+                       level = 8;
+                       i->info8.full_name.length = 2*strlen_m(s->change.full_name);
+                       i->info8.full_name.size   = 2*strlen_m(s->change.full_name);
+                       i->info8.full_name.string = s->change.full_name;
+                       
+                       s->change.fields ^= USERMOD_FIELD_FULL_NAME;
+               }
+       }
+
+       s->setuser.in.level        = level;
+       s->setuser.in.info         = i;
+
+       s->req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
+
+       s->req->async.callback = usermod_handler;
+       s->req->async.private  = c;
+
+       /* Get back here again unless all fields have been set */
+       if (s->change.fields) {
+               s->stage = USERMOD_OPEN;
+       } else {
+               s->stage = USERMOD_MODIFY;
+       }
+
+       return NT_STATUS_OK;
+}
+
+
+static NTSTATUS usermod_modify(struct composite_context *c,
+                              struct usermod_state *s)
+{
+       c->status = dcerpc_ndr_request_recv(s->req);
+       NT_STATUS_NOT_OK_RETURN(c->status);
+
+       c->state = SMBCLI_REQUEST_DONE;
+
+       return NT_STATUS_OK;
+}
+
+
+static void usermod_handler(struct rpc_request *req)
+{
+       struct composite_context *c = req->async.private;
+       struct usermod_state *s = talloc_get_type(c->private, struct usermod_state);
+       struct monitor_msg msg;
+
+       switch (s->stage) {
+       case USERMOD_LOOKUP:
+               c->status = usermod_lookup(c, s);
+               break;
+       case USERMOD_OPEN:
+               c->status = usermod_open(c, s);
+               break;
+       case USERMOD_MODIFY:
+               c->status = usermod_modify(c, s);
+               break;
+       }
+
+       if (!NT_STATUS_IS_OK(c->status)) {
+               c->state = SMBCLI_REQUEST_ERROR;
+       }
+
+       if (c->monitor_fn) {
+               c->monitor_fn(&msg);
+       }
+
+       if (c->state >= SMBCLI_REQUEST_DONE &&
+           c->async.fn) {
+               c->async.fn(c);
+       }
+}
+
+
+struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
+                                                 struct libnet_rpc_usermod *io)
+{
+       struct composite_context *c;
+       struct usermod_state *s;
+       
+       c = talloc_zero(p, struct composite_context);
+       if (c == NULL) goto failure;
+
+       s = talloc_zero(c, struct usermod_state);
+       if (s == NULL) goto failure;
+
+       c->state      = SMBCLI_REQUEST_SEND;
+       c->private    = s;
+       c->event_ctx  = dcerpc_event_context(p);
+
+       s->pipe          = p;
+       s->domain_handle = io->in.domain_handle;
+       s->change        = io->in.change;
+       
+       s->lookupname.in.domain_handle = &io->in.domain_handle;
+       s->lookupname.in.num_names     = 1;
+       s->lookupname.in.names         = talloc_zero(s, struct lsa_String);
+       s->lookupname.in.names->string = io->in.username;
+       
+       s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
+       
+       s->req->async.callback = usermod_handler;
+       s->req->async.private  = c;
+       s->stage = USERMOD_LOOKUP;
+
+       return c;
+
+failure:
+       talloc_free(c);
+       return NULL;
+}
+
+
+NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                                struct libnet_rpc_usermod *io)
+{
+       NTSTATUS status;
+       struct usermod_state *s;
+       
+       status = composite_wait(c);
+
+       talloc_free(c);
+       return status;
+}
+
+
+NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *pipe,
+                           TALLOC_CTX *mem_ctx,
+                           struct libnet_rpc_usermod *io)
 {
-       struct composite_context *c = rpc_composite_userdel_send(pipe, io);
-       return rpc_composite_userdel_recv(c, mem_ctx, io);
+       struct composite_context *c = libnet_rpc_usermod_send(pipe, io);
+       return libnet_rpc_usermod_recv(c, mem_ctx, io);
 }