summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2000-11-21 00:51:17 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2000-11-21 00:51:17 +0000
commitc25d006191bf9cf74c82ae3be8ad115399fcbe1e (patch)
tree0f857919115e6030f35d449e79c4ec3d970fa161
parent39e1c13e015b28253d0476c700d747595db651f6 (diff)
BSD authentication routines from BSDI. Presently this is not used but
the login_* helper programs and other support will be committed in the near future.
-rw-r--r--include/bsd_auth.h87
-rw-r--r--include/login_cap.h4
-rw-r--r--lib/libc/gen/auth_subr.3461
-rw-r--r--lib/libc/gen/auth_subr.c986
-rw-r--r--lib/libc/gen/authenticate.3275
-rw-r--r--lib/libc/gen/authenticate.c478
6 files changed, 2289 insertions, 2 deletions
diff --git a/include/bsd_auth.h b/include/bsd_auth.h
new file mode 100644
index 00000000000..be294455294
--- /dev/null
+++ b/include/bsd_auth.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software Design,
+ * Inc.
+ * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI $From: bsd_auth.h,v 2.3 1999/09/08 22:13:08 prb Exp $
+ */
+
+typedef struct auth_session_t auth_session_t;
+
+typedef enum {
+ AUTHV_ALL,
+ AUTHV_CHALLENGE,
+ AUTHV_CLASS,
+ AUTHV_NAME,
+ AUTHV_SERVICE,
+ AUTHV_STYLE,
+ AUTHV_INTERACTIVE
+} auth_item_t;
+
+char * auth_getitem(auth_session_t *, auth_item_t);
+int auth_setitem(auth_session_t *, auth_item_t, char *);
+
+auth_session_t *auth_open();
+auth_session_t *auth_verify(auth_session_t *, char *, char *, ...);
+auth_session_t *auth_userchallenge(char *, char *, char *, char **);
+auth_session_t *auth_usercheck(char *, char *, char *, char *);
+
+int auth_userresponse(auth_session_t *, char *, int);
+int auth_userokay(char *, char *, char *, char *);
+int auth_approval(auth_session_t *, login_cap_t *, char *, char *);
+
+int auth_close(auth_session_t *);
+void auth_clean(auth_session_t *);
+
+char * auth_getvalue(auth_session_t *, char *);
+int auth_getstate(auth_session_t *);
+char * auth_challenge(auth_session_t *);
+void auth_setenv(auth_session_t *);
+void auth_clrenv(auth_session_t *);
+
+void auth_setstate(auth_session_t *, int);
+int auth_call(auth_session_t *, char *, ...);
+
+int auth_setdata(auth_session_t *, void *, size_t);
+int auth_setoption(auth_session_t *, char *, char *);
+int auth_setpwd(auth_session_t *, struct passwd *pwd);
+void auth_set_va_list(auth_session_t *, _BSD_VA_LIST_);
+
+struct passwd *auth_getpwd(auth_session_t *);
+
+quad_t auth_check_expire(auth_session_t *);
+quad_t auth_check_change(auth_session_t *);
+
+void auth_clroptions(auth_session_t *);
+void auth_clroption(auth_session_t *, char *);
+
+
+char * auth_mkvalue(char *);
+void auth_checknologin(login_cap_t *);
+int auth_cat(char *);
diff --git a/include/login_cap.h b/include/login_cap.h
index cacf9200c72..896e95ce524 100644
--- a/include/login_cap.h
+++ b/include/login_cap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: login_cap.h,v 1.2 2000/11/19 20:12:10 millert Exp $ */
+/* $OpenBSD: login_cap.h,v 1.3 2000/11/21 00:51:16 millert Exp $ */
/*-
* Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved.
@@ -35,7 +35,7 @@
*/
#define LOGIN_DEFCLASS "default"
-#define LOGIN_DEFSTYLE "passwd"
+#define LOGIN_DEFSTYLE "krb-or-pwd"
#define LOGIN_DEFSERVICE "login"
#define LOGIN_DEFUMASK 022
#define _PATH_LOGIN_CONF "/etc/login.conf"
diff --git a/lib/libc/gen/auth_subr.3 b/lib/libc/gen/auth_subr.3
new file mode 100644
index 00000000000..7df98cef99d
--- /dev/null
+++ b/lib/libc/gen/auth_subr.3
@@ -0,0 +1,461 @@
+.\" $OpenBSD: auth_subr.3,v 1.1 2000/11/21 00:51:16 millert Exp $
+.\"
+.\" Copyright (c) 1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Berkeley Software Design,
+.\" Inc.
+.\" 4. The name of Berkeley Software Design, Inc. may not be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" BSDI $From: auth_subr.3,v 2.5 2000/03/30 19:11:27 polk Exp $
+.Dd March 20, 1997
+.Dt BSD_AUTH 3
+.Os
+.Sh NAME
+.Nm auth_open ,
+.Nm auth_call ,
+.Nm auth_challenge ,
+.Nm auth_check_change ,
+.Nm auth_check_expire ,
+.Nm auth_clean ,
+.Nm auth_close ,
+.Nm auth_clrenv ,
+.Nm auth_clroption ,
+.Nm auth_clroptions ,
+.Nm auth_getitem
+.Nm auth_getstate ,
+.Nm auth_getvalue ,
+.Nm auth_set_va_list ,
+.Nm auth_setdata ,
+.Nm auth_setenv ,
+.Nm auth_setitem
+.Nm auth_setoption ,
+.Nm auth_setpwd ,
+.Nm auth_setstate
+.Nd interface to the BSD Authentication system
+.Sh SYNOPSIS
+.Fd #include <login_cap.h>
+.Fd #include <bsd_auth.h>
+.Ft auth_session_t *
+.Fn auth_open
+.Ft int
+.Fn auth_close "auth_session_t *as"
+.Ft int
+.Fn auth_call "auth_session_t *as" "char *path" "..."
+.Ft char *
+.Fn auth_challenge "auth_session_t *as"
+.Ft quad_t
+.Fn auth_check_change "auth_session_t *as"
+.Ft quad_t
+.Fn auth_check_expire "auth_session_t *as"
+.Ft void
+.Fn auth_clean "auth_session_t *as"
+.Ft void
+.Fn auth_clrenv "auth_session_t *as"
+.Ft void
+.Fn auth_clroption "auth_session_t * as" "char *name"
+.Ft void
+.Fn auth_clroptions "auth_session_t *as"
+.Ft char *
+.Fn auth_getitem "auth_session_t *as" "auth_item_t item"
+.Ft int
+.Fn auth_getstate "auth_session_t *as"
+.Ft char *
+.Fn auth_getvalue "auth_session_t *as" "char *what"
+.Ft void
+.Fn auth_set_va_list "auth_session_t *as" "va_list ap"
+.Ft int
+.Fn auth_setdata "auth_session_t *as" "void *ptr" "size_t len"
+.Ft void
+.Fn auth_setenv "auth_session_t *as"
+.Ft int
+.Fn auth_setitem "auth_session_t *as" "auth_item_t item" "char *value"
+.Ft int
+.Fn auth_setoption "auth_session_t *as" "char *name" "char *value"
+.Ft int
+.Fn auth_setpwd "auth_session_t *as" "struct passwd *pwd"
+.Ft int
+.Fn auth_setstate "auth_session_t *as" "int state"
+.Sh DESCRIPTION
+These functions provide the lower level interface to the BSD
+Authentication system. They all operate on a BSD Authentication
+session pointer,
+.Fa as ,
+which is returned by
+.Fn auth_open .
+The session pointer
+must be passed to all other BSD Authentication functions called.
+The
+.Fn auth_open
+function returns
+.Nm NULL
+if it was unable to allocate memory for the session.
+The session is terminated by the
+.Fn auth_close
+function,
+which also sets any environment variables requested by the login script
+(assuming the user was not rejected) or removes files created by the
+login script if the authentication was not successful.
+It returns the final state of the authentication request. A return
+value of 0 implies the user was not authenticated. A non-zero return
+value is made up the 1 or more of the following values ORed together:
+.Bl -tag -width AUTH_ROOTOKAYXX
+.It Li AUTH_OKAY
+The user was authenticated.
+.It Li AUTH_ROOTOKAY
+The user was authenticated with a root instance.
+.It Li AUTH_SECURE
+The user was authenticated via a mechanism which is not subject to
+eavesdropping attacks (such as provided by token cards).
+.El
+.sp
+The full state of the session is returned by the
+.Fn auth_getstate
+function.
+In addition to the values above, it also may contain the bits:
+.Bl -tag -width AUTH_ROOTOKAYXX
+.It Li AUTH_SILENT
+Do not report an error, the user was not authenticated for access and
+was not expected to be. This is returned by login scripts that allow
+changing of the users password, for instance.
+This value is stripped off for normal returns.
+.It Li AUTH_CHALLENGE
+The user was not authenticated for access and a challenge was issued.
+The challenge should be displayed to the user, a response retrieved,
+and the result verified.
+This value is stripped off for normal returns.
+.It Li AUTH_EXPIRED
+The user's account has expired.
+.It Li AUTH_PWEXPIRED
+The user's password has expired and needs to be changed.
+.El
+.sp
+A session may be cleaned
+by calling
+.Fn auth_clean .
+This function causes any files created by a login script in this
+session and clears all state associated with this session.
+It is not necessary to call
+.Fn auth_clean
+if
+.Fn auth_close
+is called.
+.sp
+The remaining functions are described in alphabetical order.
+.sp
+The fundamental function for doing BSD Authentication is
+.Fn auth_call .
+In addition to the pointer to the BSD Authentication session, it takes
+the following parameters:
+.Bl -tag -width indent
+.It Ar path
+The full path name of the login script to run. The call will fail if
+.Ar path
+does not pass the requirements of the
+.Xr secure_path 3
+function.
+.It Ar ...
+The remaining arguments, which should be of type
+.Ft char *
+and terminated with a
+.Ev NULL
+are passed to the login script at the end of the command line.
+.El
+.Pp
+The
+.Fn auth_call
+function,
+after verifying the
+.Ar path ,
+creates a bi-directional pipe (socketpair) which is located on
+file descriptor 3 for the child (the login script). This is
+known as the
+.Dq back channel .
+The actual command line passed to the child is made up of
+3 parts.
+The parameters passed to
+.Fn auth_call
+following
+.Ar path
+have appended to them any arguments specified by the
+.Fn auth_set_va_list
+function.
+These are typically the variable arguments passed to the function
+that calls
+.Fn auth_call .
+Any option values set by the
+.Fn auth_setoption
+function are inserted between the first argument (the command
+name) and the second argument with a preceeding
+.Fl v
+flag.
+The name and value are separated by an
+.Sq = :
+.sp
+.Li Ta Fl v Ar name=value
+
+.sp
+Once the login script has been spawned, any data specified by the
+.Fn auth_setdata
+is written to the back channel. Multiple blocks of data may have
+been specified and they will be sent in the same order they were
+specified. As the data is sent, the storage for the data is
+zeroed out and then freed (the data is zeroed out since it may
+contain sensitive information, such as a password).
+Once any data is written out,
+.Fn auth_call
+reads up to 8192 bytes of data from the back channel. The
+state of the session is determined from this data
+(see
+.Xr login.conf 5
+for details).
+If the login script exits with a 0 and does not specify any return state
+on the back channel, the state prior to the call to
+.Fn auth_call
+is retained.
+.sp
+The data read from the back channel is also used by the
+.Fn auth_getvalue
+and
+.Fn auth_close
+functions.
+Subsequent calls to
+.Fn auth_call
+will cause this data to be lost and overwritten with the new data read
+from the new call.
+.sp
+The environment passed to the login script by
+.Fn auth_call
+only contains two values:
+.Ev PATH
+and
+.Ev SHELL .
+The
+.Ev PATH
+is set to the default path (
+.Pa /bin
+and
+.Pa /usr/bin )
+while the
+.Ev SHELL
+is set to the default system shell (
+.Pa /bin/sh ) .
+.sp
+The
+.Fn auth_challenge
+function queries the login script defined by the current
+.Ar style
+for a challenge for the user specified by
+.Ar name .
+(See below for the setting of the
+.Ar style
+and
+.Ar name ) .
+It internally uses the
+.Fn auth_call
+function.
+The generated challenge is returned.
+.Nm NULL
+is returned on error or if no challenge was generated.
+The challenge can also be extracted by the
+.Fn auth_getchallenge
+function, which simply returns the last challenge generated
+for this session.
+.sp
+The
+.Fn auth_check_change
+and
+.Fn auth_check_expire
+functions check the password expiration (change) and account expiration
+times.
+They return 0 if no change or expiration time is set for the account.
+They return a negative value of how many seconds have passed since
+the password or account expired. In this case the state of the
+session is marked with either
+.Li AUTH_PWEXPIRED
+or
+.Li AUTH_EXPIRED
+as well as clearing any bits which would indicate the authentication was
+successful.
+If the password or account has not expired they return the number of
+seconds left until the account does expire.
+The return value of -1 can either indicate the password or account
+just expired or that no password entry was set for the current session.
+.sp
+The
+.Fn auth_clrenv
+function clears any requests set by a login script for
+environment variables to be set.
+.sp
+The
+.Fn auth_clroption
+function clears the previously set option
+.Fa name .
+.sp
+The
+.Fn auth_clroptions
+function clears all previously set options.
+.sp
+The
+.Fn auth_getitem
+function returns the value of of
+.Fa item .
+The
+.Fa item
+may be one of:
+.Bl -tag -width AUTH_ROOTOKAYXX
+.It Li AUTH_CHALLENGE
+The latest challenge, if any, set for the session.
+.It Li AUTH_CLASS
+The class of the user, as defined by the
+.Pa /etc/login.conf
+file.
+This value is not directly used by BSD Authentication, rather, it is
+passed to the login scripts for their possible use.
+.It Li AUTH_INTERACTIVE
+If set to any value then the session is tagged as interactive. If
+not set the session is not interactive. When the value is requested
+it is always either
+.Nm NULL
+or
+.Dq True .
+The auth subroutines may choose to provide additional information to
+standard output or standard error when the session is interactive.
+There is no functional change in the operation of the subroutines.
+.It Li AUTH_NAME
+The name of the user being authenticated.
+The name should include the instance, if any, that is being requested.
+.It Li AUTH_SERVICE
+The service requesting the authentication.
+Initially it is set to the default service which provides the traditional
+interactive service.
+.It Li AUTH_STYLE
+The style of authentication being performed, as defined by the
+.Pa /etc/login.conf file.
+The style determines which login script should actually be used.
+.El
+.sp
+The
+.Fn auth_getvalue
+function returns the value, if any, associated with the specified internal
+variable
+.Ar what.
+These variables are set by login scripts.
+When a new login script is run
+(by the
+.Fn auth_call function)
+the values from the previous login script are lost.
+(See
+.Xr login.conf 5
+for details on internal variables.)
+.sp
+The
+.Fn auth_set_va_list
+function establishes a variable argument list to be used by the
+.Fn auth_call
+function.
+It is intended to be used by functions which need to call
+.Fn auth_call
+but take a variable number of arguments themselves.
+Since the arguments are not copied, the call to
+.Fn auth_call
+must be placed within the scope of
+.Fa ap .
+The
+.Fn auth_call
+function will call
+.Xr va_end 3
+on
+.Fa ap .
+.sp
+The
+.Fn auth_setdata
+function
+makes a copy of
+.Fa len
+bytes of data pointed to by
+.Fa ptr
+for use by
+.Fn auth_call .
+The data will be passed on the back channel to the next login script called.
+.sp
+The
+.Fn auth_setenv
+function adds/deletes any environment variables requested by the
+login script to the current environment.
+.sp
+The
+.Fn auth_setitem
+function assigns
+.Fa value
+to the specified
+.Fa item .
+The items are described above with the
+.Fn auth_getitem
+function.
+In addition, if
+.Fa item
+is
+.Li AUTH_ALL
+and
+.Fa value
+is
+.Li NULL
+then all items are cleared.
+.sp
+The
+.Fn auth_setoption
+function requests that the option
+.Fa name
+be set with the value of
+.Fa value
+when a script is executed by
+.Fn auth_call .
+The actual arguments to the script will be placed at the beginning
+of the argument vector. For each option two arguments will be
+issued:
+.Li -v name=value .
+.sp
+The function
+.Fn auth_setpwd
+establishes the password file entry for the authentication session.
+If the name has already been set by
+.Fn auth_setitem
+then the
+.Fa pwd
+argument may be NULL, else it must be the password entry to use.
+.sp
+The function
+.Fn auth_setstate
+sets the sessions state to
+.Fa state.
+Typically this is either
+.Li AUTH_OKAY
+or 0.
+.Sh SEE ALSO
+.Xr authenticate 3 ,
+.Xr login_cap 3 ,
+.Xr login.conf 5
diff --git a/lib/libc/gen/auth_subr.c b/lib/libc/gen/auth_subr.c
new file mode 100644
index 00000000000..3fd98adb151
--- /dev/null
+++ b/lib/libc/gen/auth_subr.c
@@ -0,0 +1,986 @@
+/* $OpenBSD: auth_subr.c,v 1.1 2000/11/21 00:51:16 millert Exp $ */
+
+/*-
+ * Copyright (c) 1995,1996,1997 Berkeley Software Design, Inc.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software Design,
+ * Inc.
+ * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI $From: auth_subr.c,v 2.4 1999/09/08 04:10:40 prb Exp $
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <login_cap.h>
+
+#define MAXSPOOLSIZE (8*1024) /* Spool up to 8K of back info */
+
+struct rmfiles {
+ struct rmfiles *next;
+ char *file;
+};
+
+struct authopts {
+ struct authopts *next;
+ char *opt;
+};
+
+struct authdata {
+ struct authdata *next;
+ void *ptr;
+ size_t len;
+};
+
+struct auth_session_t {
+ char *name; /* name of use being authenticated */
+ char *style; /* style of authentication used */
+ char *class; /* class of user */
+ char *service; /* type of service being performed */
+ char *challenge; /* last challenge issued */
+ int flags; /* see below */
+ struct passwd *pwd; /* password entry for user */
+ struct timeval now; /* time of authentication */
+
+ int state; /* authenticated state */
+
+ struct rmfiles *rmlist; /* list of files to remove on failure */
+ struct authopts *optlist; /* list of options to scripts */
+ struct authdata *data; /* additional data to send to scripts */
+
+ char spool[MAXSPOOLSIZE]; /* data returned from login script */
+ int index; /* how much returned thus far */
+
+ va_list ap0; /* argument list to auth_call */
+ va_list ap; /* additional arguments to auth_call */
+};
+
+/*
+ * Internal flags
+ */
+#define AF_INTERACTIVE 0x0001 /* This is an interactive session */
+
+/*
+ * We cannot include bsd_auth.h until we define the above structures
+ */
+#include <bsd_auth.h>
+
+/*
+ * Internally used functions
+ */
+static void _add_rmlist(auth_session_t *, char *);
+static void _auth_spool(auth_session_t *, int);
+static char *_auth_next_arg(auth_session_t *);
+/*
+ * Set up a known environment for all authentication scripts.
+ */
+static char *auth_environ[] = {
+ "PATH=" _PATH_DEFPATH,
+ "SHELL=" _PATH_BSHELL,
+ NULL,
+};
+
+static char defservice[] = LOGIN_DEFSERVICE;
+
+/*
+ * Quick one liners that only exist to keep auth_session_t opaque
+ */
+void auth_setstate(auth_session_t *as, int s){ as->state = s; }
+void auth_set_va_list(auth_session_t *as, va_list ap) { as->ap = ap; }
+int auth_getstate(auth_session_t *as) { return (as->state); }
+struct passwd *auth_getpwd(auth_session_t *as) { return (as->pwd); }
+
+/*
+ * Open a new BSD Authentication session with the default service
+ * (which can be changed later).
+ */
+auth_session_t *
+auth_open()
+{
+ auth_session_t *as;
+
+ if ((as = malloc(sizeof(auth_session_t))) != NULL) {
+ memset(as, 0, sizeof(*as));
+ as->service = defservice;
+ }
+
+ return (as);
+}
+
+/*
+ * Clean the specified BSD Authentication session.
+ */
+void
+auth_clean(auth_session_t *as)
+{
+ struct rmfiles *rm;
+ struct authdata *data;
+
+ as->state = 0;
+
+ auth_clrenv(as);
+
+ /*
+ * Clean out the rmlist and remove specified files
+ */
+ while ((rm = as->rmlist) != NULL) {
+ as->rmlist = rm->next;
+ unlink(rm->file);
+ free(rm);
+ }
+
+ /*
+ * Clean out data
+ */
+ while ((data = as->data) != NULL) {
+ if (as->data->len)
+ memset(as->data->ptr, 0, as->data->len);
+ as->data = data->next;
+ free(data);
+ }
+
+ auth_setitem(as, AUTHV_ALL, NULL);
+
+ if (as->pwd != NULL) {
+ free(as->pwd);
+ as->pwd = NULL;
+ }
+}
+
+/*
+ * Close the specified BSD Authentication session.
+ * Return 0 if not authenticated.
+ */
+int
+auth_close(auth_session_t *as)
+{
+ struct rmfiles *rm;
+ struct authopts *opt;
+ struct authdata *data;
+ int s;
+
+ /*
+ * Save our return value
+ */
+ s = as->state & AUTH_ALLOW;
+
+ if (s == 0)
+ as->index = 0;
+
+ auth_setenv(as);
+
+
+ /*
+ * Clean out the rmlist and remove specified files if the
+ * authentication failed
+ */
+ while ((rm = as->rmlist) != NULL) {
+ as->rmlist = rm->next;
+ if (s == 0)
+ unlink(rm->file);
+ free(rm);
+ }
+
+ /*
+ * Clean out the opt list
+ */
+ while ((opt = as->optlist) != NULL) {
+ as->optlist = opt->next;
+ free(opt);
+ }
+
+ /*
+ * Clean out data
+ */
+ while ((data = as->data) != NULL) {
+ if (as->data->len)
+ memset(as->data->ptr, 0, as->data->len);
+ as->data = data->next;
+ free(data);
+ }
+
+ /*
+ * Clean up random variables
+ */
+ if (as->service && as->service != defservice)
+ free(as->service);
+ if (as->challenge)
+ free(as->challenge);
+ if (as->class)
+ free(as->class);
+ if (as->style)
+ free(as->style);
+ if (as->name)
+ free(as->name);
+
+ free(as);
+ return (s);
+}
+
+/*
+ * Request a challange for the session.
+ * The name and style must have already been specified
+ */
+char *
+auth_challenge(auth_session_t *as)
+{
+ char path[MAXPATHLEN];
+
+ as->state = 0;
+
+ if (as == NULL || as->style == NULL || as->name == NULL)
+ return (NULL);
+
+ if (as->challenge) {
+ free(as->challenge);
+ as->challenge = NULL;
+ }
+
+ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", as->style);
+ auth_call(as, path, as->style, "-s", "challenge", as->name,
+ as->class, NULL);
+ if (as->state & AUTH_CHALLENGE)
+ as->challenge = auth_getvalue(as, "challenge");
+ as->state = 0;
+ as->index = 0; /* toss our data */
+ return (as->challenge);
+}
+
+/*
+ * Set/unset the requested environment variables.
+ * Mark the variables as set so they will not be set a second time.
+ * XXX - should provide a way to detect setenv() failure.
+ */
+void
+auth_setenv(auth_session_t *as)
+{
+ char *line, *name;
+
+ /*
+ * Set any environment variables we were asked for
+ */
+ for (line = as->spool; line < as->spool + as->index;) {
+ if (!strncasecmp(line, BI_SETENV, sizeof(BI_SETENV)-1)) {
+ if (isblank(line[sizeof(BI_SETENV) - 1])) {
+ /* only do it once! */
+ line[0] = 'd'; line[1] = 'i'; line[2] = 'd';
+ line += sizeof(BI_SETENV) - 1;
+ for (name = line; isblank(*name); ++name)
+ ;
+ for (line = name; *line && !isblank(*line);
+ ++line)
+ ;
+ if (*line)
+ *line++ = '\0';
+ for (; isblank(*line); ++line)
+ ;
+ if (*line != '\0' && setenv(name, line, 1))
+ warn("setenv(%s, %s)", name, line);
+ }
+ } else
+ if (!strncasecmp(line, BI_UNSETENV, sizeof(BI_UNSETENV)-1)) {
+ if (isblank(line[sizeof(BI_UNSETENV) - 1])) {
+ /* only do it once! */
+ line[2] = 'd'; line[3] = 'i'; line[4] = 'd';
+ line += sizeof(BI_UNSETENV) - 1;
+ for (name = line; isblank(*name); ++name)
+ ;
+ for (line = name; *line && !isblank(*line);
+ ++line)
+ ;
+ if (*line)
+ *line++ = '\0';
+ unsetenv(name);
+ }
+ }
+ while (*line++)
+ ;
+ }
+}
+
+/*
+ * Clear out any requested environment variables.
+ */
+void
+auth_clrenv(auth_session_t *as)
+{
+ char *line;
+
+ for (line = as->spool; line < as->spool + as->index;) {
+ if (!strncasecmp(line, BI_SETENV, sizeof(BI_SETENV)-1)) {
+ if (isblank(line[sizeof(BI_SETENV) - 1])) {
+ line[0] = 'i'; line[1] = 'g'; line[2] = 'n';
+ }
+ } else
+ if (!strncasecmp(line, BI_UNSETENV, sizeof(BI_UNSETENV)-1)) {
+ if (isblank(line[sizeof(BI_UNSETENV) - 1])) {
+ line[2] = 'i'; line[3] = 'g'; line[4] = 'n';
+ }
+ }
+ while (*line++)
+ ;
+ }
+}
+
+char *
+auth_getitem(auth_session_t *as, auth_item_t item)
+{
+ if (as != NULL) {
+ switch (item) {
+ case AUTHV_CHALLENGE:
+ return (as->challenge);
+ case AUTHV_CLASS:
+ return (as->class);
+ case AUTHV_NAME:
+ return (as->name);
+ case AUTHV_SERVICE:
+ return (as->service ? as->service : defservice);
+ case AUTHV_STYLE:
+ return (as->style);
+ case AUTHV_INTERACTIVE:
+ return ((as->flags & AF_INTERACTIVE) ? "True" : NULL);
+ default:
+ break;
+ }
+ }
+ return (NULL);
+}
+
+int
+auth_setitem(auth_session_t *as, auth_item_t item, char *value)
+{
+ if (as == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (item) {
+ case AUTHV_ALL:
+ if (value != NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ auth_setitem(as, AUTHV_CHALLENGE, NULL);
+ auth_setitem(as, AUTHV_CLASS, NULL);
+ auth_setitem(as, AUTHV_NAME, NULL);
+ auth_setitem(as, AUTHV_SERVICE, NULL);
+ auth_setitem(as, AUTHV_STYLE, NULL);
+ auth_setitem(as, AUTHV_INTERACTIVE, NULL);
+ return (0);
+
+ case AUTHV_CHALLENGE:
+ if (value != NULL && (value = strdup(value)) == NULL)
+ return (-1);
+ if (as->challenge)
+ free(as->challenge);
+ as->challenge = value;
+ return (0);
+
+ case AUTHV_CLASS:
+ if (value != NULL && (value = strdup(value)) == NULL)
+ return (-1);
+
+ if (as->class)
+ free(as->class);
+
+ as->class = value;
+ return (0);
+
+ case AUTHV_NAME:
+ if (value != NULL && (value = strdup(value)) == NULL)
+ return (-1);
+
+ if (as->name)
+ free(as->name);
+
+ as->name = value;
+ return (0);
+
+ case AUTHV_SERVICE:
+ if (value == NULL || strcmp(value, defservice) == 0)
+ value = defservice;
+ else if ((value = strdup(value)) == NULL)
+ return (-1);
+
+ if (as->service && as->service != defservice)
+ free(as->service);
+
+ as->service = value;
+ return (0);
+
+ case AUTHV_STYLE:
+ if (value == NULL || strchr(value, '/') != NULL ||
+ (value = strdup(value)) == NULL)
+ return (-1);
+
+ if (as->style)
+ free(as->style);
+
+ as->style = value;
+ return (0);
+
+ case AUTHV_INTERACTIVE:
+ if (value == NULL)
+ as->flags &= ~AF_INTERACTIVE;
+ else
+ as->flags |= ~AF_INTERACTIVE;
+ return (0);
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+int
+auth_setoption(auth_session_t *as, char *n, char *v)
+{
+ struct authopts *opt;
+ int i = strlen(n) + strlen(v) + 2;
+
+ if ((opt = malloc(sizeof(*opt) + i)) == NULL)
+ return (-1);
+
+ opt->opt = (char *)(opt + 1);
+
+ sprintf(opt->opt, "%s=%s", n, v);
+ opt->next = as->optlist;
+ as->optlist = opt;
+ return(0);
+}
+
+void
+auth_clroptions(auth_session_t *as)
+{
+ struct authopts *opt;
+
+ while ((opt = as->optlist) != NULL) {
+ as->optlist = opt->next;
+ free(opt);
+ }
+}
+
+void
+auth_clroption(auth_session_t *as, char *option)
+{
+ struct authopts *opt, *oopt;
+ int len;
+
+ len = strlen(option);
+
+ if ((opt = as->optlist) == NULL)
+ return;
+
+ if (strncmp(opt->opt, option, len) == 0 &&
+ (opt->opt[len] == '=' || opt->opt[len] == '\0')) {
+ as->optlist = opt->next;
+ free(opt);
+ return;
+ }
+
+ while ((oopt = opt->next) != NULL) {
+ if (strncmp(oopt->opt, option, len) == 0 &&
+ (oopt->opt[len] == '=' || oopt->opt[len] == '\0')) {
+ opt->next = oopt->next;
+ free(oopt);
+ return;
+ }
+ opt = oopt;
+ }
+}
+
+int
+auth_setdata(auth_session_t *as, void *ptr, size_t len)
+{
+ struct authdata *data, *dp;
+
+ if (len <= 0)
+ return (0);
+
+ if ((data = malloc(sizeof(*data) + len)) == NULL)
+ return (-1);
+
+ data->next = NULL;
+ data->len = len;
+ data->ptr = data + 1;
+ memcpy(data->ptr, ptr, len);
+
+ if (as->data == NULL)
+ as->data = data;
+ else {
+ for (dp = as->data; dp->next != NULL; dp = dp->next)
+ ;
+ dp->next = data;
+ }
+ return (0);
+}
+
+int
+auth_setpwd(auth_session_t *as, struct passwd *pwd)
+{
+ char *instance;
+
+ if (pwd == NULL && as->pwd == NULL && as->name == NULL)
+ return (-1); /* true failure */
+
+ if (pwd == NULL) {
+ /*
+ * If we were not passed in a pwd structure we need to
+ * go find one for ourself. Always look up the username
+ * (if it is defined) in the passwd database to see if there
+ * is an entry for the user. If not, either use the current
+ * entry or simply return a 1 which implies there is
+ * no user by that name here. This is not a failure, just
+ * a point of information.
+ */
+ if (as->name == NULL)
+ return (0);
+ if ((pwd = getpwnam(as->name)) == NULL) {
+ instance = strchr(as->name, '.');
+ if (instance == NULL)
+ return (as->pwd ? 0 : 1);
+ if (strcmp(instance, ".root") == 0)
+ pwd = getpwnam(instance + 1);
+ if (pwd == NULL)
+ return (as->pwd ? 0 : 1);
+ }
+ }
+ if ((pwd = pw_dup(pwd)) == NULL)
+ return (-1); /* true failure */
+ if (as->pwd)
+ free(as->pwd);
+ as->pwd = pwd;
+ return (0);
+}
+
+char *
+auth_getvalue(auth_session_t *as, char *what)
+{
+ char *line, *v, *value;
+ int n, len;
+
+ len = strlen(what);
+
+ for (line = as->spool; line < as->spool + as->index;) {
+ if (strncasecmp(line, BI_VALUE, sizeof(BI_VALUE)-1) != 0)
+ goto next;
+ line += sizeof(BI_VALUE) - 1;
+
+ if (!isblank(*line))
+ goto next;
+
+ while (isblank(*++line))
+ ;
+
+ if (strncmp(line, what, len) != 0 ||
+ !isblank(line[len]))
+ goto next;
+ line += len;
+ while (isblank(*++line))
+ ;
+ value = strdup(line);
+ if (value == NULL)
+ return (NULL);
+
+ /*
+ * XXX - There should be a more standardized
+ * routine for doing this sort of thing.
+ */
+ for (line = v = value; *line; ++line) {
+ if (*line == '\\') {
+ switch (*++line) {
+ case 'r':
+ *v++ = '\r';
+ break;
+ case 'n':
+ *v++ = '\n';
+ break;
+ case 't':
+ *v++ = '\t';
+ break;
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7':
+ n = *line - '0';
+ if (isdigit(line[1])) {
+ ++line;
+ n <<= 3;
+ n |= *line-'0';
+ }
+ if (isdigit(line[1])) {
+ ++line;
+ n <<= 3;
+ n |= *line-'0';
+ }
+ break;
+ default:
+ *v++ = *line;
+ break;
+ }
+ } else
+ *v++ = *line;
+ }
+ *v = '\0';
+ return (value);
+next:
+ while (*line++)
+ ;
+ }
+ return (NULL);
+}
+
+quad_t
+auth_check_expire(auth_session_t *as)
+{
+ if (as->pwd == NULL && auth_setpwd(as, NULL) < 0) {
+ as->state &= ~AUTH_ALLOW;
+ as->state |= AUTH_EXPIRED; /* XXX */
+ return (-1);
+ }
+
+ if (as->pwd == NULL)
+ return (0);
+
+ if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
+ if (as->now.tv_sec == 0)
+ gettimeofday(&as->now, (struct timezone *)NULL);
+ if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
+ as->state &= ~AUTH_ALLOW;
+ as->state |= AUTH_EXPIRED;
+ }
+ if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_expire)
+ return (-1);
+ return ((quad_t)as->pwd->pw_expire - (quad_t)as->now.tv_sec);
+ }
+ return (0);
+}
+
+quad_t
+auth_check_change(auth_session_t *as)
+{
+ if (as->pwd == NULL && auth_setpwd(as, NULL) < 0) {
+ as->state &= ~AUTH_ALLOW;
+ as->state |= AUTH_PWEXPIRED; /* XXX */
+ return (-1);
+ }
+
+ if (as->pwd == NULL)
+ return (0);
+
+ if (as->pwd && (quad_t)as->pwd->pw_change) {
+ if (as->now.tv_sec == 0)
+ gettimeofday(&as->now, (struct timezone *)NULL);
+ if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
+ as->state &= ~AUTH_ALLOW;
+ as->state |= AUTH_PWEXPIRED;
+ }
+ if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_change)
+ return (-1);
+ return ((quad_t)as->pwd->pw_change - (quad_t)as->now.tv_sec);
+ }
+ return (0);
+}
+
+/*
+ * The down and dirty call to the login script
+ * okay contains the default return value, typically 0 but
+ * is AUTH_OKAY for approval like scripts.
+ *
+ * Internally additional trailing arguments can be read from as->ap
+ * Options will be placed be placed just after the first argument
+ * (not including path).
+ *
+ * Any data will sent (and freed) to the script
+ */
+int
+auth_call(auth_session_t *as, char *path, ...)
+{
+ char *line;
+ struct authdata *data;
+ struct authopts *opt;
+ pid_t pid;
+ int status;
+ int okay;
+ int pfd[2];
+ int argc;
+ char *argv[64]; /* 64 args should more than enough */
+#define Nargc (sizeof(argv)/sizeof(argv[0]))
+
+ va_start(as->ap0, path);
+
+ argc = 0;
+ if ((argv[argc] = _auth_next_arg(as)) != NULL)
+ ++argc;
+
+ for (opt = as->optlist; opt != NULL; opt = opt->next) {
+ if (argc < Nargc - 2) {
+ argv[argc++] = "-v";
+ argv[argc++] = opt->opt;
+ } else {
+ syslog(LOG_ERR, "too many authentication options");
+ goto fail;
+ }
+ }
+ while (argc < Nargc - 1 && (argv[argc] = _auth_next_arg(as)))
+ ++argc;
+
+ if (argc >= Nargc - 1 && _auth_next_arg(as)) {
+ if (as->ap0) {
+ va_end(as->ap0);
+ as->ap0 = NULL;
+ }
+ if (as->ap) {
+ va_end(as->ap);
+ as->ap = NULL;
+ }
+ syslog(LOG_ERR, "too many arguments");
+ goto fail;
+ }
+
+ argv[argc] = NULL;
+
+ if (secure_path(path) < 0) {
+ syslog(LOG_ERR, "%s: path not secure", path);
+ warnx("invalid script: %s", path);
+ goto fail;
+ }
+
+ if (socketpair(PF_LOCAL, SOCK_STREAM, 0, pfd) < 0) {
+ syslog(LOG_ERR, "unable to create backchannel %m");
+ warnx("internal resource failure");
+ goto fail;
+ }
+
+ switch (pid = fork()) {
+ case -1:
+ close(pfd[0]);
+ close(pfd[1]);
+ syslog(LOG_ERR, "%s: %m", path);
+ warnx("internal resource failure");
+ goto fail;
+ case 0:
+#define COMM_FD 3
+ close(pfd[0]);
+ if (pfd[1] != COMM_FD) {
+ if (dup2(pfd[1], COMM_FD) < 0)
+ err(1, "dup of backchannel");
+ close(pfd[1]);
+ }
+
+ for (status = getdtablesize() - 1; status > COMM_FD; status--)
+ close(status);
+
+ execve(path, argv, auth_environ);
+ syslog(LOG_ERR, "%s: %m", path);
+ err(1, "%s", path);
+ default:
+ close(pfd[1]);
+ while ((data = as->data) != NULL) {
+ as->data = data->next;
+ if (data->len > 0) {
+ write(pfd[0], data->ptr, data->len);
+ memset(data->ptr, 0, data->len);
+ }
+ free(data);
+ }
+ as->index = 0;
+ _auth_spool(as, pfd[0]);
+ close(pfd[0]);
+ if (waitpid(pid, &status, 0) < 0) {
+ syslog(LOG_ERR, "%s: waitpid: %m", path);
+ warnx("internal failure");
+ goto fail;
+ }
+
+ if (!WIFEXITED(status))
+ goto fail;
+ }
+
+ /*
+ * Now scan the spooled data
+ * It is easier to wait for all the data before starting
+ * to scan it.
+ */
+ for (line = as->spool; line < as->spool + as->index;) {
+ if (!strncasecmp(line, BI_REJECT, sizeof(BI_REJECT)-1)) {
+ line += sizeof(BI_REJECT) - 1;
+ if (!*line || *line == ' ' || *line == '\t') {
+ while (*line == ' ' || *line == '\t')
+ ++line;
+ if (!strcasecmp(line, "silent")) {
+ as->state = AUTH_SILENT;
+ break;
+ }
+ if (!strcasecmp(line, "challenge")) {
+ as->state = AUTH_CHALLENGE;
+ break;
+ }
+ if (!strcasecmp(line, "expired")) {
+ as->state = AUTH_EXPIRED;
+ break;
+ }
+ if (!strcasecmp(line, "pwexpired")) {
+ as->state = AUTH_PWEXPIRED;
+ break;
+ }
+ }
+ break;
+ } else if (!strncasecmp(line, BI_AUTH, sizeof(BI_AUTH)-1)) {
+ line += sizeof(BI_AUTH) - 1;
+ if (!*line || *line == ' ' || *line == '\t') {
+ while (*line == ' ' || *line == '\t')
+ ++line;
+ if (*line == '\0')
+ as->state |= AUTH_OKAY;
+ else if (!strcasecmp(line, "root"))
+ as->state |= AUTH_ROOTOKAY;
+ else if (!strcasecmp(line, "secure"))
+ as->state |= AUTH_SECURE;
+ }
+ } else if (!strncasecmp(line, BI_REMOVE, sizeof(BI_REMOVE)-1)) {
+ line += sizeof(BI_REMOVE) - 1;
+ while (*line == ' ' || *line == '\t')
+ ++line;
+ if (*line)
+ _add_rmlist(as, line);
+ }
+ while (*line++)
+ ;
+ }
+
+ if (WEXITSTATUS(status))
+ as->state &= ~AUTH_ALLOW;
+
+ okay = as->state & AUTH_ALLOW;
+
+ if (!okay)
+ auth_clrenv(as);
+
+ if (0) {
+fail:
+ auth_clrenv(as);
+ as->state = 0;
+ okay = -1;
+ }
+
+ while ((data = as->data) != NULL) {
+ as->data = data->next;
+ free(data);
+ }
+
+ if (as->ap0) {
+ va_end(as->ap0);
+ as->ap0 = NULL;
+ }
+
+ if (as->ap) {
+ va_end(as->ap);
+ as->ap = NULL;
+ }
+ return (okay);
+}
+
+static void
+_auth_spool(auth_session_t *as, int fd)
+{
+ int r;
+ char *b;
+
+ while (as->index < sizeof(as->spool) - 1) {
+ r = read(fd, as->spool + as->index,
+ sizeof(as->spool) - as->index);
+ if (r <= 0) {
+ as->spool[as->index] = '\0';
+ return;
+ }
+ b = as->spool + as->index;
+ as->index += r;
+ /*
+ * Go ahead and convert newlines into NULs to allow
+ * easy scanning of the file.
+ */
+ while(r-- > 0)
+ if (*b++ == '\n')
+ b[-1] = '\0';
+ }
+
+ syslog(LOG_ERR, "Overflowed backchannel spool buffer");
+ errx(1, "System error in authentication program");
+}
+
+static void
+_add_rmlist(auth_session_t *as, char *file)
+{
+ struct rmfiles *rm;
+ int i = strlen(file) + 1;
+
+ if ((rm = malloc(sizeof(struct rmfiles) + i)) == NULL) {
+ syslog(LOG_ERR, "Failed to allocate rmfiles: %m");
+ return;
+ }
+ rm->file = (char *)(rm + 1);
+ rm->next = as->rmlist;
+ strcpy(rm->file, file);
+ as->rmlist = rm;
+}
+
+static char *
+_auth_next_arg(auth_session_t *as)
+{
+ char *arg;
+
+ if (as->ap0) {
+ if ((arg = va_arg(as->ap0, char *)) != NULL)
+ return (arg);
+ va_end(as->ap0);
+ as->ap0 = NULL;
+ }
+ if (as->ap) {
+ if ((arg = va_arg(as->ap, char *)) != NULL)
+ return (arg);
+ va_end(as->ap);
+ as->ap = NULL;
+ }
+ return (NULL);
+}
diff --git a/lib/libc/gen/authenticate.3 b/lib/libc/gen/authenticate.3
new file mode 100644
index 00000000000..4d9d5c50e85
--- /dev/null
+++ b/lib/libc/gen/authenticate.3
@@ -0,0 +1,275 @@
+.\" $OpenBSD: authenticate.3,v 1.1 2000/11/21 00:51:16 millert Exp $
+.\"
+.\" Copyright (c) 1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Berkeley Software Design,
+.\" Inc.
+.\" 4. The name of Berkeley Software Design, Inc. may not be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" BSDI $From: authenticate.3,v 2.7 1998/09/03 20:27:20 prb Exp $
+.Dd March 26, 1997
+.Dt AUTHENTICATE 3
+.Os
+.Sh NAME
+.Nm auth_approval ,
+.Nm auth_cat ,
+.Nm auth_checknologin ,
+.Nm auth_mkvalue ,
+.Nm auth_userchallenge ,
+.Nm auth_usercheck ,
+.Nm auth_userokay ,
+.Nm auth_userresponse ,
+.Nm auth_verify
+.Nd simplified interface to the BSD Authentication system
+.Sh SYNOPSIS
+.Fd #include <login_cap.h>
+.Fd #include <bsd_auth.h>
+.Ft int
+.Fn auth_userokay "char *name" "char *style" "char *type" "char *password"
+.Ft auth_session_t *
+.Fn auth_userchallenge "char *name" "char *style" "char *type" "char **challengep"
+.Ft auth_session_t *
+.Fn auth_usercheck "char *name" "char *style" "char *type" "char *password"
+.Ft int
+.Fn auth_userresponse "auth_session_t *as" "char *response" "int more"
+.Ft int
+.Fn auth_approval "auth_session_t *as" "login_cap_t *lc" "char *name" "char *type"
+.Ft int
+.Fn auth_cat "char *file"
+.Ft void
+.Fn auth_checknologin "login_cap_t *lc"
+.Ft char *
+.Fn auth_mkvalue "char *value"
+.Ft auth_session_t *
+.Fn auth_verify "auth_session_t *as" "char *style" "char *name" "..."
+.Sh DESCRIPTION
+These functions provide a simplified interface to the BSD Authentication
+system
+.Pq see Xr bsd_auth 3 Ns .
+The
+.Fn auth_userokay
+function provides a single function call interface.
+Provided a user's name in
+.Ar name
+and an optional
+.Ar style ,
+.Ar type ,
+and
+.Ar password
+the
+.Fn auth_userokay
+function returns a simple yes/no response.
+A return value of 0 implies failure, a non-zero return value implies success.
+If
+.Ar style
+is not
+.Dv NULL
+it specifies the desired style of authentication to be used. If it is
+.Dv NULL
+then the default style for the user is used. In this case
+.Ar name
+may include the desired style by appending it to the user's name with a
+single colon
+.Pq Sq \:
+as a separator.
+If
+.Ar type
+is not
+.Dv NULL
+then it is used as the authentication type (such as
+.Dq auth-myservice ) .
+If
+.Ar password
+is
+.Dv NULL
+then
+.Fn auth_userokay
+operates in an interactive mode with the user on standard input, output,
+and error. If
+.Ar password
+is specified,
+.Fn auth_userokay
+operates in a non-interactive mode and only tests the specified passwords.
+This non-interactive method does not work with challenge-response
+authentication styles.
+.Pp
+The
+.Fn auth_usercheck
+function operates the same as the
+.Fn auth_userokay
+function except that it does not close the BSD Authentication session
+created. Rather than returning the status of the session it returns
+a pointer to the newly created BSD Authentication session.
+.Pp
+The
+.Fn auth_userchallenge
+function takes the same
+.Ar name , style ,
+and
+.Ar type
+arguments as does
+.Fn auth_userokay .
+However, rather than authenticating the user, it returns a possible
+challenge in the pointer pointed to by
+.Ar challengep .
+The return value of the function is a pointer to a newly created
+BSD Authentication session.
+This challenge, if not
+.Dv NULL ,
+should be displayed to the user.
+In any case, the user should provide a password which is
+the
+.Ar response
+in a call to
+.Fn auth_userresponse.
+In addition to the password, the pointer returned by
+.Fn auth_userchallenge
+should be passed in as
+.Ar as
+and the value of
+.Va more
+should be non-zero if the program wishes to allow more attempts.
+If
+.Va more
+is zero then the session will be closed.
+The
+.Fn auth_userresponse
+function closes the BSD Authentication session and has the same
+return value as
+.Fn auth_userokay .
+.Pp
+The
+.Fn auth_approval
+function calls the approval script for the user of the specified
+.Fn type .
+The string
+.Dq approve-
+will be prepended to
+.Ar type
+if missing.
+The resulting type is used to lookup an entry in the
+.Pa /etc/login.conf
+for the user's class. If the entry is missing the generic
+entry for
+.Dq approve
+will be used.
+The
+.Ar name
+argument will be passed to the approval program as the name of the user.
+The
+.Ar lc
+argument points to a login class structure. If it is
+.Dv NULL
+then a login class structure will be looked up for the class of
+user
+.Ar name .
+The
+.Fn auth_approval
+function returns a value of 0 on failure to approve the user.
+.Pp
+Prior to actually calling the approval script, the account's
+expiration time, the associated nologin file, and existence
+of the account's home directory
+.Po
+if
+.Li requirehome
+is set for this class
+.Pc
+are checked.
+Failure on any of these points causes the
+.Fn auth_approval
+function to return a value of 0 and not actually call the approval script.
+.Pp
+The
+.Fn auth_cat
+function opens
+.Ar file
+for reading and copies its contents to standard output.
+It returns 0 if it was unable to open
+.Ar file
+and 1 otherwise.
+.Pp
+The
+.Fn auth_checknologin
+function must be provided with a pointer to a login class.
+If the class has a
+.Dq nologin
+entry defined and it points to a file that can be opened,
+the contents of the file will be copied to standard output and
+.Xr exit 3
+will be called with a value of 1.
+If the class does not have the field
+.Dq ignorenologin
+and the file
+.Pa /etc/nologin
+exists its contents will be copied to standard output and
+.Xr exit 3
+will be called with a value of 1.
+.Pp
+The
+.Fn auth_verify
+function is a front end to the
+.Fn auth_call
+function
+.Pq see Xr auth_subr 3 Ns .
+It will open a BSD Authentication session, if needed, and will set
+the style and user name based on the
+.Ar style
+and
+.Ar name
+arguments, if not
+.Dv NULL .
+The variable arguments are passed to
+.Fn auth_call
+via the
+.Fn auth_set_va_list
+function
+.Pq see Xr auth_subr 3 Ns .
+The, possibly created, BSD Authentication session is returned.
+The
+.Fn auth_getstate
+or
+.Fn auth_close
+function
+.Pq see Xr auth_subr 3
+should be used to determine the outcome of the authentication request.
+.Pp
+The
+.Fn auth_mkvalue
+function takes a null terminated string pointed to by
+.Ar value
+and returns a null terminated string suitable for passing
+back to a calling program on the back channel. This function
+is for use by the login scripts themselves.
+The string returned should be freed by
+.Xr free 3
+when it is no longer needed.
+A value of
+.Dv NULL
+is returned if no memory was available for the new copy of the string.
+.Sh SEE ALSO
+.Xr auth_subr 3
diff --git a/lib/libc/gen/authenticate.c b/lib/libc/gen/authenticate.c
new file mode 100644
index 00000000000..eca44f5f289
--- /dev/null
+++ b/lib/libc/gen/authenticate.c
@@ -0,0 +1,478 @@
+/* $OpenBSD: authenticate.c,v 1.1 2000/11/21 00:51:16 millert Exp $ */
+
+/*-
+ * Copyright (c) 1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software Design,
+ * Inc.
+ * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI $From: authenticate.c,v 2.21 1999/09/08 22:33:26 prb Exp $
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <login_cap.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsd_auth.h>
+
+static int _auth_checknologin(login_cap_t *, int);
+
+char *
+auth_mkvalue(char *value)
+{
+ char *big, *p;
+
+ big = malloc(strlen(value) * 4 + 1);
+ if (big == NULL)
+ return (NULL);
+ /*
+ * XXX - There should be a more standardized
+ * routine for doing this sort of thing.
+ */
+ for (p = big; *value; ++value) {
+ switch (*value) {
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ break;
+ case '\\':
+ *p++ = '\\';
+ *p++ = *value;
+ break;
+ case '\t':
+ case ' ':
+ if (p == big)
+ *p++ = '\\';
+ *p++ = *value;
+ break;
+ default:
+ if (!isprint(*value)) {
+ *p++ = '\\';
+ *p++ = ((*value >> 6) & 0x3) + '0';
+ *p++ = ((*value >> 3) & 0x7) + '0';
+ *p++ = ((*value ) & 0x7) + '0';
+ } else
+ *p++ = *value;
+ break;
+ }
+ }
+ *p = '\0';
+ return (big);
+}
+
+void
+auth_checknologin(login_cap_t *lc)
+{
+ struct stat sb;
+ char *nologin;
+
+ if (_auth_checknologin(lc, 1))
+ exit(1);
+}
+
+static int
+_auth_checknologin(login_cap_t *lc, int print)
+{
+ struct stat sb;
+ char *nologin;
+
+ /*
+ * If we fail to get the nologin file due to a database error,
+ * assume there should have been one...
+ */
+ if ((nologin = login_getcapstr(lc, "nologin", "", NULL)) == NULL) {
+ if (print) {
+ printf("Logins are not allowed at this time.\n");
+ fflush(stdout);
+ }
+ return (-1);
+ }
+ if (*nologin && stat(nologin, &sb) >= 0) {
+ if (print && auth_cat(nologin) == 0) {
+ printf("Logins are not allowed at this time.\n");
+ fflush(stdout);
+ }
+ return (-1);
+ }
+
+ if (login_getcapbool(lc, "ignorenologin", 0))
+ return(0);
+
+ if (stat(_PATH_NOLOGIN, &sb) >= 0) {
+ if (print && auth_cat(_PATH_NOLOGIN) == 0) {
+ printf("Logins are not allowed at this time.\n");
+ fflush(stdout);
+ }
+ return (-1);
+ }
+ return(0);
+}
+
+int
+auth_cat(char *file)
+{
+ int fd, nchars;
+ char tbuf[8192];
+
+ if ((fd = open(file, O_RDONLY, 0)) < 0)
+ return (0);
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+ (void)close(fd);
+ return (1);
+}
+
+int
+auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
+{
+ int close_on_exit, close_lc_on_exit;
+ struct passwd *pwd;
+ char *approve, *s, path[MAXPATHLEN];
+
+ pwd = NULL;
+ close_on_exit = as == NULL;
+ close_lc_on_exit = lc == NULL;
+
+ if (as != NULL && name == NULL)
+ name = auth_getitem(as, AUTHV_NAME);
+
+ if (as != NULL)
+ pwd = auth_getpwd(as);
+
+ if (pwd == NULL)
+ if (name != NULL)
+ pwd = getpwnam(name);
+ else {
+ if ((pwd = getpwuid(getuid())) == NULL) {
+ syslog(LOG_ERR, "no such user id %d", getuid());
+ warnx("cannot approve who we don't recognize");
+ return (0);
+ }
+ name = pwd->pw_name;
+ }
+
+ if (name == NULL)
+ name = pwd->pw_name;
+
+ if (lc == NULL) {
+ if (strlen(name) >= MAXPATHLEN) {
+ syslog(LOG_ERR, "username to login %.*s...",
+ MAXPATHLEN, name);
+ warnx("username too long");
+ return (0);
+ }
+ if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
+ strcpy(path, name);
+ path[approve-name] = '\0';
+ pwd = getpwnam(name);
+ }
+ lc = login_getclass(pwd ? pwd->pw_class : NULL);
+ if (lc == NULL) {
+ warnx("unable to classify user");
+ return (0);
+ }
+ }
+
+ if (!type)
+ type = LOGIN_DEFSERVICE;
+ else {
+ if (strncmp(type, "approve-", 8) == 0)
+ type += 8;
+
+ snprintf(path, sizeof(path), "approve-%s", type);
+ }
+
+ if ((approve = login_getcapstr(lc, s = path, NULL, NULL)) == NULL)
+ approve = login_getcapstr(lc, s = "approve", NULL, NULL);
+
+ if (approve && approve[0] != '/') {
+ if (close_lc_on_exit)
+ login_close(lc);
+ syslog(LOG_ERR, "Invalid %s script: %s", s, approve);
+ warnx("invalid path to approval script");
+ return (0);
+ }
+
+ if (as == NULL && (as = auth_open()) == NULL) {
+ if (close_lc_on_exit)
+ login_close(lc);
+ syslog(LOG_ERR, "%m");
+ warnx(NULL);
+ return (0);
+ }
+
+ auth_setstate(as, AUTH_OKAY);
+ if (auth_setitem(as, AUTHV_NAME, name) < 0) {
+ syslog(LOG_ERR, "%m");
+ warnx(NULL);
+ goto out;
+ }
+ if (auth_check_expire(as)) /* is this account expired */
+ goto out;
+ if (_auth_checknologin(lc,
+ auth_getitem(as, AUTHV_INTERACTIVE) != NULL)) {
+ auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
+ goto out;
+ }
+ if (login_getcapbool(lc, "requirehome", 0) && pwd && pwd->pw_dir &&
+ pwd->pw_dir[0]) {
+ struct stat sb;
+
+ if (stat(pwd->pw_dir, &sb) < 0 ||
+ (sb.st_mode & 0170000) != S_IFDIR ||
+ (pwd->pw_uid && sb.st_uid == pwd->pw_uid &&
+ (sb.st_mode & S_IXUSR) == 0)) {
+ auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
+ goto out;
+ }
+ }
+ if (approve)
+ auth_call(as, approve, strrchr(approve, '/') + 1, name,
+ lc->lc_class, type, 0);
+
+out:
+ if (close_lc_on_exit)
+ login_close(lc);
+
+ if (close_on_exit)
+ return (auth_close(as));
+ return (auth_getstate(as) & AUTH_ALLOW);
+}
+
+auth_session_t *
+auth_usercheck(char *name, char *style, char *type, char *password)
+{
+ char namebuf[MAXLOGNAME + 1 + NAME_MAX + 1];
+ auth_session_t *as;
+ login_cap_t *lc;
+ struct passwd *pwd;
+ char *dot;
+
+ if (strlen(name) >= sizeof(namebuf))
+ return (NULL);
+ strcpy(namebuf, name);
+ name = namebuf;
+
+ /*
+ * Split up user:style names if we were not given a style
+ */
+ if (style == NULL && (style = strchr(name, ':')) != NULL)
+ *style++ = '\0';
+
+ /*
+ * Cope with user.instance. We are only using this to get
+ * the class so it is okay if we strip a .root instance
+ * The actual login script will pay attention to the instance.
+ */
+ if ((pwd = getpwnam(name)) == NULL) {
+ if ((dot = strchr(name, '.')) != NULL) {
+ dot = '\0';
+ pwd = getpwnam(name);
+ *dot = '.';
+ }
+ }
+ if (pwd == NULL || (lc = login_getclass(pwd->pw_class)) == NULL)
+ return (NULL);
+
+ if ((style = login_getstyle(lc, style, type)) == NULL) {
+ login_close(lc);
+ return (NULL);
+ }
+
+ if (password) {
+ if ((as = auth_open()) == NULL) {
+ login_close(lc);
+ return (NULL);
+ }
+ auth_setitem(as, AUTHV_SERVICE, "response");
+ auth_setdata(as, "", 1);
+ auth_setdata(as, password, strlen(password) + 1);
+ } else
+ as = NULL;
+ as = auth_verify(as, style, name, pwd->pw_class, NULL);
+ login_close(lc);
+ return (as);
+}
+
+int
+auth_userokay(char *name, char *style, char *type, char *password)
+{
+ auth_session_t *as;
+ as = auth_usercheck(name, style, type, password);
+
+ return (as != NULL ? auth_close(as) : 0);
+}
+
+auth_session_t *
+auth_userchallenge(char *name, char *style, char *type, char **challengep)
+{
+ char namebuf[MAXLOGNAME + 1 + NAME_MAX + 1];
+ auth_session_t *as;
+ login_cap_t *lc;
+ struct passwd *pwd;
+ char *dot;
+
+ if (strlen(name) >= sizeof(namebuf))
+ return (NULL);
+ strcpy(namebuf, name);
+ name = namebuf;
+
+ /*
+ * Split up user:style names if we were not given a style
+ */
+ if (style == NULL && (style = strchr(name, ':')) != NULL)
+ *style++ = '\0';
+
+ /*
+ * Cope with user.instance. We are only using this to get
+ * the class so it is okay if we strip a .root instance
+ * The actual login script will pay attention to the instance.
+ */
+ if ((pwd = getpwnam(name)) == NULL) {
+ if ((dot = strchr(name, '.')) != NULL) {
+ dot = '\0';
+ pwd = getpwnam(name);
+ *dot = '.';
+ }
+ }
+ if (pwd == NULL || (lc = login_getclass(pwd->pw_class)) == NULL)
+ return (NULL);
+
+ if ((style = login_getstyle(lc, style, type)) == NULL ||
+ (as = auth_open()) == NULL) {
+ login_close(lc);
+ return (NULL);
+ }
+ if (auth_setitem(as, AUTHV_STYLE, style) < 0 ||
+ auth_setitem(as, AUTHV_NAME, name) < 0 ||
+ auth_setitem(as, AUTHV_CLASS, pwd->pw_class) < 0) {
+ auth_close(as);
+ login_close(lc);
+ return (NULL);
+ }
+ login_close(lc);
+ *challengep = auth_challenge(as);
+ return (as);
+}
+
+int
+auth_userresponse(auth_session_t *as, char *response, int more)
+{
+ char path[MAXPATHLEN];
+ char *style, *name, *challenge, *class;
+
+ if (as == NULL)
+ return (0);
+
+ auth_setstate(as, 0);
+
+ if ((style = auth_getitem(as, AUTHV_STYLE)) == NULL ||
+ (name = auth_getitem(as, AUTHV_NAME)) == NULL) {
+ if (more == 0)
+ return (auth_close(as));
+ return(0);
+ }
+ challenge = auth_getitem(as, AUTHV_CHALLENGE);
+ class = auth_getitem(as, AUTHV_CLASS);
+
+ if (challenge)
+ auth_setdata(as, challenge, strlen(challenge) + 1);
+ else
+ auth_setdata(as, "", 1);
+ if (response)
+ auth_setdata(as, response, strlen(response) + 1);
+ else
+ auth_setdata(as, "", 1);
+
+ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
+
+ auth_call(as, path, style, "-s", "response", name, class, NULL);
+
+ /*
+ * If they authenticated then make sure they did not expire
+ */
+ if (auth_getstate(as) & AUTH_ALLOW)
+ auth_check_expire(as);
+ if (more == 0)
+ return (auth_close(as));
+ return (auth_getstate(as) & AUTH_ALLOW);
+}
+
+/*
+ * Authenticate name with the specified style.
+ * If ``as'' is NULL a new session is formed with the default service.
+ * Returns NULL only if ``as'' is NULL and we were unable to allocate
+ * a new session.
+ *
+ * Use auth_close() or auth_getstate() to determine if the authentication
+ * worked.
+ */
+auth_session_t *
+auth_verify(auth_session_t *as, char *style, char *name, ...)
+{
+ va_list ap;
+ char path[MAXPATHLEN];
+
+ if ((name == NULL || style == NULL) && as == NULL)
+ return (as);
+
+ if (as == NULL && (as = auth_open()) == NULL)
+ return (NULL);
+ auth_setstate(as, 0);
+
+ if (style != NULL && auth_setitem(as, AUTHV_STYLE, style) < 0)
+ return (as);
+
+ if (name != NULL && auth_setitem(as, AUTHV_NAME, name) < 0)
+ return (as);
+
+ style = auth_getitem(as, AUTHV_STYLE);
+ name = auth_getitem(as, AUTHV_NAME);
+
+ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
+ va_start(ap, name);
+ auth_set_va_list(as, ap);
+ auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
+ auth_getitem(as, AUTHV_SERVICE), name, NULL);
+ return (as);
+}