Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions libpromises/evalfunction.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,54 @@ static FnCallResult FnCallGetUsers(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const
/*********************************************************************/


#if defined(HAVE_GETPWENT) && !defined(__ANDROID__)

static FnCallResult FnCallGetGroups(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, ARG_UNUSED const FnCall *fp, const Rlist *finalargs)
{
assert(finalargs != NULL);
const char *except_name = RlistScalarValue(finalargs);
const char *except_uid = RlistScalarValue(finalargs->next);
Comment thread Fixed

Rlist *except_names = RlistFromSplitString(except_name, ',');
Rlist *except_uids = RlistFromSplitString(except_uid, ',');

setgrent();

Rlist *newlist = NULL;
struct group *gr;
while ((gr = getgrent()) != NULL)
{
char *gid_str = StringFromLong((int) gr->gr_gid);

if (!RlistKeyIn(except_names, gr->gr_name) && !RlistKeyIn(except_uids, gid_str))
{
RlistAppendScalarIdemp(&newlist, gr->gr_name);
}

free(gid_str);
}

endgrent();

RlistDestroy(except_names);
RlistDestroy(except_uids);

return (FnCallResult) { FNCALL_SUCCESS, { newlist, RVAL_TYPE_LIST } };
}

#else

static FnCallResult FnCallGetGroups(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, ARG_UNUSED const FnCall *fp, ARG_UNUSED const Rlist *finalargs)
{
Log(LOG_LEVEL_ERR, "getgroups is not supported");
return FnFailure();
}

#endif

/*********************************************************************/


#if defined(HAVE_GETPWENT) && !defined(__ANDROID__)

static FnCallResult FnCallFindLocalUsers(EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs)
Expand Down Expand Up @@ -10445,6 +10493,13 @@ static const FnCallArg GETUSERS_ARGS[] =
{NULL, CF_DATA_TYPE_NONE, NULL}
};

static const FnCallArg GETGROUPS_ARGS[] =
{
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "Comma separated list of Group names"},
{CF_ANYSTRING, CF_DATA_TYPE_STRING, "Comma separated list of GroupID numbers"},
{NULL, CF_DATA_TYPE_NONE, NULL}
};

static const FnCallArg GETENV_ARGS[] =
{
{CF_IDRANGE, CF_DATA_TYPE_STRING, "Name of environment variable"},
Expand Down Expand Up @@ -11427,6 +11482,8 @@ const FnCallType CF_FNCALL_TYPES[] =
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL),
FnCallTypeNew("getgroupinfo", CF_DATA_TYPE_CONTAINER, GETGROUPINFO_ARGS, &FnCallGetGroupInfo, "Get a data container describing specified group, or current group if not specified",
FNCALL_OPTION_VARARG, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL),
FnCallTypeNew("getgroups", CF_DATA_TYPE_STRING_LIST, GETGROUPS_ARGS, &FnCallGetGroups, "Get a list of all system groups defined, minus those names defined in the first argument and group IDs defined in the second argument",
FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL),
FnCallTypeNew("getvalues", CF_DATA_TYPE_STRING_LIST, GETINDICES_ARGS, &FnCallGetValues, "Get a list of values in the list or array or data container arg1",
FNCALL_OPTION_COLLECTING, FNCALL_CATEGORY_DATA, SYNTAX_STATUS_NORMAL),
FnCallTypeNew("getvariablemetatags", CF_DATA_TYPE_STRING_LIST, GETVARIABLEMETATAGS_ARGS, &FnCallGetMetaTags, "Collect the variable arg1's meta tags into an slist, optionally collecting only tag key arg2",
Expand Down
58 changes: 58 additions & 0 deletions tests/acceptance/01_vars/02_functions/getgroups.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#######################################################
#
# Test getgroups(), list content
#
#######################################################

body common control
{
inputs => { "../../default.cf.sub" };
bundlesequence => { check };
version => "1.0";
}

bundle agent check
{
meta:
"description" -> { "ENT-12722" }
string => "Test whether the entries of getroups() are like the ones inside /etc/group";
"test_skip_unsupported"
string => "windows";
Comment thread
victormlg marked this conversation as resolved.
vars:
"group_entries"
slist => splitstring(readfile("/etc/group"), "\n", 10);
"actual_groups_unfiltered"
slist => maplist(
nth(splitstring("$(this)", ":", 2), 0), "@(group_entries)"
);
# slice out the 3 first entries: root, bin, daemon
"actual_groups"
slist => sublist("@(actual_groups_unfiltered)", "tail", 7);
# get the first 7 groups, without root, bin and deamon
"retrieved_groups_arg1"
slist => sublist(getgroups("root,daemon,bin", ""), "head", 7);
"retrieved_groups_arg2"
slist => sublist(getgroups("", "0,1,2"), "head", 7);
"retrieved_groups_arg1_arg2"
slist => sublist(getgroups("root,daemon", "1,2"), "head", 7);
"actual_groups_content"
string => join(" ", "@(actual_groups)");
"retrieved_groups_content_arg1"
string => join(" ", "@(retrieved_groups_arg1)");
"retrieved_groups_content_arg2"
string => join(" ", "@(retrieved_groups_arg2)");
"retrieved_groups_content_arg1_arg2"
string => join(" ", "@(retrieved_groups_arg1_arg2)");
classes:
"ok"
expression => and(
strcmp("$(actual_groups_content)", "$(retrieved_groups_content_arg1)"),
strcmp("$(actual_groups_content)", "$(retrieved_groups_content_arg2)"),
strcmp("$(actual_groups_content)", "$(retrieved_groups_content_arg1_arg2)")
);
reports:
ok::
"$(this.promise_filename) Pass";
!ok::
"$(this.promise_filename) FAIL";
}
Loading