notify: add new --uid= command

The new --uid= switch allows selecting the UID from which the
notificaiton messages shall originate.

This is primarily useful for testing purposes, but might have other
uses.
This commit is contained in:
Lennart Poettering 2018-01-05 13:26:38 +01:00
parent 9e1d021ee3
commit 65c6b99094
2 changed files with 45 additions and 2 deletions

View file

@ -122,6 +122,15 @@
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--uid=</option><replaceable>USER</replaceable></term>
<listitem><para>Set the user ID to send the notification from. Takes a UNIX user name or numeric UID. When
specified the notification message will be sent with the specified UID as sender, in place of the user the
command was invoked as. This option requires sufficient privileges in order to be able manipulate the user
identity of the process.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--status=</option></term>

View file

@ -33,12 +33,15 @@
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
#include "util.h"
static bool arg_ready = false;
static pid_t arg_pid = 0;
static const char *arg_status = NULL;
static bool arg_booted = false;
static uid_t arg_uid = UID_INVALID;
static gid_t arg_gid = GID_INVALID;
static void help(void) {
printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n"
@ -46,7 +49,8 @@ static void help(void) {
" -h --help Show this help\n"
" --version Show package version\n"
" --ready Inform the init system about service start-up completion\n"
" --pid[=PID] Set main pid of daemon\n"
" --pid[=PID] Set main PID of daemon\n"
" --uid=USER Set user to send from\n"
" --status=TEXT Set status text\n"
" --booted Check if the system was booted up with systemd\n",
program_invocation_short_name);
@ -60,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PID,
ARG_STATUS,
ARG_BOOTED,
ARG_UID,
};
static const struct option options[] = {
@ -69,10 +74,11 @@ static int parse_argv(int argc, char *argv[]) {
{ "pid", optional_argument, NULL, ARG_PID },
{ "status", required_argument, NULL, ARG_STATUS },
{ "booted", no_argument, NULL, ARG_BOOTED },
{ "uid", required_argument, NULL, ARG_UID },
{}
};
int c;
int c, r;
assert(argc >= 0);
assert(argv);
@ -112,6 +118,18 @@ static int parse_argv(int argc, char *argv[]) {
arg_booted = true;
break;
case ARG_UID: {
const char *u = optarg;
r = get_user_creds(&u, &arg_uid, &arg_gid, NULL, NULL);
if (r == -ESRCH) /* If the user doesn't exist, then accept it anyway as numeric */
r = parse_uid(u, &arg_uid);
if (r < 0)
return log_error_errno(r, "Can't resolve user %s: %m", optarg);
break;
}
case '?':
return -EINVAL;
@ -190,6 +208,22 @@ int main(int argc, char* argv[]) {
goto finish;
}
/* If this is requested change to the requested UID/GID. Note thta we only change the real UID here, and leave
the effective UID in effect (which is 0 for this to work). That's because we want the privileges to fake the
ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */
if (arg_gid != GID_INVALID)
if (setregid(arg_gid, (gid_t) -1) < 0) {
r = log_error_errno(errno, "Failed to change GID: %m");
goto finish;
}
if (arg_uid != UID_INVALID)
if (setreuid(arg_uid, (uid_t) -1) < 0) {
r = log_error_errno(errno, "Failed to change UID: %m");
goto finish;
}
r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
if (r < 0) {
log_error_errno(r, "Failed to notify init system: %m");