#
# pppd makefile for Linux
-# $Id: Makefile.linux,v 1.69 2006/06/04 05:07:46 paulus Exp $
+# $Id: Makefile.linux,v 1.70 2007/06/19 02:08:34 carlsonj Exp $
#
# Default installation locations
PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \
ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \
- demand.c utils.c tty.c eap.c chap-md5.c
+ demand.c utils.c tty.c eap.c chap-md5.c session.c
-HEADERS = ccp.h chap-new.h ecp.h fsm.h ipcp.h \
+HEADERS = ccp.h session.h chap-new.h ecp.h fsm.h ipcp.h \
ipxcp.h lcp.h magic.h md5.h patchlevel.h pathnames.h pppd.h \
upap.h eap.h
MANPAGES = pppd.8
PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o md5.o ccp.o \
ecp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o tty.o \
- eap.o chap-md5.o
+ eap.o chap-md5.o session.o
#
# include dependencies if present
#
# Makefile for pppd under Solaris 2.
-# $Id: Makefile.sol2,v 1.27 2005/08/28 06:49:12 paulus Exp $
+# $Id: Makefile.sol2,v 1.28 2007/06/19 02:08:35 carlsonj Exp $
#
include ../Makedefs.com
OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap-new.o eap.o md5.o \
tty.o ccp.o ecp.o auth.o options.o demand.o utils.o sys-solaris.o \
- chap-md5.o
+ chap-md5.o session.o
#
# uncomment the following to enable plugins
#CFLAGS += -DCBCP_SUPPORT
#OBJS += cbcp.o
+# Uncomment for PAM
+#CFLAGS += -DUSE_PAM
+#LIBS += -lpam
+
#
# Make targets
#
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: auth.c,v 1.112 2006/06/18 11:26:00 paulus Exp $"
+#define RCSID "$Id: auth.c,v 1.113 2007/06/19 02:08:35 carlsonj Exp $"
#include <stdio.h>
#include <stddef.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#endif
#ifdef HAS_SHADOW
#include <shadow.h>
#include "cbcp.h"
#endif
#include "pathnames.h"
+#include "session.h"
static const char rcsid[] = RCSID;
/* Records which authentication operations have been completed. */
int auth_done[NUM_PPP];
-/* Set if we have successfully called plogin() */
-static int logged_in;
-
/* List of addresses which the peer may use. */
static struct permitted_ip *addresses[NUM_PPP];
static enum script_state auth_script_state = s_down;
static pid_t auth_script_pid = 0;
-static int used_login; /* peer authenticated against login database */
-
/*
* Option variables.
*/
bool uselogin = 0; /* Use /etc/passwd for checking PAP */
+bool session_mgmt = 0; /* Do session management (login records) */
bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
static void network_phase __P((int));
static void check_idle __P((void *));
static void connect_time_expired __P((void *));
-static int plogin __P((char *, char *, char **));
-static void plogout __P((void));
static int null_login __P((int));
static int get_pap_passwd __P((char *));
static int have_pap_secret __P((int *));
&explicit_remote, MAXNAMELEN },
{ "login", o_bool, &uselogin,
- "Use system password database for PAP", 1 },
+ "Use system password database for PAP", OPT_A2COPY | 1 ,
+ &session_mgmt },
+ { "enable-session", o_bool, &session_mgmt,
+ "Enable session accounting for remote peers", OPT_PRIV | 1 },
{ "papcrypt", o_bool, &cryptpap,
"PAP passwords are encrypted", 1 },
if (pap_logout_hook) {
pap_logout_hook();
- } else {
- if (logged_in)
- plogout();
}
+ session_end(devnam);
if (!doing_multilink) {
notice("Connection terminated.");
}
new_phase(PHASE_AUTHENTICATE);
- used_login = 0;
auth = 0;
if (go->neg_eap) {
eap_authpeer(unit, our_name);
ret = UPAP_AUTHACK;
if (uselogin || login_secret) {
/* login option or secret is @login */
- if ((ret = plogin(user, passwd, msg)) == UPAP_AUTHACK)
- used_login = 1;
+ if (session_full(user, passwd, devnam, msg) == 0) {
+ ret = UPAP_AUTHNAK;
+ }
+ } else if (session_mgmt) {
+ if (session_check(user, NULL, devnam, NULL) == 0) {
+ warn("Peer %q failed PAP Session verification", user);
+ ret = UPAP_AUTHNAK;
+ }
}
if (secret[0] != 0 && !login_secret) {
/* password given in pap-secrets - must match */
return ret;
}
-/*
- * This function is needed for PAM.
- */
-
-#ifdef USE_PAM
-/* Static variables used to communicate between the conversation function
- * and the server_login function
- */
-static char *PAM_username;
-static char *PAM_password;
-static int PAM_error = 0;
-static pam_handle_t *pamh = NULL;
-
-/* PAM conversation function
- * Here we assume (for now, at least) that echo on means login name, and
- * echo off means password.
- */
-
-static int PAM_conv (int num_msg,
-#ifndef SOL2
- const
-#endif
- struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr)
-{
- int replies = 0;
- struct pam_response *reply = NULL;
-
-#define COPY_STRING(s) (s) ? strdup(s) : NULL
-
- reply = malloc(sizeof(struct pam_response) * num_msg);
- if (!reply) return PAM_CONV_ERR;
-
- for (replies = 0; replies < num_msg; replies++) {
- switch (msg[replies]->msg_style) {
- case PAM_PROMPT_ECHO_ON:
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = COPY_STRING(PAM_username);
- /* PAM frees resp */
- break;
- case PAM_PROMPT_ECHO_OFF:
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = COPY_STRING(PAM_password);
- /* PAM frees resp */
- break;
- case PAM_TEXT_INFO:
- /* fall through */
- case PAM_ERROR_MSG:
- /* ignore it, but pam still wants a NULL response... */
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = NULL;
- break;
- default:
- /* Must be an error of some sort... */
- free (reply);
- PAM_error = 1;
- return PAM_CONV_ERR;
- }
- }
- *resp = reply;
- return PAM_SUCCESS;
-}
-
-static struct pam_conv PAM_conversation = {
- &PAM_conv,
- NULL
-};
-#endif /* USE_PAM */
-
-/*
- * plogin - Check the user name and password against the system
- * password database, and login the user if OK.
- *
- * returns:
- * UPAP_AUTHNAK: Login failed.
- * UPAP_AUTHACK: Login succeeded.
- * In either case, msg points to an appropriate message.
- */
-
-static int
-plogin(user, passwd, msg)
- char *user;
- char *passwd;
- char **msg;
-{
- char *tty;
-
-#ifdef USE_PAM
- int pam_error;
-
- pam_error = pam_start ("ppp", user, &PAM_conversation, &pamh);
- if (pam_error != PAM_SUCCESS) {
- *msg = (char *) pam_strerror (pamh, pam_error);
- reopen_log();
- return UPAP_AUTHNAK;
- }
- /*
- * Define the fields for the credential validation
- */
-
- PAM_username = user;
- PAM_password = passwd;
- PAM_error = 0;
- pam_set_item (pamh, PAM_TTY, devnam); /* this might be useful to some modules */
-
- /*
- * Validate the user
- */
- pam_error = pam_authenticate (pamh, PAM_SILENT);
- if (pam_error == PAM_SUCCESS && !PAM_error) {
- pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
- if (pam_error == PAM_SUCCESS)
- pam_error = pam_open_session (pamh, PAM_SILENT);
- }
-
- *msg = (char *) pam_strerror (pamh, pam_error);
-
- /*
- * Clean up the mess
- */
- reopen_log(); /* apparently the PAM stuff does closelog() */
- PAM_username = NULL;
- PAM_password = NULL;
- if (pam_error != PAM_SUCCESS)
- return UPAP_AUTHNAK;
-#else /* #ifdef USE_PAM */
-
-/*
- * Use the non-PAM methods directly
- */
-
-#ifdef HAS_SHADOW
- struct spwd *spwd;
- struct spwd *getspnam();
-#endif
- struct passwd *pw = getpwnam(user);
-
- endpwent();
- if (pw == NULL)
- return (UPAP_AUTHNAK);
-
-#ifdef HAS_SHADOW
- spwd = getspnam(user);
- endspent();
- if (spwd) {
- /* check the age of the password entry */
- long now = time(NULL) / 86400L;
-
- if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
- || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
- && spwd->sp_lstchg >= 0
- && now >= spwd->sp_lstchg + spwd->sp_max)) {
- warn("Password for %s has expired", user);
- return (UPAP_AUTHNAK);
- }
- pw->pw_passwd = spwd->sp_pwdp;
- }
-#endif
-
- /*
- * If no passwd, don't let them login.
- */
- if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
- || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
- return (UPAP_AUTHNAK);
-
-#endif /* #ifdef USE_PAM */
-
- /*
- * Write a wtmp entry for this user.
- */
-
- tty = devnam;
- if (strncmp(tty, "/dev/", 5) == 0)
- tty += 5;
- logwtmp(tty, user, ifname); /* Add wtmp login entry */
-
-#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
- if (pw != (struct passwd *)NULL) {
- struct lastlog ll;
- int fd;
-
- if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
- (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
- memset((void *)&ll, 0, sizeof(ll));
- (void)time(&ll.ll_time);
- (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
- (void)write(fd, (char *)&ll, sizeof(ll));
- (void)close(fd);
- }
- }
-#endif /* _PATH_LASTLOG and not USE_PAM */
-
- info("user %s logged in", user);
- logged_in = 1;
-
- return (UPAP_AUTHACK);
-}
-
-/*
- * plogout - Logout the user.
- */
-static void
-plogout()
-{
- char *tty;
-#ifdef USE_PAM
- int pam_error;
-
- if (pamh != NULL) {
- pam_error = pam_close_session (pamh, PAM_SILENT);
- pam_end (pamh, pam_error);
- pamh = NULL;
- }
- /* Apparently the pam stuff does closelog(). */
- reopen_log();
-#endif /* USE_PAM */
-
- tty = devnam;
- if (strncmp(tty, "/dev/", 5) == 0)
- tty += 5;
- logwtmp(tty, "", ""); /* Wipe out utmp logout entry */
- logged_in = 0;
-}
-
-
/*
* null_login - Check if a username of "" and a password of "" are
* acceptable, and iff so, set the list of acceptable IP addresses
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: chap-new.c,v 1.8 2005/07/13 10:41:58 paulus Exp $"
+#define RCSID "$Id: chap-new.c,v 1.9 2007/06/19 02:08:35 carlsonj Exp $"
#include <stdlib.h>
#include <string.h>
#include "pppd.h"
+#include "session.h"
#include "chap-new.h"
#include "chap-md5.h"
if (ss->flags & CHALLENGE_VALID) {
ss->flags &= ~CHALLENGE_VALID;
+ if (!(ss->flags & AUTH_DONE) && !(ss->flags & AUTH_FAILED)) {
+ /*
+ * Auth is OK, so now we need to check session restrictions
+ * to ensure everything is OK, but only if we used a
+ * plugin, and only if we're configured to check. This
+ * allows us to do PAM checks on PPP servers that
+ * authenticate against ActiveDirectory, and use AD for
+ * account info (like when using Winbind integrated with
+ * PAM).
+ */
+ if (session_mgmt &&
+ session_check(name, NULL, devnam, NULL) == 0) {
+ ss->flags |= AUTH_FAILED;
+ warn("Peer %q failed CHAP Session verification", name);
+ }
+ }
if (ss->flags & AUTH_FAILED) {
auth_peer_fail(0, PPP_CHAP);
} else {
.\" manual page [] for pppd 2.4
-.\" $Id: pppd.8,v 1.88 2006/06/16 00:01:23 paulus Exp $
+.\" $Id: pppd.8,v 1.89 2007/06/19 02:08:35 carlsonj Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
which have been set. This option is like the \fBdryrun\fR option
except that pppd proceeds as normal rather than exiting.
.TP
+.B enable-session
+Enables session accounting via PAM or wtwp/wtmpx, as appropriate.
+When PAM is enabled, the PAM "account" and "session" module stacks
+determine behavior, and are enabled for all PPP authentication
+protocols. When PAM is disabled, wtmp/wtmpx entries are recorded
+regardless of whether the peer name identifies a valid user on the
+local system, making peers visible in the last(1) log. This feature
+is automatically enabled when the pppd \fBlogin\fR option is used.
+Session accounting is disabled by default.
+.TP
.B endpoint \fI<epdisc>
Sets the endpoint discriminator sent by the local machine to the peer
during multilink negotiation to \fI<epdisc>\fR. The default is to use
Use the system password database for authenticating the peer using
PAP, and record the user in the system wtmp file. Note that the peer
must have an entry in the /etc/ppp/pap\-secrets file as well as the
-system password database to be allowed access.
+system password database to be allowed access. See also the
+\fBenable\-session\fR option.
.TP
.B maxconnect \fIn
Terminate the connection when it has been available for network
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: pppd.h,v 1.91 2005/08/25 23:59:34 paulus Exp $
+ * $Id: pppd.h,v 1.92 2007/06/19 02:08:35 carlsonj Exp $
*/
/*
extern bool auth_required; /* Peer is required to authenticate */
extern bool persist; /* Reopen link after it goes down */
extern bool uselogin; /* Use /etc/passwd for checking PAP */
+extern bool session_mgmt; /* Do session management (login records) */
extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */
extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
extern bool explicit_remote;/* remote_name specified with remotename opt */
--- /dev/null
+/*
+ * session.c - PPP session control.
+ *
+ * Copyright (c) 2007 Diego Rivera. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Derived from auth.c, which is:
+ *
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <crypt.h>
+#include "pppd.h"
+#include "session.h"
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#endif /* #ifdef USE_PAM */
+
+#define SET_MSG(var, msg) if (var != NULL) { var[0] = msg; }
+#define COPY_STRING(s) ((s) ? strdup(s) : NULL)
+
+#define SUCCESS_MSG "Session started successfully"
+#define ABORT_MSG "Session can't be started without a username"
+#define SERVICE_NAME "ppp"
+
+#define SESSION_FAILED 0
+#define SESSION_OK 1
+
+/* We have successfully started a session */
+static bool logged_in = 0;
+
+#ifdef USE_PAM
+/*
+ * Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static const char *PAM_username;
+static const char *PAM_password;
+static int PAM_session = 0;
+static pam_handle_t *pamh = NULL;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int conversation (int num_msg,
+#ifndef SOL2
+ const
+#endif
+ struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) return PAM_CONV_ERR;
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_username);
+ /* PAM frees resp */
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_password);
+ /* PAM frees resp */
+ break;
+ case PAM_TEXT_INFO:
+ /* fall through */
+ case PAM_ERROR_MSG:
+ /* ignore it, but pam still wants a NULL response... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+ default:
+ /* Must be an error of some sort... */
+ free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+static struct pam_conv pam_conv_data = {
+ &conversation,
+ NULL
+};
+#endif /* #ifdef USE_PAM */
+
+int
+session_start(flags, user, passwd, ttyName, msg)
+ const int flags;
+ const char *user;
+ const char *passwd;
+ const char *ttyName;
+ char **msg;
+{
+ bool ok = 1;
+#ifdef USE_PAM
+ const char *usr;
+ int pam_error;
+ bool try_session = 0;
+#else /* #ifdef USE_PAM */
+ struct passwd *pw;
+#ifdef HAS_SHADOW
+ struct spwd *spwd;
+ struct spwd *getspnam();
+ long now = 0;
+#endif /* #ifdef HAS_SHADOW */
+#endif /* #ifdef USE_PAM */
+
+ SET_MSG(msg, SUCCESS_MSG);
+
+ /* If no verification is requested, then simply return an OK */
+ if (!(SESS_ALL & flags)) {
+ return SESSION_OK;
+ }
+
+ if (user == NULL) {
+ SET_MSG(msg, ABORT_MSG);
+ return SESSION_FAILED;
+ }
+
+#ifdef USE_PAM
+ /* Find the '\\' in the username */
+ /* This needs to be fixed to support different username schemes */
+ if ((usr = strchr(user, '\\')) == NULL)
+ usr = user;
+ else
+ usr++;
+
+ PAM_session = 0;
+ PAM_username = usr;
+ PAM_password = passwd;
+
+ dbglog("Initializing PAM (%d) for user %s", flags, usr);
+ pam_error = pam_start (SERVICE_NAME, usr, &pam_conv_data, &pamh);
+ dbglog("---> PAM INIT Result = %d", pam_error);
+ ok = (pam_error == PAM_SUCCESS);
+
+ if (ok) {
+ ok = (pam_set_item(pamh, PAM_TTY, ttyName) == PAM_SUCCESS) &&
+ (pam_set_item(pamh, PAM_RHOST, ifname) == PAM_SUCCESS);
+ }
+
+ if (ok && (SESS_AUTH & flags)) {
+ dbglog("Attempting PAM authentication");
+ pam_error = pam_authenticate (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS) {
+ /* PAM auth was OK */
+ dbglog("PAM Authentication OK for %s", user);
+ } else {
+ /* No matter the reason, we fail because we're authenticating */
+ ok = 0;
+ if (pam_error == PAM_USER_UNKNOWN) {
+ dbglog("User unknown, failing PAM authentication");
+ SET_MSG(msg, "User unknown - cannot authenticate via PAM");
+ } else {
+ /* Any other error means authentication was bad */
+ dbglog("PAM Authentication failed: %d: %s", pam_error,
+ pam_strerror(pamh, pam_error));
+ SET_MSG(msg, (char *) pam_strerror (pamh, pam_error));
+ }
+ }
+ }
+
+ if (ok && (SESS_ACCT & flags)) {
+ dbglog("Attempting PAM account checks");
+ pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS) {
+ /*
+ * PAM account was OK, set the flag which indicates that we should
+ * try to perform the session checks.
+ */
+ try_session = 1;
+ dbglog("PAM Account OK for %s", user);
+ } else {
+ /*
+ * If the account checks fail, then we should not try to perform
+ * the session check, because they don't make sense.
+ */
+ try_session = 0;
+ if (pam_error == PAM_USER_UNKNOWN) {
+ /*
+ * We're checking the account, so it's ok to not have one
+ * because the user might come from the secrets files, or some
+ * other plugin.
+ */
+ dbglog("User unknown, ignoring PAM restrictions");
+ SET_MSG(msg, "User unknown - ignoring PAM restrictions");
+ } else {
+ /* Any other error means session is rejected */
+ ok = 0;
+ dbglog("PAM Account checks failed: %d: %s", pam_error,
+ pam_strerror(pamh, pam_error));
+ SET_MSG(msg, (char *) pam_strerror (pamh, pam_error));
+ }
+ }
+ }
+
+ if (ok && try_session && (SESS_ACCT & flags)) {
+ /* Only open a session if the user's account was found */
+ pam_error = pam_open_session (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS) {
+ dbglog("PAM Session opened for user %s", user);
+ PAM_session = 1;
+ } else {
+ dbglog("PAM Session denied for user %s", user);
+ SET_MSG(msg, (char *) pam_strerror (pamh, pam_error));
+ ok = 0;
+ }
+ }
+
+ /* This is needed because apparently the PAM stuff closes the log */
+ reopen_log();
+
+ /* If our PAM checks have already failed, then we must return a failure */
+ if (!ok) return SESSION_FAILED;
+
+#else /* #ifdef USE_PAM */
+
+/*
+ * Use the non-PAM methods directly
+ */
+
+ if ((SESS_AUTH & flags)) {
+ pw = getpwnam(user);
+
+ endpwent();
+ /*
+ * Here, we bail if we have no user account, because there is nothing
+ * to verify against.
+ */
+ if (pw == NULL)
+ return SESSION_FAILED;
+
+#ifdef HAS_SHADOW
+
+ spwd = getspnam(user);
+ endspent();
+
+ /*
+ * If there is no shadow entry for the user, then we can't verify the
+ * account.
+ */
+ if (spwd == NULL)
+ return SESSION_FAILED;
+
+ /*
+ * We check validity all the time, because if the password has expired,
+ * then clearly we should not authenticate against it (if we're being
+ * called for authentication only). Thus, in this particular instance,
+ * there is no real difference between using the AUTH, SESS or ACCT
+ * flags, or combinations thereof.
+ */
+ now = time(NULL) / 86400L;
+ if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
+ || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
+ && spwd->sp_lstchg >= 0
+ && now >= spwd->sp_lstchg + spwd->sp_max)) {
+ warn("Password for %s has expired", user);
+ return SESSION_FAILED;
+ }
+
+ /* We have a valid shadow entry, keep the password */
+ pw->pw_passwd = spwd->sp_pwdp;
+
+#endif /* #ifdef HAS_SHADOW */
+
+ /*
+ * If no passwd, don't let them login if we're authenticating.
+ */
+ if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
+ || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
+ return SESSION_FAILED;
+ }
+
+#endif /* #ifdef USE_PAM */
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+
+ if (SESS_ACCT & flags) {
+ if (strncmp(ttyName, "/dev/", 5) == 0)
+ ttyName += 5;
+ logwtmp(ttyName, user, ifname); /* Add wtmp login entry */
+ logged_in = 1;
+
+#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
+ {
+ struct lastlog ll;
+ int fd;
+
+ if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
+ (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
+ memset((void *)&ll, 0, sizeof(ll));
+ (void)time(&ll.ll_time);
+ (void)strncpy(ll.ll_line, ttyName, sizeof(ll.ll_line));
+ (void)strncpy(ll.ll_host, ifname, sizeof(ll.ll_host));
+ (void)write(fd, (char *)&ll, sizeof(ll));
+ (void)close(fd);
+ }
+ }
+#endif /* _PATH_LASTLOG and not USE_PAM */
+ info("user %s logged in on tty %s intf %s", user, ttyName, ifname);
+ }
+
+ return SESSION_OK;
+}
+
+/*
+ * session_end - Logout the user.
+ */
+void
+session_end(const char* ttyName)
+{
+#ifdef USE_PAM
+ int pam_error = PAM_SUCCESS;
+
+ if (pamh != NULL) {
+ if (PAM_session) pam_error = pam_close_session (pamh, PAM_SILENT);
+ PAM_session = 0;
+ pam_end (pamh, pam_error);
+ pamh = NULL;
+ /* Apparently the pam stuff does closelog(). */
+ reopen_log();
+ }
+#endif
+ if (logged_in) {
+ if (strncmp(ttyName, "/dev/", 5) == 0)
+ ttyName += 5;
+ logwtmp(ttyName, "", ""); /* Wipe out utmp logout entry */
+ logged_in = 0;
+ }
+}
--- /dev/null
+/*
+ * session.c - PPP session control.
+ *
+ * Copyright (c) 2007 Diego Rivera. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __SESSION_H
+#define __SESSION_H
+
+#define SESS_AUTH 1 /* Check User Authentication */
+#define SESS_ACCT 2 /* Check Account Validity */
+
+/* Convenience parameter to do the whole enchilada */
+#define SESS_ALL (SESS_AUTH | SESS_ACCT)
+
+/*
+ * int session_start(...)
+ *
+ * Start a session, performing any necessary validations.
+ *
+ * Parameters:
+ * const int flags :
+ * Any combination of the SESS_XXX flags, to indicate what the function
+ * should do as part of its checks
+ *
+ * const char* user :
+ * The username to validate. May safely be null.
+ *
+ * const char* passwd :
+ * The password to validate the user with. May safely be null.
+ *
+ * const char* tty :
+ * The TTY the user is connected on. May safely be null.
+ *
+ * char** msg :
+ * A char* to return an error or success message. This message will be returned
+ * regardless of the result. May safely be null.
+ *
+ * Return Value:
+ * Zero value for failure, non-zero value for successful session verification.
+ */
+int
+session_start(const int flags, const char* user, const char* passwd, const char* tty, char** msg);
+
+/* Added these macros for convenience... */
+#define session_auth(user, pass, tty, msg) \
+ session_start(SESS_AUTH, user, pass, tty, msg)
+
+#define session_check(user, pass, tty, msg) \
+ session_start(SESS_ACCT, user, pass, tty, msg)
+
+#define session_full(user, pass, tty, msg) \
+ session_start(SESS_ALL, user, pass, tty, msg)
+
+/*
+ * void session_end(...)
+ *
+ * End a previously-started session.
+ *
+ * Parameters:
+ * const char* tty :
+ * The TTY the user is connected on. May safely be null.
+ */
+void
+session_end(const char* tty);
+
+#endif
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: sys-solaris.c,v 1.14 2005/05/04 21:31:20 carlsonj Exp $"
+#define RCSID "$Id: sys-solaris.c,v 1.15 2007/06/19 02:08:35 carlsonj Exp $"
#include <limits.h>
#include <stdio.h>
if (name[0] != 0) {
/* logging in */
strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
- strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
+ strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host));
+ if (*host != '\0') {
+ utmpx.ut_syslen = strlen(host) + 1;
+ if (utmpx.ut_syslen > sizeof(utmpx.ut_host))
+ utmpx.ut_syslen = sizeof(utmpx.ut_host);
+ }
utmpx.ut_pid = getpid();
utmpx.ut_type = USER_PROCESS;
} else {