python: Don't try to free const pointers.
[ira/wip.git] / source / libnet / userinfo.c
index 88ef80c53c849ca02f4b424626fedf137e57867a..847997fc12f6b6faab8eb2bc3c38b01106284723 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
 */
 
 #include "includes.h"
-#include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
-#include "librpc/gen_ndr/ndr_samr.h"
-
-enum userinfo_stage { USERINFO_OPENUSER, USERINFO_GETUSER, USERINFO_CLOSEUSER };
-
-struct rpc_composite_userinfo {
-       struct {
-               struct policy_handle domain_handle;
-               const char *sid;
-               uint16_t level;
-       } in;
-       struct {
-               union samr_UserInfo info;
-       } out;
-};
+#include "libnet/composite.h"
+#include "librpc/gen_ndr/security.h"
+#include "libcli/security/security.h"
+#include "libnet/userman.h"
+#include "libnet/userinfo.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+
 
 struct userinfo_state {
-       enum userinfo_stage stage;
-       struct dcerpc_pipe *pipe;
-       struct rpc_composite_userinfo io;
+       struct dcerpc_pipe        *pipe;
+       struct policy_handle      domain_handle;
+       struct policy_handle      user_handle;
+       uint16_t                  level;
+       struct samr_LookupNames   lookup;
+       struct samr_OpenUser      openuser;
+       struct samr_QueryUserInfo queryuserinfo;
+       struct samr_Close         samrclose;    
+       union  samr_UserInfo      *info;
+
+       /* information about the progress */
+       void (*monitor_fn)(struct monitor_msg *);
 };
 
-static void userinfo_handler(struct rpc_request *req);
+
+static void continue_userinfo_lookup(struct rpc_request *req);
+static void continue_userinfo_openuser(struct rpc_request *req);
+static void continue_userinfo_getuser(struct rpc_request *req);
+static void continue_userinfo_closeuser(struct rpc_request *req);
 
 
-static NTSTATUS userinfo_openuser(struct composite_context *c,
-                                 struct rpc_composite_userinfo *io)
+/**
+ * Stage 1 (optional): Look for a username in SAM server.
+ */
+static void continue_userinfo_lookup(struct rpc_request *req)
 {
-       struct userinfo_state *s = talloc_get_type(c->private, struct userinfo_state);
-       struct rpc_request *req = s->pipe->conn->pending;
-       struct samr_OpenUser *rep;
-       struct samr_QueryUserInfo r;
+       struct composite_context *c;
+       struct userinfo_state *s;
+       struct rpc_request *openuser_req;
+       struct monitor_msg msg;
+       struct msg_rpc_lookup_name *msg_lookup;
+
+       c = talloc_get_type(req->async.private_data, struct composite_context);
+       s = talloc_get_type(c->private_data, struct userinfo_state);
+
+       /* receive samr_Lookup reply */
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
+       
+       /* there could be a problem with name resolving itself */
+       if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
+               composite_error(c, s->lookup.out.result);
+               return;
+       }
+
+       /* issue a monitor message */
+       if (s->monitor_fn) {
+               msg.type = mon_SamrLookupName;
+               msg_lookup = talloc(s, struct msg_rpc_lookup_name);
+               msg_lookup->rid = s->lookup.out.rids.ids;
+               msg_lookup->count = s->lookup.out.rids.count;
+               msg.data = (void*)msg_lookup;
+               msg.data_size = sizeof(*msg_lookup);
+               
+               s->monitor_fn(&msg);
+       }
+       
+
+       /* have we actually got name resolved
+          - we're looking for only one at the moment */
+       if (s->lookup.out.rids.count == 0) {
+               composite_error(c, NT_STATUS_NO_SUCH_USER);
+       }
+
+       /* TODO: find proper status code for more than one rid found */
+
+       /* prepare parameters for LookupNames */
+       s->openuser.in.domain_handle  = &s->domain_handle;
+       s->openuser.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
+       s->openuser.in.rid            = s->lookup.out.rids.ids[0];
+       s->openuser.out.user_handle   = &s->user_handle;
+
+       /* send request */
+       openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
+       if (composite_nomem(openuser_req, c)) return;
+
+       composite_continue_rpc(c, openuser_req, continue_userinfo_openuser, c);
+}
+
+
+/**
+ * Stage 2: Open user policy handle.
+ */
+static void continue_userinfo_openuser(struct rpc_request *req)
+{
+       struct composite_context *c;
+       struct userinfo_state *s;
+       struct rpc_request *queryuser_req;
+       struct monitor_msg msg;
+       struct msg_rpc_open_user *msg_open;
+
+       c = talloc_get_type(req->async.private_data, struct composite_context);
+       s = talloc_get_type(c->private_data, struct userinfo_state);
 
        /* receive samr_OpenUser reply */
        c->status = dcerpc_ndr_request_recv(req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
-       rep = (struct samr_OpenUser*)req->ndr.struct_ptr;
+       if (!composite_is_ok(c)) return;
 
+       if (!NT_STATUS_IS_OK(s->queryuserinfo.out.result)) {
+               composite_error(c, s->queryuserinfo.out.result);
+               return;
+       }
+
+       /* issue a monitor message */
+       if (s->monitor_fn) {
+               msg.type = mon_SamrOpenUser;
+               msg_open = talloc(s, struct msg_rpc_open_user);
+               msg_open->rid = s->openuser.in.rid;
+               msg_open->access_mask = s->openuser.in.access_mask;
+               msg.data = (void*)msg_open;
+               msg.data_size = sizeof(*msg_open);
+               
+               s->monitor_fn(&msg);
+       }
+       
        /* prepare parameters for QueryUserInfo call */
-       r.in.user_handle = talloc_zero(c, struct policy_handle);
-       memcpy((void*)r.in.user_handle, (void*)rep->out.user_handle, sizeof(struct policy_handle));
-       r.in.level = io->in.level;
+       s->queryuserinfo.in.user_handle = &s->user_handle;
+       s->queryuserinfo.in.level       = s->level;
        
        /* queue rpc call, set event handling and new state */
-       s->pipe->conn->pending = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &r);
-       
-       s->pipe->conn->pending->async.callback = userinfo_handler;
-       s->pipe->conn->pending->async.private  = c;
-       s->stage = USERINFO_GETUSER;
+       queryuser_req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuserinfo);
+       if (composite_nomem(queryuser_req, c)) return;
        
