Files
shadow/libmisc/prefix_flag.c
Alejandro Colomar 09775d3718 Simplify allocation APIs
If we consider simple objects as arrays of size 1, we can considerably
simplify these APIs, merging the *ARRAY and the non-array variants.

That will produce more readable code, since lines will be shorter (by
not having ARRAY in the macro names, as all macros will consistently
handle arrays), and the allocated size will be also more explicit.

The syntax will now be of the form:

    p = MALLOC(42, foo_t);  // allocate 42 elements of type foo_t.
    p = MALLOC(1, bar_t);   // allocate 1 element of type foo_t.

The _array() allocation functions should _never_ be called directly, and
instead these macros should be used.

The non-array functions (e.g., malloc(3)) still have their place, but
are limited to allocating structures with flexible array members.  For
any other uses, the macros should be used.

Thus, we don't use any array or ARRAY variants in any code any more, and
they are only used as implementation details of these macros.

Link: <https://software.codidact.com/posts/285898/288023#answer-288023>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-06-08 09:05:39 -05:00

352 lines
7.2 KiB
C

/*
* SPDX-FileCopyrightText: 2011 , Julian Pidancet
* SPDX-FileCopyrightText: 2011 , Nicolas François
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#ident "$Id$"
#include <stdio.h>
#include <assert.h>
#include "defines.h"
#include "alloc.h"
#include "prototypes.h"
/*@-exitarg@*/
#include "exitcodes.h"
#include "groupio.h"
#include "pwio.h"
#ifdef SHADOWGRP
#include "sgroupio.h"
#endif
#include "shadowio.h"
#ifdef ENABLE_SUBIDS
#include "subordinateio.h"
#endif /* ENABLE_SUBIDS */
#include "getdef.h"
#include "shadowlog.h"
static char *passwd_db_file = NULL;
static char *spw_db_file = NULL;
static char *group_db_file = NULL;
static char *sgroup_db_file = NULL;
static char *suid_db_file = NULL;
static char *sgid_db_file = NULL;
static char *def_conf_file = NULL;
static FILE* fp_pwent = NULL;
static FILE* fp_grent = NULL;
/*
* process_prefix_flag - prefix all paths if given the --prefix option
*
* This shall be called before accessing the passwd, group, shadow,
* gshadow, useradd's default, login.defs files (non exhaustive list)
* or authenticating the caller.
*
* The audit, syslog, or locale files shall be open before
*/
extern const char* process_prefix_flag (const char* short_opt, int argc, char **argv)
{
/*
* Parse the command line options.
*/
int i;
const char *prefix = NULL, *val;
for (i = 0; i < argc; i++) {
val = NULL;
if ( (strcmp (argv[i], "--prefix") == 0)
|| ((strncmp (argv[i], "--prefix=", 9) == 0)
&& (val = argv[i] + 9))
|| (strcmp (argv[i], short_opt) == 0)) {
if (NULL != prefix) {
fprintf (log_get_logfd(),
_("%s: multiple --prefix options\n"),
log_get_progname());
exit (E_BAD_ARG);
}
if (val) {
prefix = val;
} else if (i + 1 == argc) {
fprintf (log_get_logfd(),
_("%s: option '%s' requires an argument\n"),
log_get_progname(), argv[i]);
exit (E_BAD_ARG);
} else {
prefix = argv[++ i];
}
}
}
if (prefix != NULL) {
/* Drop privileges */
if ( (setregid (getgid (), getgid ()) != 0)
|| (setreuid (getuid (), getuid ()) != 0)) {
fprintf (log_get_logfd(),
_("%s: failed to drop privileges (%s)\n"),
log_get_progname(), strerror (errno));
exit (EXIT_FAILURE);
}
if ( prefix[0] == '\0' || !strcmp(prefix, "/"))
return ""; /* if prefix is "/" then we ignore the flag option */
/* should we prevent symbolic link from being used as a prefix? */
if ( prefix[0] != '/') {
fprintf (log_get_logfd(),
_("%s: prefix must be an absolute path\n"),
log_get_progname());
exit (E_BAD_ARG);
}
size_t len;
len = strlen(prefix) + strlen(PASSWD_FILE) + 2;
passwd_db_file = XMALLOC(len, char);
snprintf(passwd_db_file, len, "%s/%s", prefix, PASSWD_FILE);
pw_setdbname(passwd_db_file);
len = strlen(prefix) + strlen(GROUP_FILE) + 2;
group_db_file = XMALLOC(len, char);
snprintf(group_db_file, len, "%s/%s", prefix, GROUP_FILE);
gr_setdbname(group_db_file);
#ifdef SHADOWGRP
len = strlen(prefix) + strlen(SGROUP_FILE) + 2;
sgroup_db_file = XMALLOC(len, char);
snprintf(sgroup_db_file, len, "%s/%s", prefix, SGROUP_FILE);
sgr_setdbname(sgroup_db_file);
#endif
#ifdef USE_NIS
__setspNIS(0); /* disable NIS for now, at least until it is properly supporting a "prefix" */
#endif
len = strlen(prefix) + strlen(SHADOW_FILE) + 2;
spw_db_file = XMALLOC(len, char);
snprintf(spw_db_file, len, "%s/%s", prefix, SHADOW_FILE);
spw_setdbname(spw_db_file);
#ifdef ENABLE_SUBIDS
len = strlen(prefix) + strlen("/etc/subuid") + 2;
suid_db_file = XMALLOC(len, char);
snprintf(suid_db_file, len, "%s/%s", prefix, "/etc/subuid");
sub_uid_setdbname(suid_db_file);
len = strlen(prefix) + strlen("/etc/subgid") + 2;
sgid_db_file = XMALLOC(len, char);
snprintf(sgid_db_file, len, "%s/%s", prefix, "/etc/subgid");
sub_gid_setdbname(sgid_db_file);
#endif
#ifdef USE_ECONF
setdef_config_file(prefix);
#else
len = strlen(prefix) + strlen("/etc/login.defs") + 2;
def_conf_file = XMALLOC(len, char);
snprintf(def_conf_file, len, "%s/%s", prefix, "/etc/login.defs");
setdef_config_file(def_conf_file);
#endif
}
if (prefix == NULL)
return "";
return prefix;
}
extern struct group *prefix_getgrnam(const char *name)
{
if (group_db_file) {
FILE* fg;
struct group * grp = NULL;
fg = fopen(group_db_file, "rt");
if (!fg)
return NULL;
while ((grp = fgetgrent(fg)) != NULL) {
if (!strcmp(name, grp->gr_name))
break;
}
fclose(fg);
return grp;
}
return getgrnam(name);
}
extern struct group *prefix_getgrgid(gid_t gid)
{
if (group_db_file) {
FILE* fg;
struct group * grp = NULL;
fg = fopen(group_db_file, "rt");
if (!fg)
return NULL;
while ((grp = fgetgrent(fg)) != NULL) {
if (gid == grp->gr_gid)
break;
}
fclose(fg);
return grp;
}
return getgrgid(gid);
}
extern struct passwd *prefix_getpwuid(uid_t uid)
{
if (passwd_db_file) {
FILE* fg;
struct passwd *pwd = NULL;
fg = fopen(passwd_db_file, "rt");
if (!fg)
return NULL;
while ((pwd = fgetpwent(fg)) != NULL) {
if (uid == pwd->pw_uid)
break;
}
fclose(fg);
return pwd;
}
else {
return getpwuid(uid);
}
}
extern struct passwd *prefix_getpwnam(const char* name)
{
if (passwd_db_file) {
FILE* fg;
struct passwd *pwd = NULL;
fg = fopen(passwd_db_file, "rt");
if (!fg)
return NULL;
while ((pwd = fgetpwent(fg)) != NULL) {
if (!strcmp(name, pwd->pw_name))
break;
}
fclose(fg);
return pwd;
}
else {
return getpwnam(name);
}
}
extern struct spwd *prefix_getspnam(const char* name)
{
if (spw_db_file) {
FILE* fg;
struct spwd *sp = NULL;
fg = fopen(spw_db_file, "rt");
if (!fg)
return NULL;
while ((sp = fgetspent(fg)) != NULL) {
if (!strcmp(name, sp->sp_namp))
break;
}
fclose(fg);
return sp;
}
else {
return getspnam(name);
}
}
extern void prefix_setpwent(void)
{
if (!passwd_db_file) {
setpwent();
return;
}
if (fp_pwent)
fclose (fp_pwent);
fp_pwent = fopen(passwd_db_file, "rt");
if (!fp_pwent)
return;
}
extern struct passwd* prefix_getpwent(void)
{
if (!passwd_db_file) {
return getpwent();
}
if (!fp_pwent) {
return NULL;
}
return fgetpwent(fp_pwent);
}
extern void prefix_endpwent(void)
{
if (!passwd_db_file) {
endpwent();
return;
}
if (fp_pwent)
fclose(fp_pwent);
fp_pwent = NULL;
}
extern void prefix_setgrent(void)
{
if (!group_db_file) {
setgrent();
return;
}
if (fp_grent)
fclose (fp_grent);
fp_grent = fopen(group_db_file, "rt");
if (!fp_grent)
return;
}
extern struct group* prefix_getgrent(void)
{
if (!group_db_file) {
return getgrent();
}
return fgetgrent(fp_grent);
}
extern void prefix_endgrent(void)
{
if (!group_db_file) {
endgrent();
return;
}
if (fp_grent)
fclose(fp_grent);
fp_grent = NULL;
}
extern struct group *prefix_getgr_nam_gid(const char *grname)
{
long long int gid;
char *endptr;
struct group *g;
if (NULL == grname) {
return NULL;
}
if (group_db_file) {
errno = 0;
gid = strtoll (grname, &endptr, 10);
if ( ('\0' != *grname)
&& ('\0' == *endptr)
&& (ERANGE != errno)
&& (gid == (gid_t)gid)) {
return prefix_getgrgid (gid);
}
g = prefix_getgrnam (grname);
return g ? __gr_dup(g) : NULL;
}
else
return getgr_nam_gid(grname);
}