root/source4/libnet/libnet_group.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. libnet_CreateGroup_send
  2. continue_domain_opened
  3. continue_rpc_group_added
  4. libnet_CreateGroup_recv
  5. libnet_CreateGroup
  6. libnet_GroupInfo_send
  7. continue_domain_open_info
  8. continue_name_found
  9. continue_group_info
  10. libnet_GroupInfo_recv
  11. libnet_GroupInfo
  12. libnet_GroupList_send
  13. continue_lsa_domain_opened
  14. continue_domain_queried
  15. continue_samr_domain_opened
  16. continue_groups_enumerated
  17. libnet_GroupList_recv
  18. libnet_GroupList

   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 #include "includes.h"
  22 #include "libnet/libnet.h"
  23 #include "libcli/composite/composite.h"
  24 #include "librpc/gen_ndr/lsa.h"
  25 #include "librpc/gen_ndr/ndr_lsa_c.h"
  26 #include "librpc/gen_ndr/samr.h"
  27 #include "librpc/gen_ndr/ndr_samr_c.h"
  28 #include "libcli/security/security.h"
  29 
  30 
  31 struct create_group_state {
  32         struct libnet_context *ctx;
  33         struct libnet_CreateGroup r;
  34         struct libnet_DomainOpen domain_open;
  35         struct libnet_rpc_groupadd group_add;
  36 
  37         /* information about the progress */
  38         void (*monitor_fn)(struct monitor_msg *);
  39 };
  40 
  41 
  42 static void continue_domain_opened(struct composite_context *ctx);
  43 static void continue_rpc_group_added(struct composite_context *ctx);
  44 
  45 
  46 struct composite_context* libnet_CreateGroup_send(struct libnet_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  47                                                   TALLOC_CTX *mem_ctx,
  48                                                   struct libnet_CreateGroup *r,
  49                                                   void (*monitor)(struct monitor_msg*))
  50 {
  51         struct composite_context *c;
  52         struct create_group_state *s;
  53         struct composite_context *create_req;
  54         bool prereq_met = false;
  55 
  56         /* composite context allocation and setup */
  57         c = composite_create(mem_ctx, ctx->event_ctx);
  58         if (c == NULL) return NULL;
  59 
  60         s = talloc_zero(c, struct create_group_state);
  61         if (composite_nomem(s, c)) return c;
  62 
  63         c->private_data = s;
  64 
  65         s->ctx = ctx;
  66         s->r   = *r;
  67         ZERO_STRUCT(s->r.out);
  68 
  69         /* prerequisite: make sure we have a valid samr domain handle */
  70         prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
  71                                         continue_domain_opened, monitor);
  72         if (!prereq_met) return c;
  73 
  74         /* prepare arguments of rpc group add call */
  75         s->group_add.in.groupname     = r->in.group_name;
  76         s->group_add.in.domain_handle = ctx->samr.handle;
  77 
  78         /* send the request */
  79         create_req = libnet_rpc_groupadd_send(ctx->samr.pipe, &s->group_add, monitor);
  80         if (composite_nomem(create_req, c)) return c;
  81 
  82         composite_continue(c, create_req, continue_rpc_group_added, c);
  83         return c;
  84 }
  85 
  86 
  87 static void continue_domain_opened(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  88 {
  89         struct composite_context *c;
  90         struct create_group_state *s;
  91         struct composite_context *create_req;
  92         
  93         c = talloc_get_type(ctx->async.private_data, struct composite_context);
  94         s = talloc_get_type(c->private_data, struct create_group_state);
  95 
  96         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
  97         if (!composite_is_ok(c)) return;
  98 
  99         /* prepare arguments of groupadd call */
 100         s->group_add.in.groupname     = s->r.in.group_name;
 101         s->group_add.in.domain_handle = s->ctx->samr.handle;
 102 
 103         /* send the request */
 104         create_req = libnet_rpc_groupadd_send(s->ctx->samr.pipe, &s->group_add,
 105                                               s->monitor_fn);
 106         if (composite_nomem(create_req, c)) return;
 107 
 108         composite_continue(c, create_req, continue_rpc_group_added, c);
 109 }
 110 
 111 
 112 static void continue_rpc_group_added(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 113 {
 114         struct composite_context *c;
 115         struct create_group_state *s;
 116 
 117         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 118         s = talloc_get_type(c->private_data, struct create_group_state);
 119 
 120         /* receive result of group add call */
 121         c->status = libnet_rpc_groupadd_recv(ctx, c, &s->group_add);
 122         if (!composite_is_ok(c)) return;
 123 
 124         /* we're done */
 125         composite_done(c);
 126 }
 127 
 128 
 129 /**
 130  * Receive result of CreateGroup call
 131  *
 132  * @param c composite context returned by send request routine
 133  * @param mem_ctx memory context of this call
 134  * @param r pointer to a structure containing arguments and result of this call
 135  * @return nt status
 136  */
 137 NTSTATUS libnet_CreateGroup_recv(struct composite_context *c,
     /* [<][>][^][v][top][bottom][index][help] */
 138                                  TALLOC_CTX *mem_ctx,
 139                                  struct libnet_CreateGroup *r)
 140 {
 141         NTSTATUS status;
 142         struct create_group_state *s;
 143 
 144         status = composite_wait(c);
 145         if (!NT_STATUS_IS_OK(status)) {
 146                 s = talloc_get_type(c->private_data, struct create_group_state);
 147                 r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
 148         }
 149 
 150         return status;
 151 }
 152 
 153 
 154 /**
 155  * Create domain group
 156  *
 157  * @param ctx initialised libnet context
 158  * @param mem_ctx memory context of this call
 159  * @param io pointer to structure containing arguments and result of this call
 160  * @return nt status
 161  */
 162 NTSTATUS libnet_CreateGroup(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 163                             struct libnet_CreateGroup *io)
 164 {
 165         struct composite_context *c;
 166 
 167         c = libnet_CreateGroup_send(ctx, mem_ctx, io, NULL);
 168         return libnet_CreateGroup_recv(c, mem_ctx, io);
 169 }
 170 
 171 
 172 struct group_info_state {
 173         struct libnet_context *ctx;
 174         const char *domain_name;
 175         enum libnet_GroupInfo_level level;
 176         const char *group_name;
 177         const char *sid_string;
 178         struct libnet_LookupName lookup;
 179         struct libnet_DomainOpen domopen;
 180         struct libnet_rpc_groupinfo info;
 181         
 182         /* information about the progress */
 183         void (*monitor_fn)(struct monitor_msg *);
 184 };
 185 
 186 
 187 static void continue_domain_open_info(struct composite_context *ctx);
 188 static void continue_name_found(struct composite_context *ctx);
 189 static void continue_group_info(struct composite_context *ctx);
 190 
 191 /**
 192  * Sends request to get group information
 193  *
 194  * @param ctx initialised libnet context
 195  * @param mem_ctx memory context of this call
 196  * @param io pointer to structure containing arguments the call
 197  * @param monitor function pointer for receiving monitor messages
 198  * @return composite context of this request
 199  */
 200 struct composite_context* libnet_GroupInfo_send(struct libnet_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 201                                                 TALLOC_CTX *mem_ctx,
 202                                                 struct libnet_GroupInfo *io,
 203                                                 void (*monitor)(struct monitor_msg*))
 204 {
 205         struct composite_context *c;
 206         struct group_info_state *s;
 207         bool prereq_met = false;
 208         struct composite_context *lookup_req, *info_req;
 209 
 210         /* composite context allocation and setup */
 211         c = composite_create(mem_ctx, ctx->event_ctx);
 212         if (c == NULL) return NULL;
 213 
 214         s = talloc_zero(c, struct group_info_state);
 215         if (composite_nomem(s, c)) return c;
 216 
 217         c->private_data = s;
 218 
 219         /* store arguments in the state structure */
 220         s->monitor_fn = monitor;
 221         s->ctx = ctx;
 222         s->domain_name = talloc_strdup(c, io->in.domain_name);
 223         s->level = io->in.level;
 224         switch(s->level) {
 225         case GROUP_INFO_BY_NAME:
 226                 s->group_name = talloc_strdup(c, io->in.data.group_name);
 227                 s->sid_string = NULL;
 228                 break;
 229         case GROUP_INFO_BY_SID:
 230                 s->group_name = NULL;
 231                 s->sid_string = dom_sid_string(c, io->in.data.group_sid);
 232                 break;
 233         }
 234 
 235         /* prerequisite: make sure the domain is opened */
 236         prereq_met = samr_domain_opened(ctx, s->domain_name, &c, &s->domopen,
 237                                         continue_domain_open_info, monitor);
 238         if (!prereq_met) return c;
 239 
 240         switch(s->level) {
 241         case GROUP_INFO_BY_NAME:
 242                 /* prepare arguments for LookupName call */
 243                 s->lookup.in.name        = s->group_name;
 244                 s->lookup.in.domain_name = s->domain_name;
 245 
 246                 /* send the request */
 247                 lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
 248                 if (composite_nomem(lookup_req, c)) return c;
 249 
 250                 /* set the next stage */
 251                 composite_continue(c, lookup_req, continue_name_found, c);
 252                 break;
 253         case GROUP_INFO_BY_SID:
 254                 /* prepare arguments for groupinfo call */
 255                 s->info.in.domain_handle = s->ctx->samr.handle;
 256                 s->info.in.sid           = s->sid_string;
 257                 /* we're looking for all information available */
 258                 s->info.in.level         = GROUPINFOALL;
 259 
 260                 /* send the request */
 261                 info_req = libnet_rpc_groupinfo_send(s->ctx->samr.pipe, &s->info, s->monitor_fn);
 262                 if (composite_nomem(info_req, c)) return c;
 263 
 264                 /* set the next stage */
 265                 composite_continue(c, info_req, continue_group_info, c);
 266                 break;
 267         }
 268 
 269         return c;
 270 }
 271 
 272 
 273 /*
 274  * Stage 0.5 (optional): receive opened domain and send lookup name request
 275  */
 276 static void continue_domain_open_info(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 277 {
 278         struct composite_context *c;
 279         struct group_info_state *s;
 280         struct composite_context *lookup_req, *info_req;
 281         
 282         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 283         s = talloc_get_type(c->private_data, struct group_info_state);
 284         
 285         /* receive domain handle */
 286         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
 287         if (!composite_is_ok(c)) return;
 288 
 289         switch(s->level) {
 290         case GROUP_INFO_BY_NAME:
 291                 /* prepare arguments for LookupName call */
 292                 s->lookup.in.name        = s->group_name;
 293                 s->lookup.in.domain_name = s->domain_name;
 294 
 295                 /* send the request */
 296                 lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
 297                 if (composite_nomem(lookup_req, c)) return;
 298 
 299                 /* set the next stage */
 300                 composite_continue(c, lookup_req, continue_name_found, c);
 301                 break;
 302         case GROUP_INFO_BY_SID:
 303                 /* prepare arguments for groupinfo call */
 304                 s->info.in.domain_handle = s->ctx->samr.handle;
 305                 s->info.in.sid           = s->sid_string;
 306                 /* we're looking for all information available */
 307                 s->info.in.level         = GROUPINFOALL;
 308 
 309                 /* send the request */
 310                 info_req = libnet_rpc_groupinfo_send(s->ctx->samr.pipe, &s->info, s->monitor_fn);
 311                 if (composite_nomem(info_req, c)) return;
 312 
 313                 /* set the next stage */
 314                 composite_continue(c, info_req, continue_group_info, c);
 315                 break;
 316 
 317         }
 318 }
 319 
 320 
 321 /*
 322  * Stage 1: Receive SID found and send request for group info
 323  */
 324 static void continue_name_found(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 325 {
 326         struct composite_context *c;
 327         struct group_info_state *s;
 328         struct composite_context *info_req;
 329 
 330         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 331         s = talloc_get_type(c->private_data, struct group_info_state);
 332 
 333         /* receive SID assiociated with name found */
 334         c->status = libnet_LookupName_recv(ctx, c, &s->lookup);
 335         if (!composite_is_ok(c)) return;
 336 
 337         /* Is is a group SID actually ? */
 338         if (s->lookup.out.sid_type != SID_NAME_DOM_GRP &&
 339             s->lookup.out.sid_type != SID_NAME_ALIAS) {
 340                 composite_error(c, NT_STATUS_NO_SUCH_GROUP);
 341         }
 342 
 343         /* prepare arguments for groupinfo call */
 344         s->info.in.domain_handle = s->ctx->samr.handle;
 345         s->info.in.groupname     = s->group_name;
 346         s->info.in.sid           = s->lookup.out.sidstr;
 347         /* we're looking for all information available */
 348         s->info.in.level         = GROUPINFOALL;
 349 
 350         /* send the request */
 351         info_req = libnet_rpc_groupinfo_send(s->ctx->samr.pipe, &s->info, s->monitor_fn);
 352         if (composite_nomem(info_req, c)) return;
 353 
 354         /* set the next stage */
 355         composite_continue(c, info_req, continue_group_info, c);
 356 }
 357 
 358 
 359 /*
 360  * Stage 2: Receive group information
 361  */
 362 static void continue_group_info(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 363 {
 364         struct composite_context *c;
 365         struct group_info_state *s;
 366 
 367         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 368         s = talloc_get_type(c->private_data, struct group_info_state);
 369 
 370         /* receive group information */
 371         c->status = libnet_rpc_groupinfo_recv(ctx, c, &s->info);
 372         if (!composite_is_ok(c)) return;
 373 
 374         /* we're done */
 375         composite_done(c);
 376 }
 377 
 378 
 379 /*
 380  * Receive group information
 381  *
 382  * @param c composite context returned by libnet_GroupInfo_send
 383  * @param mem_ctx memory context of this call
 384  * @param io pointer to structure receiving results of the call
 385  * @result nt status
 386  */
 387 NTSTATUS libnet_GroupInfo_recv(struct composite_context* c, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 388                                struct libnet_GroupInfo *io)
 389 {
 390         NTSTATUS status;
 391         struct group_info_state *s;
 392         
 393         status = composite_wait(c);
 394         if (NT_STATUS_IS_OK(status)) {
 395                 /* put the results into io structure if everything went fine */
 396                 s = talloc_get_type(c->private_data, struct group_info_state);
 397 
 398                 io->out.group_name = talloc_steal(mem_ctx,
 399                                         s->info.out.info.all.name.string);
 400                 io->out.group_sid = talloc_steal(mem_ctx, s->lookup.out.sid);
 401                 io->out.num_members = s->info.out.info.all.num_members;
 402                 io->out.description = talloc_steal(mem_ctx, s->info.out.info.all.description.string);
 403 
 404                 io->out.error_string = talloc_strdup(mem_ctx, "Success");
 405 
 406         } else {
 407                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
 408         }
 409 
 410         talloc_free(c);
 411 
 412         return status;
 413 }
 414 
 415 
 416 /**
 417  * Obtains specified group information
 418  * 
 419  * @param ctx initialised libnet context
 420  * @param mem_ctx memory context of the call
 421  * @param io pointer to a structure containing arguments and results of the call
 422  */
 423 NTSTATUS libnet_GroupInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 424                           struct libnet_GroupInfo *io)
 425 {
 426         struct composite_context *c = libnet_GroupInfo_send(ctx, mem_ctx,
 427                                                             io, NULL);
 428         return libnet_GroupInfo_recv(c, mem_ctx, io);
 429 }
 430 
 431 
 432 struct grouplist_state {
 433         struct libnet_context *ctx;
 434         const char *domain_name;
 435         struct lsa_DomainInfo dominfo;
 436         int page_size;
 437         uint32_t resume_index;
 438         struct grouplist *groups;
 439         uint32_t count;
 440 
 441         struct libnet_DomainOpen domain_open;
 442         struct lsa_QueryInfoPolicy query_domain;
 443         struct samr_EnumDomainGroups group_list;
 444 
 445         void (*monitor_fn)(struct monitor_msg*);
 446 };
 447 
 448 
 449 static void continue_lsa_domain_opened(struct composite_context *ctx);
 450 static void continue_domain_queried(struct rpc_request *req);
 451 static void continue_samr_domain_opened(struct composite_context *ctx);
 452 static void continue_domain_queried(struct rpc_request *req);
 453 static void continue_groups_enumerated(struct rpc_request *req);
 454 
 455 
 456 /**
 457  * Sends request to list (enumerate) group accounts
 458  *
 459  * @param ctx initialised libnet context
 460  * @param mem_ctx memory context of this call
 461  * @param io pointer to structure containing arguments and results of this call
 462  * @param monitor function pointer for receiving monitor messages
 463  * @return compostite context of this request
 464  */
 465 struct composite_context *libnet_GroupList_send(struct libnet_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 466                                                 TALLOC_CTX *mem_ctx,
 467                                                 struct libnet_GroupList *io,
 468                                                 void (*monitor)(struct monitor_msg*))
 469 {
 470         struct composite_context *c;
 471         struct grouplist_state *s;
 472         struct rpc_request *query_req;
 473         bool prereq_met = false;
 474 
 475         /* composite context allocation and setup */
 476         c = composite_create(mem_ctx, ctx->event_ctx);
 477         if (c == NULL) return NULL;
 478 
 479         s = talloc_zero(c, struct grouplist_state);
 480         if (composite_nomem(s, c)) return c;
 481         
 482         c->private_data = s;
 483 
 484         /* store the arguments in the state structure */
 485         s->ctx          = ctx;
 486         s->page_size    = io->in.page_size;
 487         s->resume_index = (uint32_t)io->in.resume_index;
 488         s->domain_name  = talloc_strdup(c, io->in.domain_name);
 489         s->monitor_fn   = monitor;
 490 
 491         /* make sure we have lsa domain handle before doing anything */
 492         prereq_met = lsa_domain_opened(ctx, s->domain_name, &c, &s->domain_open,
 493                                        continue_lsa_domain_opened, monitor);
 494         if (!prereq_met) return c;
 495 
 496         /* prepare arguments of QueryDomainInfo call */
 497         s->query_domain.in.handle = &ctx->lsa.handle;
 498         s->query_domain.in.level  = LSA_POLICY_INFO_DOMAIN;
 499         s->query_domain.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
 500         if (composite_nomem(s->query_domain.out.info, c)) return c;
 501 
 502         /* send the request */
 503         query_req = dcerpc_lsa_QueryInfoPolicy_send(ctx->lsa.pipe, c, &s->query_domain);
 504         if (composite_nomem(query_req, c)) return c;
 505         
 506         composite_continue_rpc(c, query_req, continue_domain_queried, c);
 507         return c;
 508 }
 509 
 510 
 511 /*
 512  * Stage 0.5 (optional): receive lsa domain handle and send
 513  * request to query domain info
 514  */
 515 static void continue_lsa_domain_opened(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 516 {
 517         struct composite_context *c;
 518         struct grouplist_state *s;
 519         struct rpc_request *query_req;
 520         
 521         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 522         s = talloc_get_type(c->private_data, struct grouplist_state);
 523 
 524         /* receive lsa domain handle */
 525         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
 526         if (!composite_is_ok(c)) return;
 527 
 528         /* prepare arguments of QueryDomainInfo call */
 529         s->query_domain.in.handle = &s->ctx->lsa.handle;
 530         s->query_domain.in.level  = LSA_POLICY_INFO_DOMAIN;
 531         s->query_domain.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
 532         if (composite_nomem(s->query_domain.out.info, c)) return;
 533 
 534         /* send the request */
 535         query_req = dcerpc_lsa_QueryInfoPolicy_send(s->ctx->lsa.pipe, c, &s->query_domain);
 536         if (composite_nomem(query_req, c)) return;
 537 
 538         composite_continue_rpc(c, query_req, continue_domain_queried, c);
 539 }
 540 
 541 
 542 /*
 543  * Stage 1: receive domain info and request to enum groups
 544  * provided a valid samr handle is opened
 545  */
 546 static void continue_domain_queried(struct rpc_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 547 {
 548         struct composite_context *c;
 549         struct grouplist_state *s;
 550         struct rpc_request *enum_req;
 551         bool prereq_met = false;
 552         
 553         c = talloc_get_type(req->async.private_data, struct composite_context);
 554         s = talloc_get_type(c->private_data, struct grouplist_state);
 555 
 556         /* receive result of rpc request */
 557         c->status = dcerpc_ndr_request_recv(req);
 558         if (!composite_is_ok(c)) return;
 559 
 560         /* get the returned domain info */
 561         s->dominfo = (*s->query_domain.out.info)->domain;
 562 
 563         /* make sure we have samr domain handle before continuing */
 564         prereq_met = samr_domain_opened(s->ctx, s->domain_name, &c, &s->domain_open,
 565                                         continue_samr_domain_opened, s->monitor_fn);
 566         if (!prereq_met) return;
 567 
 568         /* prepare arguments od EnumDomainGroups call */
 569         s->group_list.in.domain_handle  = &s->ctx->samr.handle;
 570         s->group_list.in.max_size       = s->page_size;
 571         s->group_list.in.resume_handle  = &s->resume_index;
 572         s->group_list.out.resume_handle = &s->resume_index;
 573         s->group_list.out.num_entries   = talloc(s, uint32_t);
 574         if (composite_nomem(s->group_list.out.num_entries, c)) return;
 575         s->group_list.out.sam           = talloc(s, struct samr_SamArray *);
 576         if (composite_nomem(s->group_list.out.sam, c)) return;
 577 
 578         /* send the request */
 579         enum_req = dcerpc_samr_EnumDomainGroups_send(s->ctx->samr.pipe, c, &s->group_list);
 580         if (composite_nomem(enum_req, c)) return;
 581 
 582         composite_continue_rpc(c, enum_req, continue_groups_enumerated, c);
 583 }
 584 
 585 
 586 /*
 587  * Stage 1.5 (optional): receive samr domain handle
 588  * and request to enumerate accounts
 589  */
 590 static void continue_samr_domain_opened(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 591 {
 592         struct composite_context *c;
 593         struct grouplist_state *s;
 594         struct rpc_request *enum_req;
 595 
 596         c = talloc_get_type(ctx->async.private_data, struct composite_context);
 597         s = talloc_get_type(c->private_data, struct grouplist_state);
 598 
 599         /* receive samr domain handle */
 600         c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
 601         if (!composite_is_ok(c)) return;
 602 
 603         /* prepare arguments of EnumDomainGroups call */
 604         s->group_list.in.domain_handle  = &s->ctx->samr.handle;
 605         s->group_list.in.max_size       = s->page_size;
 606         s->group_list.in.resume_handle  = &s->resume_index;
 607         s->group_list.out.resume_handle = &s->resume_index;
 608         s->group_list.out.num_entries   = talloc(s, uint32_t);
 609         if (composite_nomem(s->group_list.out.num_entries, c)) return;
 610         s->group_list.out.sam           = talloc(s, struct samr_SamArray *);
 611         if (composite_nomem(s->group_list.out.sam, c)) return;
 612 
 613         /* send the request */
 614         enum_req = dcerpc_samr_EnumDomainGroups_send(s->ctx->samr.pipe, c, &s->group_list);
 615         if (composite_nomem(enum_req, c)) return;
 616 
 617         composite_continue_rpc(c, enum_req, continue_groups_enumerated, c);
 618 }
 619 
 620 
 621 /*
 622  * Stage 2: receive enumerated groups and their rids
 623  */
 624 static void continue_groups_enumerated(struct rpc_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 625 {
 626         struct composite_context *c;
 627         struct grouplist_state *s;
 628         int i;
 629 
 630         c = talloc_get_type(req->async.private_data, struct composite_context);
 631         s = talloc_get_type(c->private_data, struct grouplist_state);
 632 
 633         /* receive result of rpc request */
 634         c->status = dcerpc_ndr_request_recv(req);
 635         if (!composite_is_ok(c)) return;
 636 
 637         /* get the actual status of the rpc call result
 638            (instead of rpc layer) */
 639         c->status = s->group_list.out.result;
 640 
 641         /* we're interested in status "ok" as well as two
 642            enum-specific status codes */
 643         if (NT_STATUS_IS_OK(c->status) ||
 644             NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
 645             NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
 646                 
 647                 /* get enumerated accounts counter and resume handle (the latter allows
 648                    making subsequent call to continue enumeration) */
 649                 s->resume_index = *s->group_list.out.resume_handle;
 650                 s->count        = *s->group_list.out.num_entries;
 651 
 652                 /* prepare returned group accounts array */
 653                 s->groups       = talloc_array(c, struct grouplist, (*s->group_list.out.sam)->count);
 654                 if (composite_nomem(s->groups, c)) return;
 655 
 656                 for (i = 0; i < (*s->group_list.out.sam)->count; i++) {
 657                         struct dom_sid *group_sid;
 658                         struct samr_SamEntry *entry = &(*s->group_list.out.sam)->entries[i];
 659                         struct dom_sid *domain_sid = (*s->query_domain.out.info)->domain.sid;
 660                         
 661                         /* construct group sid from returned rid and queried domain sid */
 662                         group_sid = dom_sid_add_rid(c, domain_sid, entry->idx);
 663                         if (composite_nomem(group_sid, c)) return;
 664 
 665                         /* groupname */
 666                         s->groups[i].groupname = talloc_strdup(c, entry->name.string);
 667                         if (composite_nomem(s->groups[i].groupname, c)) return;
 668 
 669                         /* sid string */
 670                         s->groups[i].sid = dom_sid_string(c, group_sid);
 671                         if (composite_nomem(s->groups[i].sid, c)) return;
 672                 }
 673 
 674                 /* that's it */
 675                 composite_done(c);
 676 
 677         } else {
 678                 /* something went wrong */
 679                 composite_error(c, c->status);
 680         }
 681 }
 682 
 683 
 684 /**
 685  * Receive result of GroupList call
 686  *
 687  * @param c composite context returned by send request routine
 688  * @param mem_ctx memory context of this call
 689  * @param io pointer to structure containing arguments and result of this call
 690  * @param nt status
 691  */
 692 NTSTATUS libnet_GroupList_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 693                                struct libnet_GroupList *io)
 694 {
 695         NTSTATUS status;
 696         struct grouplist_state *s;
 697 
 698         if (c == NULL || mem_ctx == NULL || io == NULL) {
 699                 return NT_STATUS_INVALID_PARAMETER;
 700         }
 701 
 702         status = composite_wait(c);
 703         if (NT_STATUS_IS_OK(status) ||
 704             NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) ||
 705             NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
 706                 
 707                 s = talloc_get_type(c->private_data, struct grouplist_state);
 708                 
 709                 /* get results from composite context */
 710                 io->out.count        = s->count;
 711                 io->out.resume_index = s->resume_index;
 712                 io->out.groups       = talloc_steal(mem_ctx, s->groups);
 713 
 714                 if (NT_STATUS_IS_OK(status)) {
 715                         io->out.error_string = talloc_asprintf(mem_ctx, "Success");
 716                 } else {
 717                         /* success, but we're not done yet */
 718                         io->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)",
 719                                                                nt_errstr(status));
 720                 }
 721 
 722         } else {
 723                 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
 724         }
 725 
 726         return status;
 727 }
 728 
 729 
 730 /**
 731  * Enumerate domain groups
 732  *
 733  * @param ctx initialised libnet context
 734  * @param mem_ctx memory context of this call
 735  * @param io pointer to structure containing arguments and result of this call
 736  * @return nt status
 737  */
 738 NTSTATUS libnet_GroupList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 739                           struct libnet_GroupList *io)
 740 {
 741         struct composite_context *c;
 742 
 743         c = libnet_GroupList_send(ctx, mem_ctx, io, NULL);
 744         return libnet_GroupList_recv(c, mem_ctx, io);
 745 }

/* [<][>][^][v][top][bottom][index][help] */