-       return rep->out.result;
+       composite_continue_rpc(c, queryuser_req, continue_userinfo_getuser, c);
 }
 
 
-static NTSTATUS userinfo_getuser(struct composite_context *c,
-                                struct rpc_composite_userinfo *io)
+/**
+ * Stage 3: Get requested user information.
+ */
+static void continue_userinfo_getuser(struct rpc_request *req)
 {
-       struct userinfo_state *s = talloc_get_type(c->private, struct userinfo_state);
-       struct rpc_request *req = s->pipe->conn->pending;
-       struct samr_QueryUserInfo *rep;
-       struct samr_Close r;
-       
+       struct composite_context *c;
+       struct userinfo_state *s;
+       struct rpc_request *close_req;
+       struct monitor_msg msg;
+       struct msg_rpc_query_user *msg_query;
+
+       c = talloc_get_type(req->async.private_data, struct composite_context);
+       s = talloc_get_type(c->private_data, struct userinfo_state);
+
        /* receive samr_QueryUserInfo reply */
        c->status = dcerpc_ndr_request_recv(req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
-       rep = (struct samr_QueryUserInfo*)req->ndr.struct_ptr;
+       if (!composite_is_ok(c)) return;
+
+       /* check if queryuser itself went ok */
+       if (!NT_STATUS_IS_OK(s->queryuserinfo.out.result)) {
+               composite_error(c, s->queryuserinfo.out.result);
+               return;
+       }
+
+       s->info = talloc_steal(s, s->queryuserinfo.out.info);
+
+       /* issue a monitor message */
+       if (s->monitor_fn) {
+               msg.type = mon_SamrQueryUser;
+               msg_query = talloc(s, struct msg_rpc_query_user);
+               msg_query->level = s->queryuserinfo.in.level;
+               msg.data = (void*)msg_query;
+               msg.data_size = sizeof(*msg_query);
+               
+               s->monitor_fn(&msg);
+       }
        
        /* prepare arguments for Close call */
-       r.in.handle = talloc_zero(c, struct policy_handle);
-       memcpy((void*)r.in.handle, (void*)rep->in.user_handle, sizeof(struct policy_handle));
+       s->samrclose.in.handle  = &s->user_handle;
+       s->samrclose.out.handle = &s->user_handle;
        
        /* queue rpc call, set event handling and new state */
-       s->pipe->conn->pending = dcerpc_samr_Close_send(s->pipe, c, &r);
+       close_req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
+       if (composite_nomem(close_req, c)) return;
        
-       s->pipe->conn->pending->async.callback = userinfo_handler;
-       s->pipe->conn->pending->async.private  = c;
-       s->stage = USERINFO_CLOSEUSER;
-
-       /* copying result of composite call */
-       memcpy((void*)&io->out.info, (void*)rep->out.info, sizeof(union samr_UserInfo));
-
-       return rep->out.result;
+       composite_continue_rpc(c, close_req, continue_userinfo_closeuser, c);
 }
 
 
-static NTSTATUS userinfo_closeuser(struct composite_context *c,
-                                  struct rpc_composite_userinfo *io)
+/**
+ * Stage 4: Close policy handle associated with opened user.
+ */
+static void continue_userinfo_closeuser(struct rpc_request *req)
 {
-       struct userinfo_state *s = talloc_get_type(c->private, struct userinfo_state);
-       struct rpc_request *req = s->pipe->conn->pending;
-       struct samr_Close *rep;
-       
-       /* receive samr_Close reply */
-       c->status = dcerpc_ndr_request_recv(req);
-       NT_STATUS_NOT_OK_RETURN(c->status);
-       rep = (struct samr_Close*)req->ndr.struct_ptr;
-
-       /* return result */
-       return rep->out.result;
-}
-
+       struct composite_context *c;
+       struct userinfo_state *s;
+       struct monitor_msg msg;
+       struct msg_rpc_close_user *msg_close;
 
-static void userinfo_handler(struct rpc_request *req)
-{
-       struct composite_context *c = req->async.private;
-       struct userinfo_state *s = talloc_get_type(c->private, struct userinfo_state);
+       c = talloc_get_type(req->async.private_data, struct composite_context);
+       s = talloc_get_type(c->private_data, struct userinfo_state);
 
-       switch (s->stage) {
-       case USERINFO_OPENUSER:
-               c->status = userinfo_openuser(c, &s->io);
-               break;
+       /* receive samr_Close reply */
+       c->status = dcerpc_ndr_request_recv(req);
+       if (!composite_is_ok(c)) return;
 
-       case USERINFO_GETUSER:
-               c->status = userinfo_getuser(c, &s->io);
-               break;
-               
-       case USERINFO_CLOSEUSER:
-               c->status = userinfo_closeuser(c, &s->io);
-               break;
+       if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
+               composite_error(c, s->samrclose.out.result);
+               return;
        }
 
-       if (!NT_STATUS_IS_OK(c->status)) {
-               /* this should be some error state instead */
-               c->state = RPC_REQUEST_DONE;
-       }
+       /* issue a monitor message */
+       if (s->monitor_fn) {
+               msg.type = mon_SamrClose;
+               msg_close = talloc(s, struct msg_rpc_close_user);
+               msg_close->rid = s->openuser.in.rid;
+               msg.data = (void*)msg_close;
+               msg.data_size = sizeof(*msg_close);
 
-       if (c->state >= RPC_REQUEST_DONE &&
-           c->async.fn) {
-               c->async.fn(c);
+               s->monitor_fn(&msg);
        }
-}
 
+       composite_done(c);
+}
 
-struct composite_context* rpc_composite_userinfo_send(struct dcerpc_pipe *p,
-                                                     struct rpc_composite_userinfo *io)
-{      
 
+/**
+ * Sends asynchronous userinfo request
+ *
+ * @param p dce/rpc call pipe 
+ * @param io arguments and results of the call
+ */
+struct composite_context *libnet_rpc_userinfo_send(struct dcerpc_pipe *p,
+                                                  struct libnet_rpc_userinfo *io,
+                                                  void (*monitor)(struct monitor_msg*))
+{
        struct composite_context *c;
        struct userinfo_state *s;
-       struct samr_OpenUser *r;
        struct dom_sid *sid;
+       struct rpc_request *openuser_req, *lookup_req;
+
+       if (!p || !io) return NULL;
        
-       c = talloc_zero(p, struct composite_context);
-       if (c == NULL) goto failure;
+       c = composite_create(p, dcerpc_event_context(p));
+       if (c == NULL) return c;
        
        s = talloc_zero(c, struct userinfo_state);
-       if (s == NULL) goto failure;
-       
-       /* copying input parameters */
-       memcpy((void*)&s->io.in.domain_handle, (void*)&io->in.domain_handle, sizeof(struct policy_handle));
-       s->io.in.sid     = talloc_strdup(p, io->in.sid);
-       s->io.in.level   = io->in.level;
-       sid              = dom_sid_parse_talloc(c, s->io.in.sid);
-       
-       c->private = s;
-       c->event_ctx = dcerpc_event_context(p);
+       if (composite_nomem(s, c)) return c;
 
-       /* preparing parameters to send rpc request */
-       r = talloc_zero(p, struct samr_OpenUser);
-       r->in.domain_handle  = &s->io.in.domain_handle;
-       r->in.access_mask    = 0;
-       r->in.rid            = sid->sub_auths[sid->num_auths - 1];
+       c->private_data = s;
 
-       /* send request */
-       s->pipe->conn->pending = dcerpc_samr_OpenUser_send(p, c, r);
+       s->level         = io->in.level;
+       s->pipe          = p;
+       s->domain_handle = io->in.domain_handle;
+       s->monitor_fn    = monitor;
+
+       if (io->in.sid) {
+               sid = dom_sid_parse_talloc(s, io->in.sid);
+               if (composite_nomem(sid, c)) return c;
+
+               s->openuser.in.domain_handle  = &s->domain_handle;
+               s->openuser.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
+               s->openuser.in.rid            = sid->sub_auths[sid->num_auths - 1];
+               s->openuser.out.user_handle   = &s->user_handle;
+               
+               /* send request */
+               openuser_req = dcerpc_samr_OpenUser_send(p, c, &s->openuser);
+               if (composite_nomem(openuser_req, c)) return c;
+
+               composite_continue_rpc(c, openuser_req, continue_userinfo_openuser, c);
 
-       /* callback handler */
-       s->pipe->conn->pending->async.callback = userinfo_handler;
-       s->pipe->conn->pending->async.private  = c;
-       s->stage = USERINFO_OPENUSER;
+       } else {
+               /* preparing parameters to send rpc request */
+               s->lookup.in.domain_handle    = &s->domain_handle;
+               s->lookup.in.num_names        = 1;
+               s->lookup.in.names            = talloc_array(s, struct lsa_String, 1);
+               if (composite_nomem(s->lookup.in.names, c)) return c;
+
+               s->lookup.in.names[0].string  = talloc_strdup(s, io->in.username);
+               if (composite_nomem(s->lookup.in.names[0].string, c)) return c;
+               
+               /* send request */
+               lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookup);
+               if (composite_nomem(lookup_req, c)) return c;
+               
+               composite_continue_rpc(c, lookup_req, continue_userinfo_lookup, c);
+       }
 
        return c;
-       
-failure:
-       talloc_free(c);
 }
 
 
-NTSTATUS rpc_composite_userinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
+/**
+ * Waits for and receives result of asynchronous userinfo call
+ * 
+ * @param c composite context returned by asynchronous userinfo call
+ * @param mem_ctx memory context of the call
+ * @param io pointer to results (and arguments) of the call
+ * @return nt status code of execution
+ */
+
+NTSTATUS libnet_rpc_userinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
+                                 struct libnet_rpc_userinfo *io)
 {
        NTSTATUS status;
        struct userinfo_state *s;
        
+       /* wait for results of sending request */
        status = composite_wait(c);
        
-       if (NT_STATUS_IS_OK(status)) {
-               s = talloc_get_type(c->private, struct userinfo_state);
-               talloc_steal(mem_ctx, &s->io.out.info);
+       if (NT_STATUS_IS_OK(status) && io) {
+               s = talloc_get_type(c->private_data, struct userinfo_state);
+               talloc_steal(mem_ctx, s->info);
+               io->out.info = *s->info;
        }
-
+       
+       /* memory context associated to composite context is no longer needed */
        talloc_free(c);
        return status;
 }
 
 
-NTSTATUS rpc_composite_userinfo(struct dcerpc_pipe *pipe,
-                               TALLOC_CTX *mem_ctx,
-                               struct rpc_composite_userinfo *io)
+/**
+ * Synchronous version of userinfo 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_userinfo(struct dcerpc_pipe *p,
+                            TALLOC_CTX *mem_ctx,
+                            struct libnet_rpc_userinfo *io)
 {
-       struct composite_context *c = rpc_composite_userinfo_send(pipe, io);
-       return rpc_composite_userinfo_recv(c, mem_ctx);
+       struct composite_context *c = libnet_rpc_userinfo_send(p, io, NULL);
+       return libnet_rpc_userinfo_recv(c, mem_ctx, io);
 }