8f473b862bd98b002bb6d6e0b25eccf4591fdb2a
[samba.git] / source4 / libnet / userinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Rafal Szczesniak 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   a composite function for getting user information via samr pipe
23 */
24
25 #include "includes.h"
26 #include "libcli/composite/composite.h"
27 #include "libcli/security/proto.h"
28 #include "libnet/composite.h"
29 #include "libnet/userinfo.h"
30
31 static void userinfo_handler(struct rpc_request *req);
32
33 enum userinfo_stage { USERINFO_OPENUSER, USERINFO_GETUSER, USERINFO_CLOSEUSER };
34
35 struct userinfo_state {
36         enum userinfo_stage       stage;
37         struct dcerpc_pipe        *pipe;
38         struct rpc_request        *req;
39         struct policy_handle      user_handle;
40         uint16_t                  level;
41         struct samr_OpenUser      openuser;
42         struct samr_QueryUserInfo queryuserinfo;
43         struct samr_Close         samrclose;    
44         union  samr_UserInfo      *info;
45
46         /* information about the progress */
47         void (*monitor_fn)(struct monitor_msg *);
48 };
49
50
51 /**
52  * Stage 1: Open user policy handle in SAM server.
53  */
54 static NTSTATUS userinfo_openuser(struct composite_context *c,
55                                   struct userinfo_state *s)
56 {
57         /* receive samr_OpenUser reply */
58         c->status = dcerpc_ndr_request_recv(s->req);
59         NT_STATUS_NOT_OK_RETURN(c->status);
60
61         /* prepare parameters for QueryUserInfo call */
62         s->queryuserinfo.in.user_handle = &s->user_handle;
63         s->queryuserinfo.in.level       = s->level;
64         
65         /* queue rpc call, set event handling and new state */
66         s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuserinfo);
67         if (s->req == NULL) goto failure;
68         
69         s->req->async.callback = userinfo_handler;
70         s->req->async.private  = c;
71         s->stage = USERINFO_GETUSER;
72         
73         return NT_STATUS_OK;
74
75 failure:
76         return NT_STATUS_UNSUCCESSFUL;
77 }
78
79
80 /**
81  * Stage 2: Get requested user information.
82  */
83 static NTSTATUS userinfo_getuser(struct composite_context *c,
84                                  struct userinfo_state *s)
85 {
86         /* receive samr_QueryUserInfo reply */
87         c->status = dcerpc_ndr_request_recv(s->req);
88         NT_STATUS_NOT_OK_RETURN(c->status);
89
90         s->info = talloc_steal(s, s->queryuserinfo.out.info);
91         
92         /* prepare arguments for Close call */
93         s->samrclose.in.handle  = &s->user_handle;
94         s->samrclose.out.handle = &s->user_handle;
95         
96         /* queue rpc call, set event handling and new state */
97         s->req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
98         
99         s->req->async.callback = userinfo_handler;
100         s->req->async.private  = c;
101         s->stage = USERINFO_CLOSEUSER;
102
103         return NT_STATUS_OK;
104 }
105
106
107 /**
108  * Stage 3: Close policy handle associated with opened user.
109  */
110 static NTSTATUS userinfo_closeuser(struct composite_context *c,
111                                    struct userinfo_state *s)
112 {
113         /* receive samr_Close reply */
114         c->status = dcerpc_ndr_request_recv(s->req);
115         NT_STATUS_NOT_OK_RETURN(c->status);
116
117         c->state = COMPOSITE_STATE_DONE;
118
119         return NT_STATUS_OK;
120 }
121
122
123 /**
124  * Event handler for asynchronous request. Handles transition through
125  * intermediate stages of the call.
126  *
127  * @param req rpc call context
128  */
129 static void userinfo_handler(struct rpc_request *req)
130 {
131         struct composite_context *c = req->async.private;
132         struct userinfo_state *s = talloc_get_type(c->private_data, struct userinfo_state);
133         struct monitor_msg msg;
134         struct msg_rpc_open_user *msg_open;
135         struct msg_rpc_query_user *msg_query;
136         struct msg_rpc_close_user *msg_close;
137         
138         /* Stages of the call */
139         switch (s->stage) {
140         case USERINFO_OPENUSER:
141                 c->status = userinfo_openuser(c, s);
142
143                 msg.type = rpc_open_user;
144                 msg_open = talloc(s, struct msg_rpc_open_user);
145                 msg_open->rid = s->openuser.in.rid;
146                 msg_open->access_mask = s->openuser.in.access_mask;
147                 msg.data = (void*)msg_open;
148                 msg.data_size = sizeof(*msg_open);
149                 break;
150
151         case USERINFO_GETUSER:
152                 c->status = userinfo_getuser(c, s);
153
154                 msg.type = rpc_query_user;
155                 msg_query = talloc(s, struct msg_rpc_query_user);
156                 msg_query->level = s->queryuserinfo.in.level;
157                 msg.data = (void*)msg_query;
158                 msg.data_size = sizeof(*msg_query);
159                 break;
160                 
161         case USERINFO_CLOSEUSER:
162                 c->status = userinfo_closeuser(c, s);
163
164                 msg.type = rpc_close_user;
165                 msg_close = talloc(s, struct msg_rpc_close_user);
166                 msg_close->rid = s->openuser.in.rid;
167                 msg.data = (void*)msg_close;
168                 msg.data_size = sizeof(*msg_close);
169                 break;
170         }
171
172         if (!NT_STATUS_IS_OK(c->status)) {
173                 c->state = COMPOSITE_STATE_ERROR;
174         }
175         
176         if (s->monitor_fn) {
177                 s->monitor_fn(&msg);
178         }
179
180         if (c->state >= COMPOSITE_STATE_DONE &&
181             c->async.fn) {
182                 c->async.fn(c);
183         }
184 }
185
186
187 /**
188  * Sends asynchronous userinfo request
189  *
190  * @param p dce/rpc call pipe 
191  * @param io arguments and results of the call
192  */
193 struct composite_context *libnet_rpc_userinfo_send(struct dcerpc_pipe *p,
194                                                    struct libnet_rpc_userinfo *io,
195                                                    void (*monitor)(struct monitor_msg*))
196 {
197         struct composite_context *c;
198         struct userinfo_state *s;
199         struct dom_sid *sid;
200
201         if (!p || !io) return NULL;
202         
203         c = talloc_zero(p, struct composite_context);
204         if (c == NULL) goto failure;
205         
206         s = talloc_zero(c, struct userinfo_state);
207         if (s == NULL) goto failure;
208
209         s->level = io->in.level;
210         s->pipe  = p;
211         s->monitor_fn  = monitor;
212         
213         sid = dom_sid_parse_talloc(s, io->in.sid);
214         if (sid == NULL) goto failure;  
215         c->state        = COMPOSITE_STATE_IN_PROGRESS;
216         c->private_data = s;
217         c->event_ctx    = dcerpc_event_context(p);
218
219         /* preparing parameters to send rpc request */
220         s->openuser.in.domain_handle  = &io->in.domain_handle;
221         s->openuser.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
222         s->openuser.in.rid            = sid->sub_auths[sid->num_auths - 1];
223         s->openuser.out.user_handle   = &s->user_handle;
224
225         /* send request */
226         s->req = dcerpc_samr_OpenUser_send(p, c, &s->openuser);
227
228         /* callback handler */
229         s->req->async.callback = userinfo_handler;
230         s->req->async.private  = c;
231         s->stage = USERINFO_OPENUSER;
232
233         return c;
234         
235 failure:
236         talloc_free(c);
237         return NULL;
238 }
239
240
241 /**
242  * Waits for and receives result of asynchronous userinfo call
243  * 
244  * @param c composite context returned by asynchronous userinfo call
245  * @param mem_ctx memory context of the call
246  * @param io pointer to results (and arguments) of the call
247  * @return nt status code of execution
248  */
249
250 NTSTATUS libnet_rpc_userinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
251                                   struct libnet_rpc_userinfo *io)
252 {
253         NTSTATUS status;
254         struct userinfo_state *s;
255         
256         /* wait for results of sending request */
257         status = composite_wait(c);
258         
259         if (NT_STATUS_IS_OK(status) && io) {
260                 s = talloc_get_type(c->private_data, struct userinfo_state);
261                 talloc_steal(mem_ctx, s->info);
262                 io->out.info = *s->info;
263         }
264         
265         /* memory context associated to composite context is no longer needed */
266         talloc_free(c);
267         return status;
268 }
269
270
271 /**
272  * Synchronous version of userinfo call
273  *
274  * @param pipe dce/rpc call pipe
275  * @param mem_ctx memory context for the call
276  * @param io arguments and results of the call
277  * @return nt status code of execution
278  */
279
280 NTSTATUS libnet_rpc_userinfo(struct dcerpc_pipe *p,
281                              TALLOC_CTX *mem_ctx,
282                              struct libnet_rpc_userinfo *io)
283 {
284         struct composite_context *c = libnet_rpc_userinfo_send(p, io, NULL);
285         return libnet_rpc_userinfo_recv(c, mem_ctx, io);
286 }