mirror of
https://github.com/systemd/systemd.git
synced 2024-11-27 12:13:33 +08:00
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-remount-api-vfs
|
||||
test-hostname
|
||||
|
49
Makefile.am
49
Makefile.am
@ -25,6 +25,7 @@ dbusinterfacedir=@dbusinterfacedir@
|
||||
udevrulesdir=@udevrulesdir@
|
||||
pamlibdir=@pamlibdir@
|
||||
pkgconfigdatadir=$(datadir)/pkgconfig
|
||||
polkitpolicydir=$(datadir)/polkit-1/actions
|
||||
|
||||
# Our own, non-special dirs
|
||||
pkgsysconfdir=$(sysconfdir)/systemd
|
||||
@ -56,14 +57,16 @@ AM_CPPFLAGS = \
|
||||
rootbin_PROGRAMS = \
|
||||
systemd \
|
||||
systemctl \
|
||||
systemd-notify
|
||||
systemd-notify \
|
||||
systemd-ask-password
|
||||
|
||||
bin_PROGRAMS = \
|
||||
systemd-cgls
|
||||
|
||||
if HAVE_GTK
|
||||
bin_PROGRAMS += \
|
||||
systemadm
|
||||
systemadm \
|
||||
systemd-ask-password-agent
|
||||
endif
|
||||
|
||||
rootlibexec_PROGRAMS = \
|
||||
@ -76,7 +79,8 @@ rootlibexec_PROGRAMS = \
|
||||
systemd-modules-load \
|
||||
systemd-remount-api-vfs \
|
||||
systemd-kmsg-syslogd \
|
||||
systemd-vconsole-setup
|
||||
systemd-vconsole-setup \
|
||||
systemd-reply-password
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
test-engine \
|
||||
@ -282,6 +286,9 @@ dist_doc_DATA = \
|
||||
pkgconfigdata_DATA = \
|
||||
systemd.pc
|
||||
|
||||
dist_polkitpolicy_DATA = \
|
||||
src/org.freedesktop.systemd1.policy
|
||||
|
||||
noinst_LTLIBRARIES = \
|
||||
libsystemd-basic.la \
|
||||
libsystemd-core.la
|
||||
@ -665,6 +672,18 @@ systemd_notify_SOURCES = \
|
||||
systemd_notify_LDADD = \
|
||||
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 = \
|
||||
src/cgls.c \
|
||||
src/cgroup-show.c \
|
||||
@ -699,6 +718,30 @@ systemadm_LDADD = \
|
||||
$(DBUSGLIB_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 = \
|
||||
src/pam-module.c \
|
||||
src/cgroup-util.c \
|
||||
|
@ -226,7 +226,7 @@ AC_SUBST(AUDIT_LIBS)
|
||||
have_gtk=no
|
||||
AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools]))
|
||||
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_SUBST(GTK_CFLAGS)
|
||||
AC_SUBST(GTK_LIBS)
|
||||
|
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
ask-password-agent.c
|
||||
systemd-interfaces.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();
|
||||
hostname_setup();
|
||||
loopback_setup();
|
||||
|
||||
mkdir_p("/dev/.systemd/ask-password/", 0755);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
int main (string[] args) {
|
||||
int main(string[] args) {
|
||||
|
||||
try {
|
||||
Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm");
|
||||
|
Loading…
Reference in New Issue
Block a user