*/
#ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.30 1997/03/04 03:37:21 paulus Exp $";
+static char rcsid[] = "$Id: auth.c,v 1.37 1998/03/26 04:46:03 paulus Exp $";
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <utmp.h>
+#include <fcntl.h>
+#if defined(_PATH_LASTLOG) && defined(_linux_)
+#include <lastlog.h>
+#endif
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#if defined(SVR4) || defined(_linux_)
-#include <crypt.h>
-#else
-#if defined(SUNOS4) || defined(ULTRIX)
-extern char *crypt();
-#endif
-#endif
-
#ifdef USE_PAM
#include <security/pam_appl.h>
-#include <security/pam_modules.h>
#endif
#ifdef HAS_SHADOW
#include <shadow.h>
-#include <shadow/pwauth.h>
#ifndef PW_PPP
#define PW_PPP PW_LOGIN
#endif
/* Records which authentication operations haven't completed yet. */
static int auth_pending[NUM_PPP];
-/* Set if we have successfully called login() */
+/* Set if we have successfully called plogin() */
static int logged_in;
/* Set if we have run the /etc/ppp/auth-up script. */
#define CHAP_WITHPEER 4
#define CHAP_PEER 8
+extern char *crypt __P((const char *, const char *));
+
/* Prototypes for procedures local to this file. */
static void network_phase __P((int));
-static void check_idle __P((caddr_t));
-static void connect_time_expired __P((caddr_t));
-static int login __P((char *, char *, char **, int *));
-static void logout __P((void));
+static void check_idle __P((void *));
+static void connect_time_expired __P((void *));
+static int plogin __P((char *, char *, char **, int *));
+static void plogout __P((void));
static int null_login __P((int));
static int get_pap_passwd __P((char *));
static int have_pap_secret __P((void));
static void free_wordlist __P((struct wordlist *));
static void auth_script __P((char *));
static void set_allowed_addrs __P((int, struct wordlist *));
-#ifdef CBCP_SUPPORT
-static void callback_phase __P((int));
-#endif
/*
* An Open on LCP has requested a change from Dead to Establish phase.
if (phase == PHASE_DEAD)
return;
if (logged_in)
- logout();
+ plogout();
phase = PHASE_DEAD;
syslog(LOG_NOTICE, "Connection terminated.");
}
if (protp->protocol != PPP_CCP)
++num_np_open;
}
+
+ if (num_np_open == 0)
+ /* nothing to do */
+ lcp_close(0, "No network protocols running");
}
/*
namelen = sizeof(peer_authname) - 1;
BCOPY(name, peer_authname, namelen);
peer_authname[namelen] = 0;
+ script_setenv("PEERNAME", peer_authname);
/*
* If there is no more authentication still to be done,
np_up(unit, proto)
int unit, proto;
{
- if (num_np_up == 0 && idle_time_limit > 0) {
- TIMEOUT(check_idle, NULL, idle_time_limit);
+ if (num_np_up == 0) {
+ /*
+ * At this point we consider that the link has come up successfully.
+ */
+ need_holdoff = 0;
+
+ if (idle_time_limit > 0)
+ TIMEOUT(check_idle, NULL, idle_time_limit);
/*
* Set a timeout to close the connection once the maximum
*/
if (maxconnect > 0)
TIMEOUT(connect_time_expired, 0, maxconnect);
+
+ /*
+ * Detach now, if the updetach option was given.
+ */
+ if (nodetach == -1)
+ detach();
}
++num_np_up;
}
*/
static void
check_idle(arg)
- caddr_t arg;
+ void *arg;
{
struct ppp_idle idle;
time_t itime;
if (itime >= idle_time_limit) {
/* link is idle: shut it down. */
syslog(LOG_INFO, "Terminating connection due to lack of activity.");
- need_holdoff = 0;
lcp_close(0, "Link inactive");
} else {
TIMEOUT(check_idle, NULL, idle_time_limit - itime);
*/
static void
connect_time_expired(arg)
- caddr_t arg;
+ void *arg;
{
syslog(LOG_INFO, "Connect time expired");
lcp_close(0, "Connect time expired"); /* Close connection */
option_error("can't override device name when noauth option used");
exit(1);
}
- if (connector != NULL && connector_info.priv == 0
- || disconnector != NULL && disconnector_info.priv == 0
- || welcomer != NULL && welcomer_info.priv == 0) {
+ if ((connector != NULL && connector_info.priv == 0)
+ || (disconnector != NULL && disconnector_info.priv == 0)
+ || (welcomer != NULL && welcomer_info.priv == 0)) {
option_error("can't override connect, disconnect or welcome");
option_error("option values when noauth option used");
exit(1);
if (!have_chap_secret(remote_name, our_name, remote))
go->neg_chap = 0;
}
-
}
}
if (uselogin && ret == UPAP_AUTHACK) {
- ret = login(user, passwd, msg, msglen);
+ ret = plogin(user, passwd, msg, msglen);
if (ret == UPAP_AUTHNAK) {
syslog(LOG_WARNING, "PAP login failure for %s", user);
}
}
/*
- * This function is needed for PAM. However, it should not be called.
- * If it is, return the error code.
+ * This function is needed for PAM.
*/
#ifdef USE_PAM
-static int pam_conv(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr)
+static char *PAM_username = "";
+static char *PAM_password = "";
+
+#ifdef PAM_ESTABLISH_CRED /* new PAM defines :(^ */
+#define MY_PAM_STRERROR(err_code) (char *) pam_strerror(pamh,err_code)
+#else
+#define MY_PAM_STRERROR(err_code) (char *) pam_strerror(err_code)
+#endif
+
+static int pam_conv (int num_msg,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr)
{
- return PAM_CONV_ERR;
+ int count = 0, replies = 0;
+ struct pam_response *reply = NULL;
+ int size = 0;
+
+ for (count = 0; count < num_msg; count++)
+ {
+ size += sizeof (struct pam_response);
+ reply = realloc (reply, size); /* ANSI: is malloc() if reply==NULL */
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ switch (msg[count]->msg_style)
+ {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies++].resp = strdup(PAM_username); /* never NULL */
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies++].resp = strdup(PAM_password); /* never NULL */
+ break;
+
+ case PAM_TEXT_INFO:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies++].resp = NULL;
+ break;
+
+ case PAM_ERROR_MSG:
+ default:
+ free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ if (resp)
+ *resp = reply;
+ else
+ free (reply);
+
+ return PAM_SUCCESS;
}
#endif
/*
- * login - Check the user name and password against the system
+ * plogin - Check the user name and password against the system
* password database, and login the user if OK.
*
* returns:
*/
static int
-login(user, passwd, msg, msglen)
+plogin(user, passwd, msg, msglen)
char *user;
char *passwd;
char **msg;
int *msglen;
{
- char *tty;
#ifdef USE_PAM
+
struct pam_conv pam_conversation;
pam_handle_t *pamh;
int pam_error;
- char *pass;
- char *dev;
/*
* Fill the pam_conversion structure
*/
pam_conversation.conv = &pam_conv;
pam_error = pam_start ("ppp", user, &pam_conversation, &pamh);
+
if (pam_error != PAM_SUCCESS) {
- *msg = (char *) pam_strerror (pam_error);
+ *msg = MY_PAM_STRERROR (pam_error);
return UPAP_AUTHNAK;
}
/*
* Define the fields for the credintial validation
*/
- (void) pam_set_item (pamh, PAM_AUTHTOK, passwd);
- (void) pam_set_item (pamh, PAM_TTY, devnam);
+ (void) pam_set_item (pamh, PAM_TTY, devnam);
+ PAM_username = user;
+ PAM_password = passwd;
/*
* Validate the user
*/
pam_error = pam_authenticate (pamh, PAM_SILENT);
- if (pam_error == PAM_SUCCESS)
+ if (pam_error == PAM_SUCCESS) {
pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
- *msg = (char *) pam_strerror (pam_error);
+ /* start a session for this user. Session closed when link ends. */
+ if (pam_error == PAM_SUCCESS)
+ (void) pam_open_session (pamh, PAM_SILENT);
+ }
+
+ *msg = MY_PAM_STRERROR (pam_error);
+
+ PAM_username =
+ PAM_password = "";
/*
* Clean up the mess
*/
#else /* #ifdef USE_PAM */
struct passwd *pw;
- char *epasswd;
+ char *tty;
#ifdef HAS_SHADOW
struct spwd *spwd;
struct spwd *getspnam();
- extern int isexpired (struct passwd *, struct spwd *); /* in libshadow.a */
#endif
pw = getpwnam(user);
+ endpwent();
if (pw == NULL) {
return (UPAP_AUTHNAK);
}
endspent();
if (spwd) {
/* check the age of the password entry */
- if (isexpired(pw, spwd)) {
- syslog(LOG_WARNING,"Expired password for %s",user);
+ 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)) {
+ syslog(LOG_WARNING, "Password for %s has expired", user);
return (UPAP_AUTHNAK);
}
pw->pw_passwd = spwd->sp_pwdp;
|| strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
return (UPAP_AUTHNAK);
-#endif /* #ifdef USE_PAM */
-
- syslog(LOG_INFO, "user %s logged in", user);
+ /* These functions are not enabled for PAM. The reason for this is that */
+ /* there is not necessarily a "passwd" entry for this user. That is */
+ /* real purpose of 'PAM' -- to virtualize the account data from the */
+ /* application. If you want to do the same thing, write the entry in */
+ /* the 'session' hook. */
/*
* Write a wtmp entry for this user.
*/
+
tty = devnam;
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
logwtmp(tty, user, remote_name); /* Add wtmp login entry */
+
+#if defined(_PATH_LASTLOG)
+ {
+ 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
+
+#endif /* #ifdef USE_PAM */
+
+ syslog(LOG_INFO, "user %s logged in", user);
logged_in = TRUE;
return (UPAP_AUTHACK);
}
/*
- * logout - Logout the user.
+ * plogout - Logout the user.
*/
static void
-logout()
+plogout()
{
+#ifdef USE_PAM
+ struct pam_conv pam_conversation;
+ pam_handle_t *pamh;
+ int pam_error;
+/*
+ * Fill the pam_conversion structure. The PAM specification states that the
+ * session must be able to be closed by a totally different handle from which
+ * it was created. Hold the PAM group to their own specification!
+ */
+ memset (&pam_conversation, '\0', sizeof (struct pam_conv));
+ pam_conversation.conv = &pam_conv;
+
+ pam_error = pam_start ("ppp", user, &pam_conversation, &pamh);
+ if (pam_error == PAM_SUCCESS) {
+ (void) pam_set_item (pamh, PAM_TTY, devnam);
+ (void) pam_close_session (pamh, PAM_SILENT);
+ (void) pam_end (pamh, PAM_SUCCESS);
+ }
+
+#else
char *tty;
tty = devnam;
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
- logwtmp(tty, "", ""); /* Wipe out wtmp logout entry */
+ logwtmp(tty, "", ""); /* Wipe out utmp logout entry */
+#endif
+
logged_in = FALSE;
}
{
char *filename;
FILE *f;
+ int ret;
struct wordlist *addrs;
char secret[MAXWORDLEN];
if (f == NULL)
return 0;
check_access(f, filename);
- if (scan_authfile(f, user,
- remote_name[0]? remote_name: NULL,
- (u_int32_t)0, secret, NULL, filename) < 0)
+ ret = scan_authfile(f, user,
+ remote_name[0]? remote_name: NULL,
+ (u_int32_t)0, secret, NULL, filename);
+ fclose(f);
+ if (ret < 0)
return 0;
if (passwd != NULL) {
strncpy(passwd, secret, MAXSECRETLEN);
u_int32_t a;
struct hostent *hp;
- if (wo->hisaddr == 0 && *p != '!' && *p != '-'
- && strchr(p, '/') == NULL) {
+ if (*p != '!' && *p != '-' && strchr(p, '/') == NULL) {
hp = gethostbyname(p);
if (hp != NULL && hp->h_addrtype == AF_INET)
a = *(u_int32_t *)hp->h_addr;
if (ptr_mask != NULL)
*ptr_mask = '/';
- if (a == -1L)
+ if (a == (u_int32_t)-1L)
syslog (LOG_WARNING,
"unknown host %s in auth. address list",
addrs->word);