Commit 1c3d5691 authored by David Zeuthen's avatar David Zeuthen

Lots of changes! Almost ready for 0.2 release.

parent 12d20fc8
2006-06-05 David Zeuthen <davidz@redhat.com>
Lots of changes! Almost ready for 0.2 release.
* Makefile.am:
* README:
* configure.in:
* doc/TODO:
* doc/api/polkit-docs.xml:
* doc/spec/Makefile.am:
* doc/spec/polkit-spec.html:
* doc/spec/polkit-spec.xml.in:
* libpolkit/Makefile.am:
* libpolkit/libpolkit-grant.c: (have_questions_handler),
(libpolkit_grant_provide_answers), (auth_done_handler),
(libpolkit_grant_new_context),
(libpolkit_grant_get_libpolkit_context),
(libpolkit_grant_set_questions_handler),
(libpolkit_grant_set_grant_complete_handler),
(libpolkit_grant_initiate_temporary_grant),
(libpolkit_grant_get_user_for_auth),
(libpolkit_grant_get_pam_service_for_auth),
(libpolkit_grant_close), (libpolkit_grant_free_context),
(libpolkit_grant_get_user), (libpolkit_grant_get_privilege),
(libpolkit_grant_get_resource):
* libpolkit/libpolkit-grant.h:
* libpolkit/libpolkit.c:
(libpolkit_get_allowed_resources_for_privilege_for_uid),
(libpolkit_is_uid_allowed_for_privilege):
* libpolkit/libpolkit.h:
* pam-polkit-console/Makefile.am:
* pam-polkit-console/pam-polkit-console.c: (_pam_log),
(_parse_module_args), (_is_local_xconsole), (_poke_polkitd),
(pam_sm_authenticate), (pam_sm_setcred), (pam_sm_open_session),
(pam_sm_close_session):
* polkit-interface-manager.xml:
* polkit-interface-session.xml:
* polkit.pc.in:
* polkitd/PolicyKit.in:
* polkitd/main.c: (handle_sigusr1), (sigusr1_iochn_data), (main):
* polkitd/policy.c: (txt_backend_read_policy),
(txt_backend_read_list), (txt_backend_read_word),
(policy_get_sufficient_privileges),
(policy_get_required_privileges),
(policy_get_auth_details_for_policy),
(_policy_is_uid_gid_allowed_for_policy),
(policy_is_uid_gid_allowed_for_policy),
(policy_is_uid_allowed_for_policy):
* polkitd/policy.h:
* polkitd/polkit-manager.c: (_granting_temp_priv),
(_revoking_temp_priv), (polkit_manager_error_get_type),
(bus_name_owner_changed), (polkit_manager_get_caller_info),
(_check_for_temp_privilege),
(polkit_manager_initiate_temporary_privilege_grant),
(polkit_manager_is_user_privileged),
(polkit_manager_get_allowed_resources_for_privilege),
(polkit_manager_revoke_temporary_privilege),
(polkit_manager_add_temporary_privilege),
(polkit_manager_remove_temporary_privilege),
(polkit_manager_update_desktop_console_privileges):
* polkitd/polkit-manager.h:
* polkitd/polkit-session.c: (polkit_session_close),
(polkit_session_grant_privilege_temporarily), (polkit_session_new),
(polkit_session_initiator_disconnected):
* polkitd/polkit-session.h:
* privileges/desktop-console.privilege:
* tools/Makefile.am:
* tools/polkit-grant-privilege.c: (questions_cb),
(grant_complete_cb), (main):
* tools/polkit-is-privileged.c: (usage), (main):
* tools/polkit-list-privileges.c: (main):
* tools/polkit-revoke-privilege.c: (main):
2006-04-22 David Zeuthen <davidz@redhat.com>
* tools/polkit-list-privileges.c (main): Update to new D-BUS API;
......
## Process this file with automake to produce Makefile.in
SUBDIRS = libpolkit polkitd doc tools privileges
SUBDIRS = libpolkit pam-polkit-console polkitd doc tools privileges
pamdir = $(sysconfdir)/pam.d
pam_DATA = policy-kit
......
......@@ -2,7 +2,6 @@
PolicyKit is a framework for defining policy for system-wide components and
for desktop pieces to configure it. It is used by HAL.
See also the file HACKING for notes of interest to developers working
on PolicyKit.
......
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_INIT(PolicyKit, 0.1, david@fubar.dk)
AM_INIT_AUTOMAKE(PolicyKit, 0.1)
AC_INIT(PolicyKit, 0.2, david@fubar.dk)
AM_INIT_AUTOMAKE(PolicyKit, 0.2)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
......@@ -48,7 +48,7 @@ AC_DEFINE_UNQUOTED(POLKIT_GROUP,"$POLKIT_GROUP", [Group for PolicyKit])
# Taken from dbus
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
AC_ARG_ENABLE(docbook-docs, [ --enable-docbook-docs build documentation (requires docbook2html)],enable_docbook_docs=$enableval,enable_docbook_docs=auto)
AC_ARG_ENABLE(docbook-docs, [ --enable-docbook-docs build documentation (requires xmlto)],enable_docbook_docs=$enableval,enable_docbook_docs=auto)
GTK_DOC_CHECK([1.3])
......@@ -150,7 +150,7 @@ AC_CHECK_FUNCS(getgrouplist)
# DocBook Documentation
AC_PATH_PROG(DOCBOOK, docbook2html, no)
AC_PATH_PROG(XMLTO, xmlto, no)
AC_MSG_CHECKING([whether to build DocBook documentation])
......@@ -347,6 +347,7 @@ AC_OUTPUT([
policy-kit
polkit.pc
Makefile
pam-polkit-console/Makefile
polkitd/Makefile
polkitd/PolicyKit
polkitd/PolicyKit.conf
......
TODO
DONE
- Write up a nice spec about how all this works since it can be a bit
confusing
- Refine the .privilege file format so e.g. user 'foo' is always
allowed to grant privilege 'bar' to other users. Also other stuff.
- write polkit-revoke-privilege
- make polkit-list-privileges and polkit-is-privileged display if a
privilege is granted permanently or temporary. Also display if it's
confined to a certain D-BUS connection.
- Factor out auth code in polkit-is-privileged into a GObject and put
it in a libpolkit-gobject library (since the interaction is pretty
hairy (see interaction diagram in polkitd/polkit-session.c) I will
not put this in libpolkit as I want to use the glib bindings and
these require the glib main loop => not suitable for Qt etc.)
PENDING
- Make polkitd emit signals on an interface such that privileged apps
can be notified when privileges are granted and revoked. Also
export other useful query operations.
- make D-BUS interface in general and polkit-grant-privilege in
particular capable of granting privs permanently
- write some man pages
- write libpolkit-gnome that GNOME apps can consume
- implement D-BUS interfaces suitable for a GUI privilege editor
- write more tests; audit code
......@@ -7,8 +7,9 @@
</bookinfo>
<chapter>
<title>Client library</title>
<title>Client libraries</title>
<xi:include href="xml/libpolkit.xml"/>
<xi:include href="xml/libpolkit-grant.xml"/>
</chapter>
</book>
......@@ -9,7 +9,7 @@ htmldocdir = $(DOCDIR)/spec
htmldoc_DATA = polkit-spec.html $(FIGURE_FILES)
polkit-spec.html : polkit-spec.xml $(FIGURE_FILES)
$(DOCBOOK) --nochunks polkit-spec.xml -o .
$(XMLTO) html-nochunks polkit-spec.xml
clean-local:
rm -f *~
......
This diff is collapsed.
This diff is collapsed.
......@@ -12,7 +12,7 @@ INCLUDES = \
@GLIB_CFLAGS@ \
@DBUS_GLIB_CFLAGS@
lib_LTLIBRARIES=libpolkit.la
lib_LTLIBRARIES=libpolkit.la libpolkit-grant.la
libpolkitincludedir=$(includedir)/libpolkit
......@@ -26,6 +26,29 @@ libpolkit_la_LIBADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@
libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libpolkit_grantincludedir=$(includedir)/libpolkit
libpolkit_grantinclude_HEADERS = \
libpolkit-grant.h
libpolkit_grant_la_SOURCES = \
libpolkit-grant.c libpolkit-grant.h \
polkit-interface-manager-glue.h \
polkit-interface-session-glue.h
libpolkit_grant_la_LIBADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@
libpolkit_grant_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am
dbus-binding-tool --prefix=polkit_manager --mode=glib-client --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml
polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am
dbus-binding-tool --prefix=polkit_session --mode=glib-client --output=polkit-interface-session-glue.h ../polkit-interface-session.xml
BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h
clean-local :
rm -f *~
rm -f *~ $(BUILT_SOURCES)
This diff is collapsed.
/***************************************************************************
*
* libpolkit-grant.h : Wraps temporary grant methods on the PolicyKit daemon
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
* Licensed under the Academic Free License version 2.1
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifndef LIBPOLKIT_GRANT_H
#define LIBPOLKIT_GRANT_H
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <libpolkit/libpolkit.h>
struct LibPolKitGrantContext_s;
typedef struct LibPolKitGrantContext_s LibPolKitGrantContext;
/**
* LibPolKitGrantQuestions:
* @ctx: Context
* @questions: NULL terminated series of pairs. Each pair represent one question.
* @user_data: User data
*
* Callback when information is needed from the user in order to
* authenticate.
*
* The first component of the each pair in the questions array denote
* the question type. It can assume the values "PamPromptEchoOff"
* (meaning prompt for answer but don't echo it on the screen as the
* user types it), "PamPromptEchoOn" (meaning prompt for answer and
* echo the answer on the screen as the user types it), "PamErrorMsg"
* (display the message as an error message to the user) and
* "PamTextInfo" (textual information to the user). The second
* component in the pair is the actual question or information
* (e.g. "Password:") and it should be shown to the user next to the
* text input box.
*
* The callee should call libpolkit_grant_provide_answers with a
* string array once it the answers have been obtained from the user.
*
*/
typedef void (*LibPolKitGrantQuestions) (LibPolKitGrantContext *ctx,
const char **questions,
gpointer user_data);
/**
* LibPolKitGrantComplete:
* @obtained_privilege: Whether the user sucessfully authenticated
* and was granted the privilege.
* @reason_not_obtained: If the user did not obtain the privilege
* this is the reason. May be NULL.
* @user_data: User data
*
* Callback when authorization was complete or there was an error.
*
*/
typedef void (*LibPolKitGrantComplete) (LibPolKitGrantContext *ctx,
gboolean obtained_privilege,
const char *reason_not_obtained,
gpointer user_data);
LibPolKitGrantContext* libpolkit_grant_new_context (DBusGConnection *dbus_g_connection,
const char *user,
const char *privilege,
const char *resource,
gboolean restrict_to_dbus_connection,
gpointer user_data);
const char* libpolkit_grant_get_user (LibPolKitGrantContext *ctx);
const char* libpolkit_grant_get_privilege (LibPolKitGrantContext *ctx);
const char* libpolkit_grant_get_resource (LibPolKitGrantContext *ctx);
LibPolKitContext* libpolkit_grant_get_libpolkit_context (LibPolKitGrantContext *ctx);
void libpolkit_grant_set_questions_handler (LibPolKitGrantContext *ctx,
LibPolKitGrantQuestions questions_handler);
void libpolkit_grant_set_grant_complete_handler (LibPolKitGrantContext *ctx,
LibPolKitGrantComplete grant_complete_handler);
gboolean libpolkit_grant_initiate_temporary_grant (LibPolKitGrantContext *ctx);
const char* libpolkit_grant_get_user_for_auth (LibPolKitGrantContext *ctx);
const char* libpolkit_grant_get_pam_service_for_auth (LibPolKitGrantContext *ctx);
void libpolkit_grant_provide_answers (LibPolKitGrantContext *ctx,
const char **answers);
gboolean libpolkit_grant_close (LibPolKitGrantContext *ctx,
gboolean revoke_privilege);
void libpolkit_grant_free_context (LibPolKitGrantContext *ctx);
#endif /* LIBPOLKIT_GRANT_H */
......@@ -54,8 +54,8 @@
return _ret_; \
} \
if (_ctx_->magic != LIBPOLKIT_MAGIC) { \
g_warning ("%s: given LibPolKitContext is invalid", \
__FUNCTION__); \
g_warning ("%s: given LibPolKitContext is invalid (read magic 0x%08x, should be 0x%08x)", \
__FUNCTION__, _ctx_->magic, LIBPOLKIT_MAGIC); \
return _ret_; \
} \
} while(0)
......@@ -102,7 +102,8 @@ LibPolKitResult
libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
const char *user,
const char *privilege,
GList **result,
GList **resources,
GList **restrictions,
int *num_non_temporary)
{
LibPolKitResult res;
......@@ -111,12 +112,15 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
DBusError error;
char **resource_list;
int num_resources;
char **restriction_list;
int num_restrictions;
int i;
LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
res = LIBPOLKIT_RESULT_ERROR;
*result = NULL;
*resources = NULL;
*restrictions = NULL;
message = dbus_message_new_method_call ("org.freedesktop.PolicyKit",
"/org/freedesktop/PolicyKit/Manager",
......@@ -149,6 +153,7 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
if (!dbus_message_get_args (reply, &error,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &resource_list, &num_resources,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &restriction_list, &num_restrictions,
DBUS_TYPE_INT32, num_non_temporary,
DBUS_TYPE_INVALID)) {
g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message);
......@@ -157,10 +162,15 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
}
for (i = 0; i < num_resources; i++) {
*result = g_list_append (*result, g_strdup (resource_list[i]));
*resources = g_list_append (*resources, g_strdup (resource_list[i]));
}
dbus_free_string_array (resource_list);
for (i = 0; i < num_restrictions; i++) {
*restrictions = g_list_append (*restrictions, g_strdup (restriction_list[i]));
}
dbus_free_string_array (restriction_list);
res = LIBPOLKIT_RESULT_OK;
out:
......@@ -172,25 +182,28 @@ out:
}
LibPolKitResult
libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
pid_t pid,
const char *user,
const char *privilege,
const char *resource,
gboolean *is_allowed,
gboolean *is_temporary)
libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
const char *system_bus_unique_name,
const char *user,
const char *privilege,
const char *resource,
gboolean *out_is_allowed,
gboolean *out_is_temporary,
char **out_is_privileged_but_restricted_to_system_bus_unique_name)
{
LibPolKitResult res;
DBusMessage *message = NULL;
DBusMessage *reply = NULL;
DBusError error;
const char *myresource = "";
const char *mysystem_bus_unique_name = "";
char *but_restricted_to = NULL;
LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
res = LIBPOLKIT_RESULT_ERROR;
*is_allowed = FALSE;
*is_temporary = FALSE;
*out_is_allowed = FALSE;
*out_is_temporary = FALSE;
message = dbus_message_new_method_call ("org.freedesktop.PolicyKit",
"/org/freedesktop/PolicyKit/Manager",
......@@ -204,8 +217,11 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
if (resource != NULL)
myresource = resource;
if (system_bus_unique_name != NULL)
mysystem_bus_unique_name = system_bus_unique_name;
if (!dbus_message_append_args (message,
DBUS_TYPE_INT32, &pid,
DBUS_TYPE_STRING, &mysystem_bus_unique_name,
DBUS_TYPE_STRING, &user,
DBUS_TYPE_STRING, &privilege,
DBUS_TYPE_STRING, &myresource,
......@@ -232,14 +248,24 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
if (!dbus_message_get_args (reply, &error,
DBUS_TYPE_BOOLEAN, is_allowed,
DBUS_TYPE_BOOLEAN, is_temporary,
DBUS_TYPE_BOOLEAN, out_is_allowed,
DBUS_TYPE_BOOLEAN, out_is_temporary,
DBUS_TYPE_STRING, &but_restricted_to,
DBUS_TYPE_INVALID)) {
g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message);
dbus_error_free (&error);
goto out;
}
if (out_is_privileged_but_restricted_to_system_bus_unique_name != NULL) {
if (but_restricted_to != NULL && strlen (but_restricted_to) > 0) {
*out_is_privileged_but_restricted_to_system_bus_unique_name = strdup (but_restricted_to);
} else {
*out_is_privileged_but_restricted_to_system_bus_unique_name = NULL;
}
//dbus_free (but_restricted_to);
}
res = LIBPOLKIT_RESULT_OK;
out:
......
......@@ -51,12 +51,13 @@ LibPolKitResult libpolkit_get_privilege_list (LibPolKit
GList **result);
LibPolKitResult libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
pid_t pid,
const char *system_bus_unique_name,
const char *user,
const char *privilege,
const char *resource,
gboolean *is_allowed,
gboolean *is_temporary);
gboolean *out_is_allowed,
gboolean *out_is_temporary,
char **out_is_privileged_but_restricted_to_system_bus_unique_name);
LibPolKitResult libpolkit_revoke_temporary_privilege (LibPolKitContext *ctx,
const char *user,
......@@ -67,7 +68,8 @@ LibPolKitResult libpolkit_revoke_temporary_privilege (LibPolKit
LibPolKitResult libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
const char *user,
const char *privilege,
GList **result,
GList **resources,
GList **restrictions,
int *num_non_temporary);
#endif /* LIBPOLKIT_H */
......
LOCKDIR = $(localstatedir)/run/polkit-console
LOCKDIRMODE = 0700
securelibdir = /lib/security
securelib_LTLIBRARIES = pam_polkit_console.la
pam_polkit_console_la_LDFLAGS = -no-undefined -avoid-version -module
pam_polkit_console_la_LIBADD = -lpam
pam_polkit_console_la_CFLAGS = -DLOCKDIR=\"$(LOCKDIR)\"
pam_polkit_console_la_SOURCES = pam-polkit-console.c
clean-local :
rm -f *~
install-data-local:
mkdir -m $(LOCKDIRMODE) -p $(DESTDIR)$(LOCKDIR)
/***************************************************************************
* CVSID: $Id$
*
* pam-polkit-console.c : Maintain files in /var/run/polkit-console to
* maintain a list of what users are logged in at
* what console
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#include <config.h>
#include <errno.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <security/pam_modules.h>
#include <security/_pam_macros.h>
#include <security/pam_modutil.h>
#include <security/pam_ext.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
static int debug = 0;
static void
_pam_log (pam_handle_t *pamh,
int err,
int debug_noforce,
const char *format, ...)
{
va_list args;
if (debug_noforce && !debug)
return;
va_start (args, format);
pam_vsyslog (pamh, err, format, args);
closelog ();
}
static void
_parse_module_args (pam_handle_t *pamh,
int argc,
const char **argv)
{
int i;
for (i = 0; i < argc; i++) {
const char *arg;
arg = argv[i];
if (strcmp (arg,"debug") == 0) {
debug = 1;
} else {
_pam_log(pamh, LOG_ERR, FALSE,
"_parse_module_args: unknown option; %s", arg);
}
}
}
static int
_is_local_xconsole (const char *tty)
{
int a, b;
if (sscanf (tty, ":%d.%d", &a, &b) == 2)
return TRUE;
else if (sscanf (tty, ":%d", &a) == 1)
return TRUE;
else
return FALSE;
}
static void
_poke_polkitd (pam_handle_t *pamh)
{
char buf[80];
/* This is a PAM module so we're loaded into the address space
* of some other process (e.g. gdm) - though it's tempting to
* use D-BUS to poke the PolicyKit daemon it may, just resort to
* using oldskool SIGUSR1 instead.
*/
FILE *f;
f = fopen (POLKITD_PID_FILE, "r");
if (f != NULL) {
if (fgets (buf, sizeof (buf), f) != NULL && buf[0] != '\0' && buf[0] != '\n') {
pid_t pid;
char *p;
pid = strtol (buf, &p, 10);
if ((*p == '\0') || (*p == '\n'))
{
_pam_log (pamh, LOG_DEBUG, TRUE,
"Sending SIGUSR1 to polkitd with pid %d to reload configuration", pid);
kill (pid, SIGUSR1);
}
}
fclose (f);
}
}
PAM_EXTERN int
pam_sm_authenticate (pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
return PAM_AUTH_ERR;
}
PAM_EXTERN int
pam_sm_setcred (pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int
pam_sm_open_session (pam_handle_t *pamh,
int flags,
int argc,