1 /* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Rafal Szczesniak 2007 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 3 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, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /* 21 a composite function for getting group information via samr pipe 22 */ 23 24 25 #include "includes.h" 26 #include "libcli/composite/composite.h" 27 #include "librpc/gen_ndr/security.h" 28 #include "libcli/security/security.h" 29 #include "libnet/libnet.h" 30 #include "librpc/gen_ndr/ndr_samr_c.h" 31 32 33 struct groupinfo_state { 34 struct dcerpc_binding_handle *binding_handle; 35 struct policy_handle domain_handle; 36 struct policy_handle group_handle; 37 uint16_t level; 38 struct samr_LookupNames lookup; 39 struct samr_OpenGroup opengroup; 40 struct samr_QueryGroupInfo querygroupinfo; 41 struct samr_Close samrclose; 42 union samr_GroupInfo *info; 43 44 /* information about the progress */ 45 void (*monitor_fn)(struct monitor_msg *); 46 }; 47 48 49 static void continue_groupinfo_lookup(struct tevent_req *subreq); 50 static void continue_groupinfo_opengroup(struct tevent_req *subreq); 51 static void continue_groupinfo_getgroup(struct tevent_req *subreq); 52 static void continue_groupinfo_closegroup(struct tevent_req *subreq); 53 54 55 /** 56 * Stage 1 (optional): Look for a group name in SAM server. 57 */ 58 static void continue_groupinfo_lookup(struct tevent_req *subreq) 59 { 60 struct composite_context *c; 61 struct groupinfo_state *s; 62 struct monitor_msg msg; 63 struct msg_rpc_lookup_name *msg_lookup; 64 65 c = tevent_req_callback_data(subreq, struct composite_context); 66 s = talloc_get_type(c->private_data, struct groupinfo_state); 67 68 /* receive samr_Lookup reply */ 69 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s); 70 TALLOC_FREE(subreq); 71 if (!composite_is_ok(c)) return; 72 73 /* there could be a problem with name resolving itself */ 74 if (!NT_STATUS_IS_OK(s->lookup.out.result)) { 75 composite_error(c, s->lookup.out.result); 76 return; 77 } 78 79 /* issue a monitor message */ 80 if (s->monitor_fn) { 81 msg.type = mon_SamrLookupName; 82 msg_lookup = talloc(s, struct msg_rpc_lookup_name); 83 msg_lookup->rid = s->lookup.out.rids->ids; 84 msg_lookup->count = s->lookup.out.rids->count; 85 msg.data = (void*)msg_lookup; 86 msg.data_size = sizeof(*msg_lookup); 87 88 s->monitor_fn(&msg); 89 } 90 91 /* have we actually got name resolved 92 - we're looking for only one at the moment */ 93 if (s->lookup.out.rids->count != s->lookup.in.num_names) { 94 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); 95 return; 96 } 97 if (s->lookup.out.types->count != s->lookup.in.num_names) { 98 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); 99 return; 100 } 101 102 /* TODO: find proper status code for more than one rid found */ 103 104 /* prepare parameters for LookupNames */ 105 s->opengroup.in.domain_handle = &s->domain_handle; 106 s->opengroup.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; 107 s->opengroup.in.rid = s->lookup.out.rids->ids[0]; 108 s->opengroup.out.group_handle = &s->group_handle; 109 110 /* send request */ 111 subreq = dcerpc_samr_OpenGroup_r_send(s, c->event_ctx, 112 s->binding_handle, 113 &s->opengroup); 114 if (composite_nomem(subreq, c)) return; 115 116 tevent_req_set_callback(subreq, continue_groupinfo_opengroup, c); 117 } 118 119 120 /** 121 * Stage 2: Open group policy handle. 122 */ 123 static void continue_groupinfo_opengroup(struct tevent_req *subreq) 124 { 125 struct composite_context *c; 126 struct groupinfo_state *s; 127 struct monitor_msg msg; 128 struct msg_rpc_open_group *msg_open; 129 130 c = tevent_req_callback_data(subreq, struct composite_context); 131 s = talloc_get_type(c->private_data, struct groupinfo_state); 132 133 /* receive samr_OpenGroup reply */ 134 c->status = dcerpc_samr_OpenGroup_r_recv(subreq, s); 135 TALLOC_FREE(subreq); 136 if (!composite_is_ok(c)) return; 137 138 if (!NT_STATUS_IS_OK(s->opengroup.out.result)) { 139 composite_error(c, s->opengroup.out.result); 140 return; 141 } 142 143 /* issue a monitor message */ 144 if (s->monitor_fn) { 145 msg.type = mon_SamrOpenGroup; 146 msg_open = talloc(s, struct msg_rpc_open_group); 147 msg_open->rid = s->opengroup.in.rid; 148 msg_open->access_mask = s->opengroup.in.access_mask; 149 msg.data = (void*)msg_open; 150 msg.data_size = sizeof(*msg_open); 151 152 s->monitor_fn(&msg); 153 } 154 155 /* prepare parameters for QueryGroupInfo call */ 156 s->querygroupinfo.in.group_handle = &s->group_handle; 157 s->querygroupinfo.in.level = s->level; 158 s->querygroupinfo.out.info = talloc(s, union samr_GroupInfo *); 159 if (composite_nomem(s->querygroupinfo.out.info, c)) return; 160 161 /* queue rpc call, set event handling and new state */ 162 subreq = dcerpc_samr_QueryGroupInfo_r_send(s, 163 c->event_ctx, 164 s->binding_handle, 165 &s->querygroupinfo); 166 if (composite_nomem(subreq, c)) return; 167 168 tevent_req_set_callback(subreq, continue_groupinfo_getgroup, c); 169 } 170 171 172 /** 173 * Stage 3: Get requested group information. 174 */ 175 static void continue_groupinfo_getgroup(struct tevent_req *subreq) 176 { 177 struct composite_context *c; 178 struct groupinfo_state *s; 179 struct monitor_msg msg; 180 struct msg_rpc_query_group *msg_query; 181 182 c = tevent_req_callback_data(subreq, struct composite_context); 183 s = talloc_get_type(c->private_data, struct groupinfo_state); 184 185 /* receive samr_QueryGroupInfo reply */ 186 c->status = dcerpc_samr_QueryGroupInfo_r_recv(subreq, s); 187 TALLOC_FREE(subreq); 188 if (!composite_is_ok(c)) return; 189 190 /* check if querygroup itself went ok */ 191 if (!NT_STATUS_IS_OK(s->querygroupinfo.out.result)) { 192 composite_error(c, s->querygroupinfo.out.result); 193 return; 194 } 195 196 s->info = talloc_steal(s, *s->querygroupinfo.out.info); 197 198 /* issue a monitor message */ 199 if (s->monitor_fn) { 200 msg.type = mon_SamrQueryGroup; 201 msg_query = talloc(s, struct msg_rpc_query_group); 202 msg_query->level = s->querygroupinfo.in.level; 203 msg.data = (void*)msg_query; 204 msg.data_size = sizeof(*msg_query); 205 206 s->monitor_fn(&msg); 207 } 208 209 /* prepare arguments for Close call */ 210 s->samrclose.in.handle = &s->group_handle; 211 s->samrclose.out.handle = &s->group_handle; 212 213 /* queue rpc call, set event handling and new state */ 214 subreq = dcerpc_samr_Close_r_send(s, c->event_ctx, 215 s->binding_handle, 216 &s->samrclose); 217 if (composite_nomem(subreq, c)) return; 218 219 tevent_req_set_callback(subreq, continue_groupinfo_closegroup, c); 220 } 221 222 223 /** 224 * Stage 4: Close policy handle associated with opened group. 225 */ 226 static void continue_groupinfo_closegroup(struct tevent_req *subreq) 227 { 228 struct composite_context *c; 229 struct groupinfo_state *s; 230 struct monitor_msg msg; 231 struct msg_rpc_close_group *msg_close; 232 233 c = tevent_req_callback_data(subreq, struct composite_context); 234 s = talloc_get_type(c->private_data, struct groupinfo_state); 235 236 /* receive samr_Close reply */ 237 c->status = dcerpc_samr_Close_r_recv(subreq, s); 238 TALLOC_FREE(subreq); 239 if (!composite_is_ok(c)) return; 240 241 if (!NT_STATUS_IS_OK(s->samrclose.out.result)) { 242 composite_error(c, s->samrclose.out.result); 243 return; 244 } 245 246 /* issue a monitor message */ 247 if (s->monitor_fn) { 248 msg.type = mon_SamrClose; 249 msg_close = talloc(s, struct msg_rpc_close_group); 250 msg_close->rid = s->opengroup.in.rid; 251 msg.data = (void*)msg_close; 252 msg.data_size = sizeof(*msg_close); 253 254 s->monitor_fn(&msg); 255 } 256 257 composite_done(c); 258 } 259 260 261 /** 262 * Sends asynchronous groupinfo request 263 * 264 * @param p dce/rpc call pipe 265 * @param io arguments and results of the call 266 */ 267 struct composite_context *libnet_rpc_groupinfo_send(TALLOC_CTX *mem_ctx, 268 struct tevent_context *ev, 269 struct dcerpc_binding_handle *b, 270 struct libnet_rpc_groupinfo *io, 271 void (*monitor)(struct monitor_msg*)) 272 { 273 struct composite_context *c; 274 struct groupinfo_state *s; 275 struct dom_sid *sid; 276 struct tevent_req *subreq; 277 278 if (!b || !io) return NULL; 279 280 c = composite_create(mem_ctx, ev); 281 if (c == NULL) return c; 282 283 s = talloc_zero(c, struct groupinfo_state); 284 if (composite_nomem(s, c)) return c; 285 286 c->private_data = s; 287 288 s->level = io->in.level; 289 s->binding_handle= b; 290 s->domain_handle = io->in.domain_handle; 291 s->monitor_fn = monitor; 292 293 if (io->in.sid) { 294 sid = dom_sid_parse_talloc(s, io->in.sid); 295 if (composite_nomem(sid, c)) return c; 296 297 s->opengroup.in.domain_handle = &s->domain_handle; 298 s->opengroup.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; 299 s->opengroup.in.rid = sid->sub_auths[sid->num_auths - 1]; 300 s->opengroup.out.group_handle = &s->group_handle; 301 302 /* send request */ 303 subreq = dcerpc_samr_OpenGroup_r_send(s, c->event_ctx, 304 s->binding_handle, 305 &s->opengroup); 306 if (composite_nomem(subreq, c)) return c; 307 308 tevent_req_set_callback(subreq, continue_groupinfo_opengroup, c); 309 310 } else { 311 /* preparing parameters to send rpc request */ 312 s->lookup.in.domain_handle = &s->domain_handle; 313 s->lookup.in.num_names = 1; 314 s->lookup.in.names = talloc_array(s, struct lsa_String, 1); 315 if (composite_nomem(s->lookup.in.names, c)) return c; 316 317 s->lookup.in.names[0].string = talloc_strdup(s, io->in.groupname); 318 if (composite_nomem(s->lookup.in.names[0].string, c)) return c; 319 s->lookup.out.rids = talloc_zero(s, struct samr_Ids); 320 s->lookup.out.types = talloc_zero(s, struct samr_Ids); 321 if (composite_nomem(s->lookup.out.rids, c)) return c; 322 if (composite_nomem(s->lookup.out.types, c)) return c; 323 324 /* send request */ 325 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx, 326 s->binding_handle, 327 &s->lookup); 328 if (composite_nomem(subreq, c)) return c; 329 330 tevent_req_set_callback(subreq, continue_groupinfo_lookup, c); 331 } 332 333 return c; 334 } 335 336 337 /** 338 * Waits for and receives result of asynchronous groupinfo call 339 * 340 * @param c composite context returned by asynchronous groupinfo call 341 * @param mem_ctx memory context of the call 342 * @param io pointer to results (and arguments) of the call 343 * @return nt status code of execution 344 */ 345 346 NTSTATUS libnet_rpc_groupinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 347 struct libnet_rpc_groupinfo *io) 348 { 349 NTSTATUS status; 350 struct groupinfo_state *s; 351 352 /* wait for results of sending request */ 353 status = composite_wait(c); 354 355 if (NT_STATUS_IS_OK(status) && io) { 356 s = talloc_get_type(c->private_data, struct groupinfo_state); 357 talloc_steal(mem_ctx, s->info); 358 io->out.info = *s->info; 359 } 360 361 /* memory context associated to composite context is no longer needed */ 362 talloc_free(c); 363 return status; 364 } 365 366 367 /** 368 * Synchronous version of groupinfo call 369 * 370 * @param pipe dce/rpc call pipe 371 * @param mem_ctx memory context for the call 372 * @param io arguments and results of the call 373 * @return nt status code of execution 374 */ 375 376 NTSTATUS libnet_rpc_groupinfo(struct tevent_context *ev, 377 struct dcerpc_binding_handle *b, 378 TALLOC_CTX *mem_ctx, 379 struct libnet_rpc_groupinfo *io) 380 { 381 struct composite_context *c = libnet_rpc_groupinfo_send(mem_ctx, ev, b, 382 io, NULL); 383 return libnet_rpc_groupinfo_recv(c, mem_ctx, io); 384 } 385