ask-password: add minimal framework to allow services query SSL/harddisk passphrases from the user
This commit is contained in:
parent
1ebdf5b684
commit
490aed5849
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
|
systemd-reply-password
|
||||||
|
systemd-ask-password-agent
|
||||||
|
systemd-ask-password
|
||||||
systemd-kmsg-syslogd
|
systemd-kmsg-syslogd
|
||||||
systemd-remount-api-vfs
|
systemd-remount-api-vfs
|
||||||
test-hostname
|
test-hostname
|
||||||
|
|
49
Makefile.am
49
Makefile.am
|
@ -25,6 +25,7 @@ dbusinterfacedir=@dbusinterfacedir@
|
||||||
udevrulesdir=@udevrulesdir@
|
udevrulesdir=@udevrulesdir@
|
||||||
pamlibdir=@pamlibdir@
|
pamlibdir=@pamlibdir@
|
||||||
pkgconfigdatadir=$(datadir)/pkgconfig
|
pkgconfigdatadir=$(datadir)/pkgconfig
|
||||||
|
polkitpolicydir=$(datadir)/polkit-1/actions
|
||||||
|
|
||||||
# Our own, non-special dirs
|
# Our own, non-special dirs
|
||||||
pkgsysconfdir=$(sysconfdir)/systemd
|
pkgsysconfdir=$(sysconfdir)/systemd
|
||||||
|
@ -56,14 +57,16 @@ AM_CPPFLAGS = \
|
||||||
rootbin_PROGRAMS = \
|
rootbin_PROGRAMS = \
|
||||||
systemd \
|
systemd \
|
||||||
systemctl \
|
systemctl \
|
||||||
systemd-notify
|
systemd-notify \
|
||||||
|
systemd-ask-password
|
||||||
|
|
||||||
bin_PROGRAMS = \
|
bin_PROGRAMS = \
|
||||||
systemd-cgls
|
systemd-cgls
|
||||||
|
|
||||||
if HAVE_GTK
|
if HAVE_GTK
|
||||||
bin_PROGRAMS += \
|
bin_PROGRAMS += \
|
||||||
systemadm
|
systemadm \
|
||||||
|
systemd-ask-password-agent
|
||||||
endif
|
endif
|
||||||
|
|
||||||
rootlibexec_PROGRAMS = \
|
rootlibexec_PROGRAMS = \
|
||||||
|
@ -76,7 +79,8 @@ rootlibexec_PROGRAMS = \
|
||||||
systemd-modules-load \
|
systemd-modules-load \
|
||||||
systemd-remount-api-vfs \
|
systemd-remount-api-vfs \
|
||||||
systemd-kmsg-syslogd \
|
systemd-kmsg-syslogd \
|
||||||
systemd-vconsole-setup
|
systemd-vconsole-setup \
|
||||||
|
systemd-reply-password
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
noinst_PROGRAMS = \
|
||||||
test-engine \
|
test-engine \
|
||||||
|
@ -282,6 +286,9 @@ dist_doc_DATA = \
|
||||||
pkgconfigdata_DATA = \
|
pkgconfigdata_DATA = \
|
||||||
systemd.pc
|
systemd.pc
|
||||||
|
|
||||||
|
dist_polkitpolicy_DATA = \
|
||||||
|
src/org.freedesktop.systemd1.policy
|
||||||
|
|
||||||
noinst_LTLIBRARIES = \
|
noinst_LTLIBRARIES = \
|
||||||
libsystemd-basic.la \
|
libsystemd-basic.la \
|
||||||
libsystemd-core.la
|
libsystemd-core.la
|
||||||
|
@ -665,6 +672,18 @@ systemd_notify_SOURCES = \
|
||||||
systemd_notify_LDADD = \
|
systemd_notify_LDADD = \
|
||||||
libsystemd-basic.la
|
libsystemd-basic.la
|
||||||
|
|
||||||
|
systemd_ask_password_SOURCES = \
|
||||||
|
src/ask-password.c
|
||||||
|
|
||||||
|
systemd_ask_password_LDADD = \
|
||||||
|
libsystemd-basic.la
|
||||||
|
|
||||||
|
systemd_reply_password_SOURCES = \
|
||||||
|
src/reply-password.c
|
||||||
|
|
||||||
|
systemd_reply_password_LDADD = \
|
||||||
|
libsystemd-basic.la
|
||||||
|
|
||||||
systemd_cgls_SOURCES = \
|
systemd_cgls_SOURCES = \
|
||||||
src/cgls.c \
|
src/cgls.c \
|
||||||
src/cgroup-show.c \
|
src/cgroup-show.c \
|
||||||
|
@ -699,6 +718,30 @@ systemadm_LDADD = \
|
||||||
$(DBUSGLIB_LIBS) \
|
$(DBUSGLIB_LIBS) \
|
||||||
$(GTK_LIBS)
|
$(GTK_LIBS)
|
||||||
|
|
||||||
|
systemd_ask_password_agent_SOURCES = \
|
||||||
|
src/ask-password-agent.vala
|
||||||
|
|
||||||
|
systemd_ask_password_agent_CFLAGS = \
|
||||||
|
$(AM_CFLAGS) \
|
||||||
|
$(DBUSGLIB_CFLAGS) \
|
||||||
|
$(GTK_CFLAGS) \
|
||||||
|
-Wno-unused-variable \
|
||||||
|
-Wno-unused-function \
|
||||||
|
-Wno-shadow \
|
||||||
|
-Wno-format-nonliteral
|
||||||
|
|
||||||
|
systemd_ask_password_agent_VALAFLAGS = \
|
||||||
|
--pkg=dbus-glib-1 \
|
||||||
|
--pkg=posix \
|
||||||
|
--pkg=gtk+-2.0 \
|
||||||
|
--pkg=linux \
|
||||||
|
--pkg=gio-unix-2.0 \
|
||||||
|
-g
|
||||||
|
|
||||||
|
systemd_ask_password_agent_LDADD = \
|
||||||
|
$(DBUSGLIB_LIBS) \
|
||||||
|
$(GTK_LIBS)
|
||||||
|
|
||||||
pam_systemd_la_SOURCES = \
|
pam_systemd_la_SOURCES = \
|
||||||
src/pam-module.c \
|
src/pam-module.c \
|
||||||
src/cgroup-util.c \
|
src/cgroup-util.c \
|
||||||
|
|
|
@ -226,7 +226,7 @@ AC_SUBST(AUDIT_LIBS)
|
||||||
have_gtk=no
|
have_gtk=no
|
||||||
AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools]))
|
AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools]))
|
||||||
if test "x$enable_gtk" != "xno"; then
|
if test "x$enable_gtk" != "xno"; then
|
||||||
PKG_CHECK_MODULES(GTK, [ gtk+-2.0 ],
|
PKG_CHECK_MODULES(GTK, [ gtk+-2.0 gio-unix-2.0 ],
|
||||||
[AC_DEFINE(HAVE_GTK, 1, [Define if GTK is available]) have_gtk=yes], have_gtk=no)
|
[AC_DEFINE(HAVE_GTK, 1, [Define if GTK is available]) have_gtk=yes], have_gtk=no)
|
||||||
AC_SUBST(GTK_CFLAGS)
|
AC_SUBST(GTK_CFLAGS)
|
||||||
AC_SUBST(GTK_LIBS)
|
AC_SUBST(GTK_LIBS)
|
||||||
|
|
1
src/.gitignore
vendored
1
src/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
|
ask-password-agent.c
|
||||||
systemd-interfaces.c
|
systemd-interfaces.c
|
||||||
systemadm.c
|
systemadm.c
|
||||||
|
|
250
src/ask-password-agent.vala
Normal file
250
src/ask-password-agent.vala
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 2010 Lennart Poettering
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
systemd is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
using Gtk;
|
||||||
|
using GLib;
|
||||||
|
using DBus;
|
||||||
|
using Linux;
|
||||||
|
using Posix;
|
||||||
|
|
||||||
|
[CCode (cheader_filename = "time.h")]
|
||||||
|
extern int clock_gettime(int id, out timespec ts);
|
||||||
|
|
||||||
|
public class PasswordDialog : Dialog {
|
||||||
|
|
||||||
|
public Entry entry;
|
||||||
|
|
||||||
|
public PasswordDialog(string message, string icon) {
|
||||||
|
set_title("System Password");
|
||||||
|
set_has_separator(false);
|
||||||
|
set_border_width(8);
|
||||||
|
set_default_response(ResponseType.OK);
|
||||||
|
set_icon_name(icon);
|
||||||
|
|
||||||
|
add_button(STOCK_CANCEL, ResponseType.CANCEL);
|
||||||
|
add_button(STOCK_OK, ResponseType.OK);
|
||||||
|
|
||||||
|
Container content = (Container) get_content_area();
|
||||||
|
|
||||||
|
Box hbox = new HBox(false, 16);
|
||||||
|
hbox.set_border_width(8);
|
||||||
|
content.add(hbox);
|
||||||
|
|
||||||
|
Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
|
||||||
|
hbox.pack_start(image, false, false);
|
||||||
|
|
||||||
|
Box vbox = new VBox(false, 8);
|
||||||
|
hbox.pack_start(vbox, true, true);
|
||||||
|
|
||||||
|
Label label = new Label(message);
|
||||||
|
vbox.pack_start(label, false, false);
|
||||||
|
|
||||||
|
entry = new Entry();
|
||||||
|
entry.set_visibility(false);
|
||||||
|
entry.set_activates_default(true);
|
||||||
|
vbox.pack_start(entry, false, false);
|
||||||
|
|
||||||
|
entry.activate.connect(on_entry_activated);
|
||||||
|
|
||||||
|
show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void on_entry_activated() {
|
||||||
|
response(ResponseType.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MyStatusIcon : StatusIcon {
|
||||||
|
|
||||||
|
File directory;
|
||||||
|
File current;
|
||||||
|
FileMonitor file_monitor;
|
||||||
|
|
||||||
|
string message;
|
||||||
|
string icon;
|
||||||
|
string socket;
|
||||||
|
|
||||||
|
PasswordDialog password_dialog;
|
||||||
|
|
||||||
|
public MyStatusIcon() throws GLib.Error {
|
||||||
|
GLib.Object(icon_name : "dialog-password");
|
||||||
|
set_title("System Password Agent");
|
||||||
|
|
||||||
|
directory = File.new_for_path("/dev/.systemd/ask-password/");
|
||||||
|
file_monitor = directory.monitor_directory(0);
|
||||||
|
file_monitor.changed.connect(file_monitor_changed);
|
||||||
|
|
||||||
|
current = null;
|
||||||
|
look_for_password();
|
||||||
|
|
||||||
|
activate.connect(status_icon_activate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error {
|
||||||
|
|
||||||
|
if (!file.get_basename().has_prefix("ask."))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event_type == FileMonitorEvent.CREATED ||
|
||||||
|
event_type == FileMonitorEvent.DELETED)
|
||||||
|
look_for_password();
|
||||||
|
}
|
||||||
|
|
||||||
|
void look_for_password() throws GLib.Error {
|
||||||
|
|
||||||
|
if (current != null) {
|
||||||
|
if (!current.query_exists()) {
|
||||||
|
current = null;
|
||||||
|
if (password_dialog != null)
|
||||||
|
password_dialog.response(ResponseType.REJECT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == null) {
|
||||||
|
FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
|
||||||
|
|
||||||
|
FileInfo i;
|
||||||
|
while ((i = enumerator.next_file()) != null) {
|
||||||
|
if (!i.get_name().has_prefix("ask."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
current = directory.get_child(i.get_name());
|
||||||
|
|
||||||
|
if (load_password())
|
||||||
|
break;
|
||||||
|
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == null)
|
||||||
|
set_visible(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_password() {
|
||||||
|
|
||||||
|
KeyFile key_file = new KeyFile();
|
||||||
|
|
||||||
|
try {
|
||||||
|
timespec ts;
|
||||||
|
|
||||||
|
key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
|
||||||
|
|
||||||
|
string not_after_as_string = key_file.get_string("Ask", "NotAfter");
|
||||||
|
|
||||||
|
clock_gettime(1, out ts);
|
||||||
|
uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
|
||||||
|
|
||||||
|
uint64 not_after;
|
||||||
|
if (not_after_as_string.scanf("%llu", out not_after) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not_after < now)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
socket = key_file.get_string("Ask", "Socket");
|
||||||
|
} catch (GLib.Error e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
message = key_file.get_string("Ask", "Message").compress();
|
||||||
|
} catch (GLib.Error e) {
|
||||||
|
message = "Please Enter System Password!";
|
||||||
|
}
|
||||||
|
set_tooltip_text(message);
|
||||||
|
|
||||||
|
try {
|
||||||
|
icon = key_file.get_string("Ask", "Icon");
|
||||||
|
} catch (GLib.Error e) {
|
||||||
|
icon = "dialog-password";
|
||||||
|
}
|
||||||
|
set_from_icon_name(icon);
|
||||||
|
|
||||||
|
set_visible(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void status_icon_activate() throws GLib.Error {
|
||||||
|
|
||||||
|
if (current == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (password_dialog != null) {
|
||||||
|
password_dialog.present();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
password_dialog = new PasswordDialog(message, icon);
|
||||||
|
|
||||||
|
int result = password_dialog.run();
|
||||||
|
string password = password_dialog.entry.get_text();
|
||||||
|
|
||||||
|
password_dialog.destroy();
|
||||||
|
password_dialog = null;
|
||||||
|
|
||||||
|
if (result == ResponseType.REJECT ||
|
||||||
|
result == ResponseType.DELETE_EVENT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int to_process;
|
||||||
|
|
||||||
|
Process.spawn_async_with_pipes(
|
||||||
|
null,
|
||||||
|
{ "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
out to_process,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
OutputStream stream = new UnixOutputStream(to_process, true);
|
||||||
|
|
||||||
|
stream.write(password, password.length, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const OptionEntry entries[] = {
|
||||||
|
{ null }
|
||||||
|
};
|
||||||
|
|
||||||
|
void show_error(string e) {
|
||||||
|
var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
|
||||||
|
m.run();
|
||||||
|
m.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(string[] args) {
|
||||||
|
try {
|
||||||
|
Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
|
||||||
|
|
||||||
|
MyStatusIcon i = new MyStatusIcon();
|
||||||
|
Gtk.main();
|
||||||
|
|
||||||
|
} catch (DBus.Error e) {
|
||||||
|
show_error(e.message);
|
||||||
|
} catch (GLib.Error e) {
|
||||||
|
show_error(e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
352
src/ask-password.c
Normal file
352
src/ask-password.c
Normal file
|
@ -0,0 +1,352 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 2010 Lennart Poettering
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
systemd is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static const char *arg_icon = NULL;
|
||||||
|
static const char *arg_message = NULL;
|
||||||
|
static usec_t arg_timeout = 60 * USEC_PER_SEC;
|
||||||
|
|
||||||
|
static int create_socket(char **name) {
|
||||||
|
int fd;
|
||||||
|
union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_un un;
|
||||||
|
} sa;
|
||||||
|
int one = 1, r;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
|
||||||
|
log_error("socket() failed: %m");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
zero(sa);
|
||||||
|
sa.un.sun_family = AF_UNIX;
|
||||||
|
snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, "/org/freedesktop/systemd1/ask-password/%llu", random_ull());
|
||||||
|
|
||||||
|
if (bind(fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
log_error("bind() failed: %m");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
|
||||||
|
r = -errno;
|
||||||
|
log_error("SO_PASSCRED failed: %m");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(c = strdup(sa.un.sun_path+1))) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
log_error("Out of memory");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
*name = c;
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_nointr_nofail(fd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int help(void) {
|
||||||
|
|
||||||
|
printf("%s [OPTIONS...] MESSAGE\n\n"
|
||||||
|
"Query the user for a passphrase.\n\n"
|
||||||
|
" -h --help Show this help\n"
|
||||||
|
" --icon=NAME Icon name\n"
|
||||||
|
" --timeout=USEC Timeout in usec\n",
|
||||||
|
program_invocation_short_name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_argv(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_ICON = 0x100,
|
||||||
|
ARG_TIMEOUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option options[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "icon", required_argument, NULL, ARG_ICON },
|
||||||
|
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int c;
|
||||||
|
|
||||||
|
assert(argc >= 0);
|
||||||
|
assert(argv);
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
help();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case ARG_ICON:
|
||||||
|
arg_icon = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_TIMEOUT:
|
||||||
|
if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) {
|
||||||
|
log_error("Failed to parse --timeout parameter %s", optarg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_error("Unknown option code %c", c);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind != argc-1) {
|
||||||
|
help();
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_message = argv[optind];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX";
|
||||||
|
char final[sizeof(temp)] = "";
|
||||||
|
int fd = -1, r = EXIT_FAILURE, k;
|
||||||
|
FILE *f = NULL;
|
||||||
|
char *socket_name = NULL;
|
||||||
|
int socket_fd, signal_fd;
|
||||||
|
sigset_t mask;
|
||||||
|
usec_t not_after;
|
||||||
|
|
||||||
|
log_parse_environment();
|
||||||
|
log_open();
|
||||||
|
|
||||||
|
if ((k = parse_argv(argc, argv)) < 0) {
|
||||||
|
r = k < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
|
||||||
|
log_error("Failed to create password file: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fchmod(fd, 0644);
|
||||||
|
|
||||||
|
if (!(f = fdopen(fd, "w"))) {
|
||||||
|
log_error("Failed to allocate FILE: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
|
assert_se(sigemptyset(&mask) == 0);
|
||||||
|
sigset_add_many(&mask, SIGINT, SIGTERM, -1);
|
||||||
|
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
|
||||||
|
|
||||||
|
if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
|
||||||
|
log_error("signalfd(): %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((socket_fd = create_socket(&socket_name)) < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
not_after = now(CLOCK_MONOTONIC) + arg_timeout;
|
||||||
|
|
||||||
|
fprintf(f,
|
||||||
|
"[Ask]\n"
|
||||||
|
"Socket=%s\n"
|
||||||
|
"NotAfter=%llu\n",
|
||||||
|
socket_name,
|
||||||
|
(unsigned long long) not_after);
|
||||||
|
|
||||||
|
if (arg_message)
|
||||||
|
fprintf(f, "Message=%s\n", arg_message);
|
||||||
|
|
||||||
|
if (arg_icon)
|
||||||
|
fprintf(f, "Icon=%s\n", arg_icon);
|
||||||
|
|
||||||
|
fflush(f);
|
||||||
|
|
||||||
|
if (ferror(f)) {
|
||||||
|
log_error("Failed to write query file: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(final, temp, sizeof(temp));
|
||||||
|
|
||||||
|
final[sizeof(final)-11] = 'a';
|
||||||
|
final[sizeof(final)-10] = 's';
|
||||||
|
final[sizeof(final)-9] = 'k';
|
||||||
|
|
||||||
|
if (rename(temp, final) < 0) {
|
||||||
|
log_error("Failed to rename query file: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
enum {
|
||||||
|
FD_SOCKET,
|
||||||
|
FD_SIGNAL,
|
||||||
|
_FD_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
char passphrase[LINE_MAX+1];
|
||||||
|
struct msghdr msghdr;
|
||||||
|
struct iovec iovec;
|
||||||
|
struct ucred *ucred;
|
||||||
|
union {
|
||||||
|
struct cmsghdr cmsghdr;
|
||||||
|
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
||||||
|
} control;
|
||||||
|
ssize_t n;
|
||||||
|
struct pollfd pollfd[_FD_MAX];
|
||||||
|
|
||||||
|
zero(pollfd);
|
||||||
|
pollfd[FD_SOCKET].fd = socket_fd;
|
||||||
|
pollfd[FD_SOCKET].events = POLLIN;
|
||||||
|
pollfd[FD_SIGNAL].fd = signal_fd;
|
||||||
|
pollfd[FD_SIGNAL].events = POLLIN;
|
||||||
|
|
||||||
|
if ((k = poll(pollfd, 2, arg_timeout/USEC_PER_MSEC)) < 0) {
|
||||||
|
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log_error("poll() failed: %s", strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k <= 0) {
|
||||||
|
log_notice("Timed out");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollfd[FD_SIGNAL].revents & POLLIN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pollfd[FD_SOCKET].revents != POLLIN) {
|
||||||
|
log_error("Unexpected poll() event.");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
zero(iovec);
|
||||||
|
iovec.iov_base = passphrase;
|
||||||
|
iovec.iov_len = sizeof(passphrase)-1;
|
||||||
|
|
||||||
|
zero(control);
|
||||||
|
zero(msghdr);
|
||||||
|
msghdr.msg_iov = &iovec;
|
||||||
|
msghdr.msg_iovlen = 1;
|
||||||
|
msghdr.msg_control = &control;
|
||||||
|
msghdr.msg_controllen = sizeof(control);
|
||||||
|
|
||||||
|
if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) {
|
||||||
|
|
||||||
|
if (errno == EAGAIN ||
|
||||||
|
errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log_error("recvmsg() failed: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n <= 0) {
|
||||||
|
log_error("Message too short");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
|
||||||
|
control.cmsghdr.cmsg_level != SOL_SOCKET ||
|
||||||
|
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
|
||||||
|
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
|
||||||
|
log_warning("Received message without credentials. Ignoring.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
|
||||||
|
if (ucred->uid != 0) {
|
||||||
|
log_warning("Got request from unprivileged user. Ignoring.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passphrase[0] == '+') {
|
||||||
|
passphrase[n] = 0;
|
||||||
|
fputs(passphrase+1, stdout);
|
||||||
|
} else if (passphrase[0] == '-')
|
||||||
|
goto finish;
|
||||||
|
else {
|
||||||
|
log_error("Invalid packet");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (fd >= 0)
|
||||||
|
close_nointr_nofail(fd);
|
||||||
|
|
||||||
|
if (socket_fd >= 0)
|
||||||
|
close_nointr_nofail(socket_fd);
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
unlink(temp);
|
||||||
|
|
||||||
|
if (final[0])
|
||||||
|
unlink(final);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
|
@ -1006,6 +1006,8 @@ int main(int argc, char *argv[]) {
|
||||||
kmod_setup();
|
kmod_setup();
|
||||||
hostname_setup();
|
hostname_setup();
|
||||||
loopback_setup();
|
loopback_setup();
|
||||||
|
|
||||||
|
mkdir_p("/dev/.systemd/ask-password/", 0755);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((r = manager_new(arg_running_as, &m)) < 0) {
|
if ((r = manager_new(arg_running_as, &m)) < 0) {
|
||||||
|
|
30
src/org.freedesktop.systemd1.policy
Normal file
30
src/org.freedesktop.systemd1.policy
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
|
||||||
|
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<policyconfig>
|
||||||
|
|
||||||
|
<vendor>The systemd Project</vendor>
|
||||||
|
<vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
|
||||||
|
|
||||||
|
<action id="org.freedesktop.systemd1.ReplyPassword">
|
||||||
|
<description>Send passphrase back to system</description>
|
||||||
|
<message>Authentication is required to send the entered passphrase back to the system.</message>
|
||||||
|
<defaults>
|
||||||
|
<allow_any>no</allow_any>
|
||||||
|
<allow_inactive>no</allow_inactive>
|
||||||
|
<allow_active>auth_admin_keep</allow_active>
|
||||||
|
</defaults>
|
||||||
|
<annotate key="org.freedesktop.policykit.exec.path">/lib/systemd/systemd-reply-password</annotate>
|
||||||
|
</action>
|
||||||
|
|
||||||
|
</policyconfig>
|
108
src/reply-password.c
Normal file
108
src/reply-password.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 2010 Lennart Poettering
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
systemd is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
|
||||||
|
union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_un un;
|
||||||
|
} sa;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert(socket_name);
|
||||||
|
assert(packet);
|
||||||
|
|
||||||
|
zero(sa);
|
||||||
|
sa.un.sun_family = AF_UNIX;
|
||||||
|
strncpy(sa.un.sun_path+1, socket_name, sizeof(sa.un.sun_path)-1);
|
||||||
|
|
||||||
|
if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, sizeof(sa_family_t) + 1 + strlen(socket_name)) < 0) {
|
||||||
|
log_error("Failed to send: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int fd = -1, r = EXIT_FAILURE;
|
||||||
|
char packet[LINE_MAX];
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
|
||||||
|
log_parse_environment();
|
||||||
|
log_open();
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
log_error("Wrong number of arguments.");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(argv[1], "1")) {
|
||||||
|
|
||||||
|
packet[0] = '+';
|
||||||
|
if (!fgets(packet+1, sizeof(packet)-1, stdin)) {
|
||||||
|
log_error("Failed to read password: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncate_nl(packet+1);
|
||||||
|
length = strlen(packet+1) + 1;
|
||||||
|
} else if (streq(argv[1], "0")) {
|
||||||
|
packet[0] = '-';
|
||||||
|
length = 1;
|
||||||
|
} else {
|
||||||
|
log_error("Invalid first argument %s", argv[1]);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
|
||||||
|
log_error("socket() failed: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_on_socket(fd, argv[2], packet, length) < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (fd >= 0)
|
||||||
|
close_nointr_nofail(fd);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
|
@ -978,7 +978,7 @@ void show_error(string e) {
|
||||||
m.destroy();
|
m.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (string[] args) {
|
int main(string[] args) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm");
|
Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm");
|
||||||
|
|
Loading…
Reference in a new issue