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 manipulating (add/edit/del) groups via samr pipe 22*/ 23 24#include "includes.h" 25#include "libcli/composite/composite.h" 26#include "libnet/libnet.h" 27#include "librpc/gen_ndr/ndr_samr_c.h" 28 29 30struct groupadd_state { 31 struct dcerpc_pipe *pipe; 32 struct policy_handle domain_handle; 33 struct samr_CreateDomainGroup creategroup; 34 struct policy_handle group_handle; 35 uint32_t group_rid; 36 37 void (*monitor_fn)(struct monitor_msg*); 38}; 39 40 41static void continue_groupadd_created(struct rpc_request *req); 42 43 44struct composite_context* libnet_rpc_groupadd_send(struct dcerpc_pipe *p, 45 struct libnet_rpc_groupadd *io, 46 void (*monitor)(struct monitor_msg*)) 47{ 48 struct composite_context *c; 49 struct groupadd_state *s; 50 struct rpc_request *create_req; 51 52 if (!p || !io) return NULL; 53 54 c = composite_create(p, dcerpc_event_context(p)); 55 if (c == NULL) return NULL; 56 57 s = talloc_zero(c, struct groupadd_state); 58 if (composite_nomem(s, c)) return c; 59 60 c->private_data = s; 61 62 s->domain_handle = io->in.domain_handle; 63 s->pipe = p; 64 s->monitor_fn = monitor; 65 66 s->creategroup.in.domain_handle = &s->domain_handle; 67 68 s->creategroup.in.name = talloc_zero(c, struct lsa_String); 69 if (composite_nomem(s->creategroup.in.name, c)) return c; 70 71 s->creategroup.in.name->string = talloc_strdup(c, io->in.groupname); 72 if (composite_nomem(s->creategroup.in.name->string, c)) return c; 73 74 s->creategroup.in.access_mask = 0; 75 76 s->creategroup.out.group_handle = &s->group_handle; 77 s->creategroup.out.rid = &s->group_rid; 78 79 create_req = dcerpc_samr_CreateDomainGroup_send(s->pipe, c, &s->creategroup); 80 if (composite_nomem(create_req, c)) return c; 81 82 composite_continue_rpc(c, create_req, continue_groupadd_created, c); 83 return c; 84} 85 86 87NTSTATUS libnet_rpc_groupadd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 88 struct libnet_rpc_groupadd *io) 89{ 90 NTSTATUS status; 91 struct groupadd_state *s; 92 93 status = composite_wait(c); 94 if (NT_STATUS_IS_OK(status)) { 95 s = talloc_get_type(c, struct groupadd_state); 96 } 97 98 return status; 99} 100 101 102static void continue_groupadd_created(struct rpc_request *req) 103{ 104 struct composite_context *c; 105 struct groupadd_state *s; 106 107 c = talloc_get_type(req->async.private_data, struct composite_context); 108 s = talloc_get_type(c->private_data, struct groupadd_state); 109 110 c->status = dcerpc_ndr_request_recv(req); 111 if (!composite_is_ok(c)) return; 112 113 c->status = s->creategroup.out.result; 114 if (!composite_is_ok(c)) return; 115 116 composite_done(c); 117} 118 119 120NTSTATUS libnet_rpc_groupadd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 121 struct libnet_rpc_groupadd *io) 122{ 123 struct composite_context *c; 124 125 c = libnet_rpc_groupadd_send(p, io, NULL); 126 return libnet_rpc_groupadd_recv(c, mem_ctx, io); 127} 128 129 130struct groupdel_state { 131 struct dcerpc_pipe *pipe; 132 struct policy_handle domain_handle; 133 struct policy_handle group_handle; 134 struct samr_LookupNames lookupname; 135 struct samr_OpenGroup opengroup; 136 struct samr_DeleteDomainGroup deletegroup; 137 138 /* information about the progress */ 139 void (*monitor_fn)(struct monitor_msg *); 140}; 141 142 143static void continue_groupdel_name_found(struct rpc_request *req); 144static void continue_groupdel_group_opened(struct rpc_request *req); 145static void continue_groupdel_deleted(struct rpc_request *req); 146 147 148struct composite_context* libnet_rpc_groupdel_send(struct dcerpc_pipe *p, 149 struct libnet_rpc_groupdel *io, 150 void (*monitor)(struct monitor_msg*)) 151{ 152 struct composite_context *c; 153 struct groupdel_state *s; 154 struct rpc_request *lookup_req; 155 156 /* composite context allocation and setup */ 157 c = composite_create(p, dcerpc_event_context(p)); 158 if (c == NULL) return NULL; 159 160 s = talloc_zero(c, struct groupdel_state); 161 if (composite_nomem(s, c)) return c; 162 163 c->private_data = s; 164 165 /* store function parameters in the state structure */ 166 s->pipe = p; 167 s->domain_handle = io->in.domain_handle; 168 s->monitor_fn = monitor; 169 170 /* prepare parameters to send rpc request */ 171 s->lookupname.in.domain_handle = &io->in.domain_handle; 172 s->lookupname.in.num_names = 1; 173 s->lookupname.in.names = talloc_zero(s, struct lsa_String); 174 s->lookupname.in.names->string = io->in.groupname; 175 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids); 176 s->lookupname.out.types = talloc_zero(s, struct samr_Ids); 177 if (composite_nomem(s->lookupname.out.rids, c)) return c; 178 if (composite_nomem(s->lookupname.out.types, c)) return c; 179 180 /* send the request */ 181 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname); 182 if (composite_nomem(lookup_req, c)) return c; 183 184 composite_continue_rpc(c, lookup_req, continue_groupdel_name_found, c); 185 return c; 186} 187 188 189static void continue_groupdel_name_found(struct rpc_request *req) 190{ 191 struct composite_context *c; 192 struct groupdel_state *s; 193 struct rpc_request *opengroup_req; 194 195 c = talloc_get_type(req->async.private_data, struct composite_context); 196 s = talloc_get_type(c->private_data, struct groupdel_state); 197 198 /* receive samr_LookupNames result */ 199 c->status = dcerpc_ndr_request_recv(req); 200 if (!composite_is_ok(c)) return; 201 202 c->status = s->lookupname.out.result; 203 if (!NT_STATUS_IS_OK(c->status)) { 204 composite_error(c, c->status); 205 return; 206 } 207 208 /* what to do when there's no group account to delete 209 and what if there's more than one rid resolved */ 210 if (!s->lookupname.out.rids->count) { 211 c->status = NT_STATUS_NO_SUCH_GROUP; 212 composite_error(c, c->status); 213 return; 214 215 } else if (!s->lookupname.out.rids->count > 1) { 216 c->status = NT_STATUS_INVALID_ACCOUNT_NAME; 217 composite_error(c, c->status); 218 return; 219 } 220 221 /* prepare the arguments for rpc call */ 222 s->opengroup.in.domain_handle = &s->domain_handle; 223 s->opengroup.in.rid = s->lookupname.out.rids->ids[0]; 224 s->opengroup.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; 225 s->opengroup.out.group_handle = &s->group_handle; 226 227 /* send rpc request */ 228 opengroup_req = dcerpc_samr_OpenGroup_send(s->pipe, c, &s->opengroup); 229 if (composite_nomem(opengroup_req, c)) return; 230 231 composite_continue_rpc(c, opengroup_req, continue_groupdel_group_opened, c); 232} 233 234 235static void continue_groupdel_group_opened(struct rpc_request *req) 236{ 237 struct composite_context *c; 238 struct groupdel_state *s; 239 struct rpc_request *delgroup_req; 240 241 c = talloc_get_type(req->async.private_data, struct composite_context); 242 s = talloc_get_type(c->private_data, struct groupdel_state); 243 244 /* receive samr_OpenGroup result */ 245 c->status = dcerpc_ndr_request_recv(req); 246 if (!composite_is_ok(c)) return; 247 248 c->status = s->opengroup.out.result; 249 if (!NT_STATUS_IS_OK(c->status)) { 250 composite_error(c, c->status); 251 return; 252 } 253 254 /* prepare the final rpc call arguments */ 255 s->deletegroup.in.group_handle = &s->group_handle; 256 s->deletegroup.out.group_handle = &s->group_handle; 257 258 /* send rpc request */ 259 delgroup_req = dcerpc_samr_DeleteDomainGroup_send(s->pipe, c, &s->deletegroup); 260 if (composite_nomem(delgroup_req, c)) return; 261 262 /* callback handler setup */ 263 composite_continue_rpc(c, delgroup_req, continue_groupdel_deleted, c); 264} 265 266 267static void continue_groupdel_deleted(struct rpc_request *req) 268{ 269 struct composite_context *c; 270 struct groupdel_state *s; 271 272 c = talloc_get_type(req->async.private_data, struct composite_context); 273 s = talloc_get_type(c->private_data, struct groupdel_state); 274 275 /* receive samr_DeleteGroup result */ 276 c->status = dcerpc_ndr_request_recv(req); 277 if (!composite_is_ok(c)) return; 278 279 /* return the actual function call status */ 280 c->status = s->deletegroup.out.result; 281 if (!NT_STATUS_IS_OK(c->status)) { 282 composite_error(c, c->status); 283 return; 284 } 285 286 composite_done(c); 287} 288 289 290NTSTATUS libnet_rpc_groupdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 291 struct libnet_rpc_groupdel *io) 292{ 293 NTSTATUS status; 294 struct groupdel_state *s; 295 296 status = composite_wait(c); 297 if (NT_STATUS_IS_OK(status) && io) { 298 s = talloc_get_type(c->private_data, struct groupdel_state); 299 io->out.group_handle = s->group_handle; 300 } 301 302 talloc_free(c); 303 return status; 304} 305 306 307NTSTATUS libnet_rpc_groupdel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 308 struct libnet_rpc_groupdel *io) 309{ 310 struct composite_context *c; 311 312 c = libnet_rpc_groupdel_send(p, io, NULL); 313 return libnet_rpc_groupdel_recv(c, mem_ctx, io); 314} 315