pam-module.c revision 92bd5ff3a062c3f9475b9d9d39b9335bfeb7705e
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <endian.h>
#include <sys/capability.h>
#include <security/pam_modules.h>
#include <security/_pam_macros.h>
#include <security/pam_modutil.h>
#include <security/pam_misc.h>
#include "util.h"
#include "audit.h"
#include "macro.h"
#include "strv.h"
#include "bus-util.h"
#include "def.h"
#include "socket-util.h"
#include "fileio.h"
#include "bus-error.h"
static int parse_argv(
const char **class,
bool *debug) {
unsigned i;
for (i = 0; i < (unsigned) argc; i++)
if (class)
if (debug)
*debug = true;
int k;
if (k < 0)
else if (debug)
*debug = k;
} else
return 0;
}
static int get_user_data(
const char **ret_username,
int r;
if (r != PAM_SUCCESS) {
return r;
}
return PAM_AUTH_ERR;
}
if (!pw) {
return PAM_USER_UNKNOWN;
}
return PAM_SUCCESS;
}
union sockaddr_union sa = {
};
socklen_t l;
int v, r;
/* We deduce the X11 socket from the display name, then use
* SO_PEERCRED to determine the X11 server process, ask for
* the controlling tty of that and if it's a VC then we know
* the seat and the virtual terminal. Sounds ugly, is only
* semi-ugly. */
r = socket_from_display(display, &p);
if (r < 0)
return r;
if (fd < 0)
return -errno;
return -errno;
l = sizeof(ucred);
if (r < 0)
return -errno;
if (r < 0)
return r;
v = vtnr_from_tty(tty);
if (v < 0)
return v;
else if (v == 0)
return -ENOENT;
if (seat)
*seat = "seat0";
return 0;
}
int flags,
const char
/* Make this a NOP on non-logind systems */
if (!logind_running())
return PAM_SUCCESS;
if (parse_argv(handle,
&debug) < 0)
return PAM_SESSION_ERR;
if (debug)
if (r != PAM_SUCCESS) {
return r;
}
/* Make sure we don't enter a loop by talking to
* systemd-logind when it is actually waiting for the
* background to finish start-up. If the service is
* "systemd-user" we simply set XDG_RUNTIME_DIR and
* leave. */
return PAM_BUF_ERR;
r = parse_env_file(p, NEWLINE,
"RUNTIME", &rt,
NULL);
if (r < 0 && r != -ENOENT)
return PAM_SESSION_ERR;
if (rt) {
if (r != PAM_SUCCESS) {
return r;
}
}
return PAM_SUCCESS;
}
/* Otherwise, we ask logind to create a session for us */
/* A tty with a colon is usually an X11 display,
* placed there to show up in utmp. We rearrange
* things and don't pretend that an X display was a
* tty. */
tty = "";
/* cron has been setting PAM_TTY to "cron" for a very
* long time and it probably shouldn't stop doing that
* for compatibility reasons. */
tty = "";
type = "unspecified";
/* ssh has been setting PAM_TTY to "ssh" for a very
* long time and probably shouldn't stop doing that
* for compatibility reasons. */
tty = "";
type ="tty";
}
/* If this fails vtnr will be 0, that's intended */
}
if (!type)
/* Talk to logind over the message bus */
r = sd_bus_open_system(&bus);
if (r < 0) {
return PAM_SESSION_ERR;
}
if (debug)
"uid=%u pid=%u service=%s type=%s class=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
r = sd_bus_call_method(bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"CreateSession",
&error,
&reply,
"uussssussbssa(sv)",
type,
vtnr,
tty,
0);
if (r < 0) {
return PAM_SYSTEM_ERR;
}
r = sd_bus_message_read(reply,
"soshusub",
&id,
&seat,
&vtnr,
&existing);
if (r < 0) {
return PAM_SESSION_ERR;
}
if (debug)
"id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u",
if (r != PAM_SUCCESS) {
return r;
}
/* Don't set $XDG_RUNTIME_DIR if the user we now
* authenticated for does not match the original user
* of the session. We do this in order not to result
* in privileged apps clobbering the runtime directory
* unnecessarily. */
if (r != PAM_SUCCESS) {
return r;
}
}
if (r != PAM_SUCCESS) {
return r;
}
}
if (vtnr > 0) {
if (r != PAM_SUCCESS) {
return r;
}
}
if (r != PAM_SUCCESS) {
return r;
}
if (session_fd >= 0) {
if (session_fd < 0) {
return PAM_SESSION_ERR;
}
if (r != PAM_SUCCESS) {
return r;
}
}
return PAM_SUCCESS;
}
int flags,
const char *id;
int r;
/* Only release session if it wasn't pre-existing when we
* tried to create it */
/* Before we go and close the FIFO we need to tell
* logind that this is a clean session shutdown, so
* that it doesn't just go and slaughter us
* immediately after closing the fd */
r = sd_bus_open_system(&bus);
if (r < 0) {
"Failed to connect to system bus: %s", strerror(-r));
r = PAM_SESSION_ERR;
goto finish;
}
r = sd_bus_call_method(bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ReleaseSession",
&error,
NULL,
"s",
id);
if (r < 0) {
r = PAM_SESSION_ERR;
goto finish;
}
}
r = PAM_SUCCESS;
if (p)
return r;
}