@@ -1367,6 +1367,75 @@ static FnCallResult FnCallGetGid(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const P
1367
1367
#endif
1368
1368
}
1369
1369
1370
+ /*********************************************************************/
1371
+
1372
+ static FnCallResult no_entry (int ret , const FnCall * fp , const char * group_name , bool is_user_db )
1373
+ {
1374
+ assert (fp != NULL );
1375
+
1376
+ const char * entry_type = is_user_db ? "user" : "group" ;
1377
+ const char * db_type = is_user_db ? "passwd" : "group" ;
1378
+ if (ret == 0 || ret == ENOENT || ret == ESRCH || ret == EBADF || ret == EPERM )
1379
+ {
1380
+ Log (LOG_LEVEL_DEBUG , "Couldn't find %s '%s' in %s database" , entry_type , group_name , db_type );
1381
+ return FnReturnContext (false);
1382
+ }
1383
+ const char * const error_msg = GetErrorStrFromCode (ret );
1384
+ Log (LOG_LEVEL_ERR , "Couldn't open %s database in function '%s': %s" , db_type , fp -> name , error_msg );
1385
+ return FnFailure ();
1386
+ }
1387
+
1388
+ static FnCallResult FnCallUserInGroup (ARG_UNUSED EvalContext * ctx , ARG_UNUSED const Policy * policy , const FnCall * fp , const Rlist * finalargs )
1389
+ {
1390
+ assert (fp != NULL );
1391
+ assert (finalargs != NULL );
1392
+ #ifdef _WIN32
1393
+ Log (LOG_LEVEL_ERR , "Function '%s' is POSIX specific" , fp -> name );
1394
+ return FnFailure ();
1395
+ #else
1396
+
1397
+ const char * user_name = RlistScalarValue (finalargs );
1398
+ const char * group_name = RlistScalarValue (finalargs -> next );
1399
+ assert (group_name != NULL ); // Guaranteed by parser
1400
+
1401
+ int ret ;
1402
+
1403
+ // Check secondary group. This is what we expect the user to check for, thus it comes first.
1404
+ struct group grp ;
1405
+ struct group * grent ;
1406
+ char gr_buf [GETGR_R_SIZE_MAX ] = {0 };
1407
+ ret = getgrnam_r (group_name , & grp , gr_buf , GETGR_R_SIZE_MAX , & grent );
1408
+
1409
+ if (grent == NULL )
1410
+ {
1411
+ // Group does not exist at all, so cannot be
1412
+ // primary or secondary group of user
1413
+ return no_entry (ret , fp , group_name , false);
1414
+ }
1415
+ while (grent -> gr_mem [0 ] != NULL )
1416
+ {
1417
+ if (StringEqual (grent -> gr_mem [0 ], user_name ))
1418
+ {
1419
+ return FnReturnContext (true);
1420
+ }
1421
+ grent -> gr_mem ++ ;
1422
+ }
1423
+
1424
+ // Check primary group
1425
+ struct passwd pwd ;
1426
+ struct passwd * pwent ;
1427
+ char pw_buf [GETPW_R_SIZE_MAX ] = {0 };
1428
+ ret = getpwnam_r (user_name , & pwd , pw_buf , GETPW_R_SIZE_MAX , & pwent );
1429
+
1430
+ if (pwent == NULL )
1431
+ {
1432
+ return no_entry (ret , fp , user_name , true);
1433
+ }
1434
+ return FnReturnContext (grent -> gr_gid == pwent -> pw_gid );
1435
+
1436
+ #endif
1437
+ }
1438
+
1370
1439
/*********************************************************************/
1371
1440
1372
1441
static FnCallResult FnCallHandlerHash (ARG_UNUSED EvalContext * ctx , ARG_UNUSED const Policy * policy , ARG_UNUSED const FnCall * fp , const Rlist * finalargs )
@@ -9885,6 +9954,13 @@ static const FnCallArg GETUID_ARGS[] =
9885
9954
{NULL , CF_DATA_TYPE_NONE , NULL }
9886
9955
};
9887
9956
9957
+ static const FnCallArg USERINGROUP_ARGS [] =
9958
+ {
9959
+ {CF_ANYSTRING , CF_DATA_TYPE_STRING , "User name" },
9960
+ {CF_ANYSTRING , CF_DATA_TYPE_STRING , "Group name" },
9961
+ {NULL , CF_DATA_TYPE_NONE , NULL }
9962
+ };
9963
+
9888
9964
static const FnCallArg GETUSERINFO_ARGS [] =
9889
9965
{
9890
9966
{CF_ANYSTRING , CF_DATA_TYPE_STRING , "User name in text" },
@@ -10936,7 +11012,9 @@ const FnCallType CF_FNCALL_TYPES[] =
10936
11012
FnCallTypeNew ("randomint" , CF_DATA_TYPE_INT , RANDOMINT_ARGS , & FnCallRandomInt , "Generate a random integer between the given limits, excluding the upper" ,
10937
11013
FNCALL_OPTION_NONE , FNCALL_CATEGORY_DATA , SYNTAX_STATUS_NORMAL ),
10938
11014
FnCallTypeNew ("hash_to_int" , CF_DATA_TYPE_INT , HASH_TO_INT_ARGS , & FnCallHashToInt , "Generate an integer in given range based on string hash" ,
10939
- FNCALL_OPTION_NONE , FNCALL_CATEGORY_DATA , SYNTAX_STATUS_NORMAL ),
11015
+ FNCALL_OPTION_NONE , FNCALL_CATEGORY_DATA , SYNTAX_STATUS_NORMAL ),
11016
+ FnCallTypeNew ("useringroup" , CF_DATA_TYPE_CONTEXT , USERINGROUP_ARGS , & FnCallUserInGroup , "Checks whether a user is in a group" ,
11017
+ FNCALL_OPTION_NONE , FNCALL_CATEGORY_DATA , SYNTAX_STATUS_NORMAL ),
10940
11018
10941
11019
FnCallTypeNew ("string" , CF_DATA_TYPE_STRING , STRING_ARGS , & FnCallString , "Convert argument to string" ,
10942
11020
FNCALL_OPTION_NONE , FNCALL_CATEGORY_DATA , SYNTAX_STATUS_NORMAL ),
0 commit comments