diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index 0dfda10936..9fa57ebf53 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -935,11 +935,12 @@ static FnCallResult FnCallGetEnv(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const P static FnCallResult FnCallGetUsers(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, ARG_UNUSED const FnCall *fp, const Rlist *finalargs) { - const char *except_name = RlistScalarValue(finalargs); - const char *except_uid = RlistScalarValue(finalargs->next); + const char *first_arg = (finalargs != NULL) ? RlistScalarValue(finalargs) : NULL; + const char *second_arg = (finalargs != NULL && finalargs->next != NULL) ? RlistScalarValue(finalargs->next) : NULL; - Rlist *except_names = RlistFromSplitString(except_name, ','); - Rlist *except_uids = RlistFromSplitString(except_uid, ','); + + Rlist *except_names = RlistFromSplitString(first_arg, ','); + Rlist *except_uids = RlistFromSplitString(second_arg, ','); setpwent(); @@ -982,12 +983,11 @@ static FnCallResult FnCallGetUsers(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const 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); + const char *first_arg = (finalargs != NULL) ? RlistScalarValue(finalargs) : NULL; + const char *second_arg = (finalargs != NULL && finalargs->next != NULL) ? RlistScalarValue(finalargs->next) : NULL; - Rlist *except_names = RlistFromSplitString(except_name, ','); - Rlist *except_uids = RlistFromSplitString(except_uid, ','); + Rlist *except_names = RlistFromSplitString(first_arg, ','); + Rlist *except_uids = RlistFromSplitString(second_arg, ','); setgrent(); @@ -11621,13 +11621,13 @@ const FnCallType CF_FNCALL_TYPES[] = FnCallTypeNew("getuid", CF_DATA_TYPE_INT, GETUID_ARGS, &FnCallGetUid, "Return the integer user id of the named user on this host", FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL), FnCallTypeNew("getusers", CF_DATA_TYPE_STRING_LIST, GETUSERS_ARGS, &FnCallGetUsers, "Get a list of all system users defined, minus those names defined in arg1 and uids in arg2", - FNCALL_OPTION_NONE, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL), + FNCALL_OPTION_VARARG, FNCALL_CATEGORY_SYSTEM, SYNTAX_STATUS_NORMAL), FnCallTypeNew("getuserinfo", CF_DATA_TYPE_CONTAINER, GETUSERINFO_ARGS, &FnCallGetUserInfo, "Get a data container describing user arg1, defaulting to current user", 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), + FNCALL_OPTION_VARARG, 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", diff --git a/tests/acceptance/01_vars/02_functions/getgroups_vararg.cf b/tests/acceptance/01_vars/02_functions/getgroups_vararg.cf new file mode 100644 index 0000000000..29cb3cdfff --- /dev/null +++ b/tests/acceptance/01_vars/02_functions/getgroups_vararg.cf @@ -0,0 +1,62 @@ +####################################################### +# +# Test getgroups() variable args +# +####################################################### + +body common control +{ + inputs => { "../../default.cf.sub" }; + bundlesequence => { default("$(this.promise_filename)") }; + version => "1.0"; +} +bundle agent test +{ + meta: + "description" + string => "Test variable arguments with getgroups()"; + + "test_skip_unsupported" + string => "windows"; + vars: + "group_entries" slist => splitstring(string_trim(readfile("/etc/group")), "\n", 999); + + "name_list" + slist => maplist( + nth(splitstring("$(this)", ":", 1), 0), + "@(group_entries)" + ); + "actual_groups_content" + string => join(" ", sort("@(name_list)", "lex")); + + "groups1" slist => getgroups(); + "groups2" slist => getgroups(""); + "groups3" slist => getgroups("",""); + + "retrieved_groups_content_1" + string => join(" ", sort("@(groups1)", "lex")); + "retrieved_groups_content_2" + string => join(" ", sort("@(groups2)", "lex")); + "retrieved_groups_content_3" + string => join(" ", sort("@(groups3)", "lex")); + +} + +bundle agent check +{ + + classes: + "ok" + expression => and( + strcmp("$(test.actual_groups_content)", "$(test.retrieved_groups_content_1)"), + strcmp("$(test.actual_groups_content)", "$(test.retrieved_groups_content_2)"), + strcmp("$(test.actual_groups_content)", "$(test.retrieved_groups_content_3)") + ); + + reports: + ok:: + "$(this.promise_filename) Pass"; + + !ok:: + "$(this.promise_filename) FAIL"; +} diff --git a/tests/acceptance/01_vars/02_functions/getusers_vararg.cf b/tests/acceptance/01_vars/02_functions/getusers_vararg.cf new file mode 100644 index 0000000000..07b9054477 --- /dev/null +++ b/tests/acceptance/01_vars/02_functions/getusers_vararg.cf @@ -0,0 +1,62 @@ +####################################################### +# +# Test getusers() variable args +# +####################################################### + +body common control +{ + inputs => { "../../default.cf.sub" }; + bundlesequence => { default("$(this.promise_filename)") }; + version => "1.0"; +} +bundle agent test +{ + meta: + "description" -> { "ENT-9962" } + string => "Test variable arguments with getusers()"; + + "test_skip_unsupported" + string => "windows"; + vars: + "user_entries" slist => splitstring(string_trim(readfile("/etc/passwd")), "\n", 999); + + "name_list" + slist => maplist( + nth(splitstring("$(this)", ":", 1), 0), + "@(user_entries)" + ); + "actual_users_content" + string => join(" ", sort("@(name_list)", "lex")); + + "users1" slist => getusers(); + "users2" slist => getusers(""); + "users3" slist => getusers("",""); + + "retrieved_users_content_1" + string => join(" ", sort("@(users1)", "lex")); + "retrieved_users_content_2" + string => join(" ", sort("@(users2)", "lex")); + "retrieved_users_content_3" + string => join(" ", sort("@(users3)", "lex")); + +} + +bundle agent check +{ + + classes: + "ok" + expression => and( + strcmp("$(test.actual_users_content)", "$(test.retrieved_users_content_1)"), + strcmp("$(test.actual_users_content)", "$(test.retrieved_users_content_2)"), + strcmp("$(test.actual_users_content)", "$(test.retrieved_users_content_3)") + ); + + reports: + ok:: + "$(this.promise_filename) Pass"; + + !ok:: + "$(this.promise_filename) FAIL"; +}