diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2000-11-21 00:51:17 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2000-11-21 00:51:17 +0000 |
commit | c25d006191bf9cf74c82ae3be8ad115399fcbe1e (patch) | |
tree | 0f857919115e6030f35d449e79c4ec3d970fa161 | |
parent | 39e1c13e015b28253d0476c700d747595db651f6 (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.h | 87 | ||||
-rw-r--r-- | include/login_cap.h | 4 | ||||
-rw-r--r-- | lib/libc/gen/auth_subr.3 | 461 | ||||
-rw-r--r-- | lib/libc/gen/auth_subr.c | 986 | ||||
-rw-r--r-- | lib/libc/gen/authenticate.3 | 275 | ||||
-rw-r--r-- | lib/libc/gen/authenticate.c | 478 |
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); +} |