summaryrefslogtreecommitdiffstats
path: root/lib/libutil
diff options
context:
space:
mode:
authordavidn <davidn@FreeBSD.org>1997-01-04 16:50:08 +0000
committerdavidn <davidn@FreeBSD.org>1997-01-04 16:50:08 +0000
commit592532aadcdb13b887c05694955f650b9bd949ec (patch)
treeaa04c54fb028c62bb1d96580ed4783ff2af6df69 /lib/libutil
parent4caa8a8a8d6d5751162281575440b4564e1831c5 (diff)
downloadFreeBSD-src-592532aadcdb13b887c05694955f650b9bd949ec.zip
FreeBSD-src-592532aadcdb13b887c05694955f650b9bd949ec.tar.gz
Library functions relating to the login class capabilities database,
including manpages. See also login_cap.h.
Diffstat (limited to 'lib/libutil')
-rw-r--r--lib/libutil/Makefile20
-rw-r--r--lib/libutil/login_auth.371
-rw-r--r--lib/libutil/login_auth.c383
-rw-r--r--lib/libutil/login_cap.3378
-rw-r--r--lib/libutil/login_cap.c564
-rw-r--r--lib/libutil/login_class.3187
-rw-r--r--lib/libutil/login_class.c371
-rw-r--r--lib/libutil/login_ok.3109
-rw-r--r--lib/libutil/login_ok.c242
-rw-r--r--lib/libutil/login_times.3155
-rw-r--r--lib/libutil/login_times.c166
11 files changed, 2644 insertions, 2 deletions
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index e5f7063..2e6b8c8 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -4,9 +4,25 @@ LIB= util
SHLIB_MAJOR= 2
SHLIB_MINOR= 1
CFLAGS+=-DLIBC_SCCS -I${.CURDIR} -I/sys
-SRCS= login.c login_tty.c logout.c logwtmp.c pty.c setproctitle.c
-MAN3+= login.3 login_tty.3 logout.3 logwtmp.3 pty.3 setproctitle.3
+SRCS= login.c login_tty.c logout.c logwtmp.c pty.c setproctitle.c \
+ login_cap.c login_class.c login_auth.c login_times.c login_ok.c
+MAN3+= login.3 login_tty.3 logout.3 logwtmp.3 pty.3 setproctitle.3 \
+ login_cap.3 login_class.3 login_times.3 login_ok.3
+MAN5+= login.conf.5
MLINKS+= pty.3 openpty.3 pty.3 forkpty.3
+MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \
+ login_cap.3 login_getclass.3 login_cap.3 login_getuserclass.3 \
+ login_cap.3 login_getcapstr.3 login_cap.3 login_getcaplist.3 \
+ login_cap.3 login_getstyle.3 login_cap.3 login_getcaptime.3 \
+ login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \
+ login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3
+MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \
+ login_class.3 setclassenvironment.3 login_class.3 setclassresources.3
+MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \
+ login_times.3 in_lt.3 login_times.3 in_ltms.3 \
+ login_times.3 in_lts.3
+MLINKS+=login_ok.3 auth_ttyok.3 login_ok.3 auth_hostok.3 \
+ login_ok.3 auth_timeok.3
beforeinstall:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/libutil.h \
diff --git a/lib/libutil/login_auth.3 b/lib/libutil/login_auth.3
new file mode 100644
index 0000000..555195f
--- /dev/null
+++ b/lib/libutil/login_auth.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" 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. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd December 29, 1996
+.Os FreeBSD
+.Dt LOGIN_AUTH 3
+.Sh NAME
+.Nm authenticate
+.Nm auth_script
+.Nm auth_env
+.Nm auth_scan
+.Nm auth_rmfiles
+.Nm auth_checknologin
+.Nm auth_cat
+.Nm auth_ttyok
+.Nm auth_hostok
+.Nm auth_timesok
+.Nd Authentication style support library for login class capabilities database.
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <login_cap.h>
+.Ft int
+.Fn authenticate "const char *name" "const char *classname" "const char *style" "const char *service"
+.Ft int
+.Fn auth_script "const char * path" ...
+.Ft int
+.Fn auth_env "void"
+.Ft int
+.Fn auth_scan "int ok"
+.Ft int
+.Fn auth_rmfiles "void"
+.Ft int
+.Fn auth_checknologin "login_cap_t *lc"
+.Ft int
+.Fn auth_cat "const char *file"
+.Ft int
+.Fn auth_ttyok "login_cap_t *lc" "const char *tty"
+.Ft int
+.Fn auth_hostok "login_cap_t *lc" "const char *hostname" "char const *ip"
+.Ft int
+.Fn auth_timesok "login_cap_t *lc" "time_t now"
+.Sh DESCRIPTION
+This set of functions support the login class authorisation style interface provided
+by
+.Xr login.conf 5 .
+
+.Sh RETURN VALUES
+.Sh SEE ALSO
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5 ,
+.Xr getcap 3
diff --git a/lib/libutil/login_auth.c b/lib/libutil/login_auth.c
new file mode 100644
index 0000000..38007b0
--- /dev/null
+++ b/lib/libutil/login_auth.c
@@ -0,0 +1,383 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <login_cap.h>
+#include <stdarg.h>
+#include <paths.h>
+#include <sys/wait.h>
+
+extern char *fgetline(FILE *, int*);
+
+#ifdef RLIM_LONG
+# define STRTOV strtol
+#else
+# define STRTOV strtoq
+#endif
+
+#define AUTHMAXLINES 1024
+#define AUTHMAXARGS 16
+
+struct auth_info {
+ int reject;
+ int auths;
+ int env_count;
+ char **env;
+ int file_count;
+ char **files;
+};
+
+static struct auth_info auth_info;
+
+/*
+ * free_auth_info()
+ * Go through the auth_info structure, and free() anything of interest.
+ * This includes the string arrays, and any individual element.
+ * All part of being environmentally conscious ;).
+ */
+
+static void
+free_auth_info(void)
+{
+ int i;
+ char *ptr;
+
+ auth_info.reject = 0;
+ auth_info.auths = 0;
+ if (auth_info.env) {
+ for (i = 0; i < auth_info.env_count; i++) {
+ if (auth_info.env[i])
+ free(auth_info.env[i]);
+ }
+ free(auth_info.env);
+ auth_info.env = NULL;
+ }
+ if (auth_info.files) {
+ for (i = 0; i < auth_info.file_count; i++) {
+ if (auth_info.files[i])
+ free(auth_info.files[i]);
+ }
+ free(auth_info.files);
+ auth_info.files = NULL;
+ }
+}
+
+
+/*
+ * collect_info()
+ * Read from <fd>, a list of authorization commands.
+ * These commands are:
+ * reject
+ * authorize [root|secure]
+ * setenv <name>[ <value>]
+ * remove <file>
+ * A single reject means the entire thing is bad;
+ * multiple authorize statements can be present (it would be
+ * silly, but that's what the spec says).
+ * The commands are collected, and are accted upon by:
+ * auth_scan() -- check for authorization or rejection
+ * auth_rmfiles() -- remove the specified files
+ * auth_env() -- set the specified environment variables
+ * We only get up to AUTHMAXLINES lines of input from the program.
+ */
+#define STRSIZEOF(x) (sizeof(x)-1)
+static void
+collect_info(int fd)
+{
+ char *line;
+ FILE *fp;
+ char *ptr;
+ int len;
+ int line_count = 0;
+
+ fp = fdopen(fd, "r");
+
+ while ((line = fgetline(fp, &len)) != NULL) {
+ if (++line_count > AUTHMAXLINES)
+ break;
+ if (strncasecmp(line, BI_REJECT, STRSIZEOF(BI_REJECT)) == 0) {
+ auth_info.reject = 1;
+ } else if (strncasecmp(line, BI_AUTH, STRSIZEOF(BI_AUTH)) == 0) {
+ ptr = line + STRSIZEOF(BI_AUTH);
+ ptr += strspn(ptr, " \t");
+ if (!*ptr)
+ auth_info.auths |= AUTH_OKAY;
+ else if (strncasecmp(ptr, BI_ROOTOKAY, STRSIZEOF(BI_ROOTOKAY)) == 0)
+ auth_info.auths |= AUTH_ROOTOKAY;
+ else if (strncasecmp(ptr, BI_SECURE, STRSIZEOF(BI_SECURE)) == 0)
+ auth_info.auths |= AUTH_SECURE;
+ } else if (strncasecmp(line, BI_SETENV, STRSIZEOF(BI_SETENV)) == 0) {
+ ptr = line + STRSIZEOF(BI_SETENV);
+ ptr += strspn(ptr, " \t");
+ if (*ptr) {
+ char **tmp = realloc(auth_info.env, sizeof(char*) * (auth_info.env_count + 1));
+ if (tmp != NULL) {
+ auth_info.env = tmp;
+ if ((auth_info.env[auth_info.env_count] = strdup(ptr)) != NULL)
+ auth_info.env_count++;
+ }
+ }
+ } else if (strncasecmp(line, BI_REMOVE, STRSIZE(BI_REMOVE)) == 0) {
+ ptr = line + STRSIZE(BI_REMOVE);
+ ptr += strspn(ptr, " \t");
+ if (*ptr) {
+ char **tmp = realloc(auth_info.files, sizeof(char*) * (auth_info.file_count + 1));
+ if (tmp != NULL) {
+ auth_info.files = tmp;
+ if ((auth_info.files[auth_info.file_count] = strdup(ptr)) != NULL)
+ auth_info.file_count++;
+ }
+ }
+ }
+ }
+ fclose(fp);
+}
+
+
+/*
+ * authenticate()
+ * Starts an auth_script() for the given <user>, with a class <class>,
+ * style <style>, and service <service>. <style> is necessary,
+ * as are <user> and <class>, but <service> is optional -- it defaults
+ * to "login".
+ * Since auth_script() expects an execl'able program name, authenticate()
+ * also concatenates <style> to _PATH_AUTHPROG.
+ * Lastly, calls auth_scan(AUTH_NONE) to see if there are any "reject" statements,
+ * or lack of "auth" statements.
+ * Returns -1 on error, 0 on rejection, and >0 on success.
+ * (See AUTH_* for the return values.)
+ *
+ */
+int
+authenticate(const char * name, const char * class, const char * style, const char *service)
+{
+ int retval;
+
+ if (style == NULL || *style == '\0')
+ retval = -1;
+ else {
+ char buf[sizeof(_PATH_AUTHPROG) + 64];
+
+ if (service == NULL || *service == '\0')
+ service = LOGIN_DEFSERVICE;
+
+ free_auth_info();
+
+ if (snprintf(buf, sizeof buf, _PATH_AUTHPROG "%s", style) >= sizeof buf)
+ retval = -1;
+ else {
+ retval = auth_script(buf, style, "-s", service, name, class, NULL);
+ if (retval >= 0)
+ retval = auth_scan(AUTH_NONE);
+ }
+ }
+ return retval;
+}
+
+
+/*
+ * auth_script()
+ * Runs an authentication program with specified arguments.
+ * It sets up file descriptor 3 for the program to write to;
+ * it stashes the output somewhere. The output of the program
+ * consists of statements:
+ * reject
+ * authorize [root|secure]
+ * setenv <name> [<value>]
+ * remove <file>
+ *
+ * Terribly exciting, isn't it? There is no limit specified in
+ * BSDi's API for how much output can be present, but we should
+ * keep it fairly small, I think.
+ * No more than AUTHMAXLINES lines.
+ */
+
+int
+auth_script(const char * path, ...)
+{
+ va_list ap;
+ int pid, status;
+ int argc = 0;
+ int p[2]; /* pipes */
+ char *argv[AUTHMAXARGS+1];
+
+ va_start(ap, path);
+ while (argc < AUTHMAXARGS && (argv[argc++] = va_arg(ap, char*)) != NULL)
+ ;
+ argv[argc] = NULL;
+ va_end(ap);
+
+ fflush(NULL);
+
+ if (pipe(p) >= 0) {
+ if ((pid = fork()) == -1) {
+ close(p[0]);
+ close(p[1]);
+ } else if (pid == 0) { /* Child */
+ close(p[0]);
+ dup2(p[1], 3);
+ if (setenv("PATH", _PATH_DEFPATH, 1)==0 && setenv("SHELL", _PATH_BSHELL, 1)==0)
+ execv(path, argv);
+ _exit(1);
+ } else {
+ close(p[1]);
+ collect_info(p[0]);
+ if (waitpid(pid, &status, 0) != -1 && WIFEXITED(status) && !WEXITSTATUS(status))
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * auth_env()
+ * Processes the stored "setenv" lines from the stored authentication
+ * output.
+ */
+
+int
+auth_env(void)
+{
+ int i;
+
+ for (i = 0; i < auth_info.env_count; i++) {
+ char *nam = auth_info.env[i];
+ char *ptr = nam + strcspn(nam, " \t=");
+ if (*ptr) {
+ *ptr++ = '\0';
+ ptr += strspn(ptr, " \t");
+ }
+ setenv(nam, ptr, 1);
+ }
+}
+
+
+/*
+ * auth_scan()
+ * Goes through the output of the auth_script/authenticate, and
+ * checks for a failure or authentication.
+ * <ok> is a default authentication value -- if there are no
+ * rejection or authentication statements, then it is returned
+ * unmodified.
+ * AUTH_NONE is returned if there were any reject statements
+ * from the authentication program (invoked by auth_script()), and
+ * AUTH, AUTH_ROOTOKAY, and/or AUTH_SECURE are returned if the
+ * appropriate directives were found. Note that AUTH* are
+ * *bitmasks*!
+ */
+
+int
+auth_scan(int ok)
+{
+ if (auth_info.reject)
+ return 0;
+ return ok | auth_info.auths;
+}
+
+
+/*
+ * auth_rmfiles()
+ * Removes any files that the authentication program said needed to be
+ * removed, said files having come from a previous execution of
+ * auth_script().
+ */
+
+int
+auth_rmfiles(void)
+{
+ int i = auth_info.file_count;
+ while (i-- > 0) {
+ unlink(auth_info.files[i]);
+ free(auth_info.files[i]);
+ auth_info.files[i] = NULL;
+ }
+}
+
+
+/*
+ * auth_checknologin()
+ * Checks for the existance of a nologin file in the login_cap
+ * capability <lc>. If there isn't one specified, then it checks
+ * to see if this class should just ignore nologin files. Lastly,
+ * it tries to print out the default nologin file, and, if such
+ * exists, it exits.
+ */
+
+void
+auth_checknologin(login_cap_t *lc)
+{
+ char *file;
+
+ /* Do we ignore a nologin file? */
+ if (login_getcapbool(lc, "ignorenologin", 0))
+ return;
+
+ /* Note that <file> will be "" if there is no nologin capability */
+ if ((file = login_getcapstr(lc, "nologin", "", NULL)) == NULL)
+ exit(1);
+
+ /*
+ * *file is true IFF there was a "nologin" capability
+ * Note that auth_cat() returns 1 only if the specified
+ * file exists, and is readable. E.g., /.nologin exists.
+ */
+ if ((*file && auth_cat(file)) || auth_cat(_PATH_NOLOGIN))
+ exit(1);
+}
+
+
+/*
+ * auth_cat()
+ * Checks for the readability of <file>; if it can be opened for
+ * reading, it prints it out to stdout, and then exits. Otherwise,
+ * it returns 0 (meaning no nologin file).
+ */
+int
+auth_cat(const char *file)
+{
+ int fd, count;
+ char buf[BUFSIZ];
+
+ if ((fd = open(file, O_RDONLY)) < 0)
+ return 0;
+ while ((count = read(fd, buf, sizeof(buf))) > 0)
+ write(fileno(stdout), buf, count);
+ close(fd);
+ return 1;
+}
diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3
new file mode 100644
index 0000000..3fbf3a6
--- /dev/null
+++ b/lib/libutil/login_cap.3
@@ -0,0 +1,378 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" 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. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd December 27, 1996
+.Os FreeBSD
+.Dt LOGIN_CAP 3
+.Sh NAME
+.Nm login_getclassbyname ,
+.Nm login_close ,
+.Nm login_getclass ,
+.Nm login_getuserclass ,
+.Nm login_getcapstr ,
+.Nm login_getcaplist ,
+.Nm login_getcaptime ,
+.Nm login_getcapnum ,
+.Nm login_getcapsize ,
+.Nm login_getcapbool ,
+.Nm login_getstyle
+.Nd functions for accessing the login class capabilities database.
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <login_cap.h>
+.Ft void
+.Fn login_close "login_cap_t * lc"
+.Ft login_cap_t *
+.Fn login_getclassbyname "const char *nam" "const char *dir"
+.Ft login_cap_t *
+.Fn login_getclass "const struct passwd *pwd"
+.Ft login_cap_t *
+.Fn login_getuserclass "const struct passwd *pwd"
+.Ft char *
+.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "char *def" "char *error"
+.Ft char **
+.Fn login_getcaplist "login_cap_t *lc" "const char *cap" "const char *chars"
+.Ft char *
+.Fn login_getpath "login_cap_t *lc" "const char *cap" "char *error"
+.Ft rlim_t
+.Fn login_getcaptime "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
+.Ft rlim_t
+.Fn login_getcapnum "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
+.Ft rlim_t
+.Fn login_getcapsize "login_cap_t *lc" const "char *cap" "rlim_t def" "rlim_t error"
+.Ft int
+.Fn login_getcapbool "login_cap_t *lc" "const char *cap" "int def"
+.Ft char *
+.Fn login_getstyle "login_cap_t *lc" "char *style" "const char *auth"
+.Pp
+.Sh DESCRIPTION
+These functions represent a programming interface to the login
+classes database provided in
+.Xr login.conf 5 .
+This database contains capabilities, attributes and default environment
+and accounting settings for users and programs running as specific users,
+as determined by the login class field within entries in
+.Pa /etc/master.passwd .
+.Pp
+Entries in
+.Xr login.conf 5
+consist of colon
+.Ql \&:
+separated fields, the first field in each record being one or more
+identifiers for the record which must be unique for the entire database
+each separated by a '|' and may optionally include a description as
+the last 'name'.
+Remaining fields in the record consist of keyword/data pairs.
+Long lines may be continued with a backslash within empty entries
+with the second and subsequent lines optionally indented for readability.
+This is similar to the format used in
+.Xr termcap 5
+except that keywords are not limited to two significant characters,
+and are usually longer for improved readability.
+As with termcap entries, multiple records can be linked together
+(one record including another) using a field containing tc=<recordid>,
+the result is that the entire record referenced by <recordid> replaces
+the tc= field at the point at which it occurs.
+See
+.Xr getcap 3
+for further details on the format and use of a capabilities database.
+.Pp
+The
+.Nm login_cap
+interface provides a convenient means of retrieving login class
+records with all tc= references expanded.
+A program will typically call one of
+.Fn login_getclass ,
+.Fn login_getuserclass
+or
+.Fn login_getclassbyname
+according to its requirements.
+Each of these functions returns a login capabilities structure,
+.Ft login_cap_t
+which may subsequently be used to interrogate the database for
+specific values using the rest of the API.
+Once the login_cap_t is of no further use, the
+.Fn login_close
+function should be called to free all resources used.
+.Pp
+The structure of login_cap_t is defined in login_cap.h, as:
+.Bd -literal -offset indent
+typedef struct {
+ char *lc_class;
+ char *lc_cap;
+ char *lc_style;
+} login_cap_t;
+.Ed
+.Pp
+The
+.Ar lc_class
+member contains a pointer to the name of the login class
+retrieved.
+This may not necessarily be the same as the one requested,
+either directly via
+.Fn login_getclassbyname ,
+or indirectly via a user's login record using
+.Fn login_getclass
+or
+.Fn login_getuserclass .
+If the referenced user has no login class specified in
+.Pa /etc/master.passwd ,
+the class name is NULL or an empty string, or if the class
+specified does not exist in the database, each of these
+functions will search for a record with an id of "default",
+with that name returned in the
+.Ar lc_class
+field.
+.Pp
+The
+.Ar lc_cap
+field is used internally by the library to contain the
+expanded login capabilities record.
+Programs with unusual requirements may wish to use this
+with the lower-level
+.Fn getcap
+style functions to access the record directly.
+.Pp
+The
+.Ar lc_style
+field is set by the
+.Fn login_getstyle
+function to the authorisation style according to the requirements
+of the program handling a login itself.
+.Pp
+As noted above, the
+.Fn get*class
+functions return a login_cap_t object which is used to access
+the matching or default record in the capabilities database.
+.Fn getclassbyname
+accepts two arguments: the first one is the record identifier of the
+record to be retrieved, the second being an optional directory name.
+If the first
+.Ar name
+argument is NULL, an empty string, or a class that does not exist
+in the supplimental or system login class database, then the system
+.Em default
+record is returned instead.
+If the second
+.Ar dir
+parameter is NULL, then only the system login class database is
+used, but when not NULL, the named directory is searched for
+a login database file called ".login.conf", and capability records
+contained within it may override the system defaults.
+This scheme allows users to override some login settings from
+those in the system login class database by creating class records
+for their own private class with a record id of `me'.
+In the context of a
+.Em login ,
+it should be noted that some options cannot by overridden by
+users for two reasons; many options, such as resource settings
+and deafult process priorities, require root privileges
+in order to take effect, and other fields in the user's file are
+not be consulted at all during the early phases of login for
+security or administrative reasons.
+See
+.Xr login.conf 5
+for more information on which settings a user is able to override.
+Typically, these are limited purely to the user's default login
+environment which might otherwise have been overridden in shell
+startup scripts in any case.
+The user's
+.Pa .login.conf
+merely provides a convenient way for a user to set up their preferred
+login environment before the shell is invoked on login.
+.Pp
+If the specified record is NULL, empty or does not exist, and the
+system has no "default" record available to fallback, there is a
+memory allocation error or for some reason
+.Xr cgetent 3
+is unable to access the login capabilities database, this function
+returns NULL.
+.Pp
+The functions
+.Fn login_getclass
+and
+.Fn login_getuserclass
+retrieve the applicable login class record for the user's passwd
+entry by calling
+.Fn login_getclassbyname .
+On failure, NULL is returned.
+The difference between the two functions is that
+.Fn login_getuserclass
+includes the user's overriding
+.Pa .login.conf
+that exists in the user's home directory, while
+.Fn login_getclass
+restricts itself only to the system login class database in
+.Pa /etc/login.conf .
+In either case, if the passwd pointer is NULL, or the user has
+no class, then the system "default" entry is retrieved.
+.Pp
+Once a program no longer wishes to use a login_cap_t object,
+.Fn login_close
+may be called to free all resources used by the login class.
+.Fn login_close
+may be passed a NULL pointer with no harmful side-effects.
+.Pp
+The remaining functions may be used to retrieve individual
+capability records.
+Each function takes a login_cap_t object as its first parameter,
+a capability tag as the second, and remaining parameters being
+default and error values that are returned if the capability is
+not found.
+The type of the additional parameters passed and returned depend
+on the
+.Em type
+of capability each deals with, be it a simple string, a list,
+a time value, a file or memory size value, a path (consisting of
+a colon-separated list of directories) or a boolean flag.
+The manpage for
+.Xr login.conf 5
+deals in specific tags and their type.
+.Pp
+Note that with all functions in this group, you should not call
+.Xr free 3
+on any pointers returned.
+Memory allocated during retrieval or processing of capability
+tags is automatically reused by subsequent calls to functions
+in this group, or deallocated on calling
+.Fn login_close .
+.Bl -tag -width "login_getcaplist()"
+.It Fn login_getcapstr
+This function returns a simple string capability.
+If the string is not found, then the value in
+.Ar def
+is returned as the default value, or if an error
+occurs, the value in the
+.Ar error
+parameter is returned.
+.It Fn login_getcaplist
+This function returns the value corresponding to the named
+capability tag as a list of values in a NULL terminated
+array.
+Within the login class database, some tags are of type
+.Em list ,
+which consist of one or more comma- or space separated
+values.
+Usually, this function is not called directly from an
+application, but is used indirectly via
+.Fn login_getstyle .
+.It Fn login_getpath
+This function returns a list of directories separated by colons
+.Ql &: .
+Capability tags for which this function is called consist of a list of
+directories separated by spaces.
+.It Fn login_getcaptime
+This function returns a
+.Em time value
+associated with a particular capability tag with the value expressed
+in seconds (the default), minutes, hours, days, weeks or (365 day)
+years or any combination of these.
+A suffix determines the units used: S for seconds, M for minutes,
+H for hours, D for days, W for weeks and Y for 365 day years.
+Case of the units suffix is ignored.
+.Pp
+Time values are normally used for setting resource, accounting and
+session limits.
+If supported by the operating system and compiler (which is true of
+FreeBSD), the value returned is a quad (long long), of type
+.Em rlim_t .
+A value "inf" or "infinity" may be used to express an infinite
+value, in which case RLIM_INFINITY is returned.
+.It Fn login_getcapnum
+This function returns a numeric value for a tag, expressed either as
+tag=<value> or the standard
+.Fn cgetnum
+format tag#<value>.
+The first format should be used in preference to the second, the
+second format is provided for compatibility and consistency with the
+.Xr getcap 3
+database format where numeric types use the
+.Ql \&#
+as the delimiter for numeric values.
+If in the first format, then the value given may be "inf" or
+"infinity" which results in a return value of RLIM_INFINITY.
+If the given capability tag cannot be found, the
+.Ar def
+parameter is returned, and if an error occurs, the
+.Ar error
+parameter is returned.
+.It Fn login_getcapsize
+.Fn login_getcapsize
+returns a value representing a size (typicially, file or memory)
+which may be expressed as bytes (the default), 512 byte blocks,
+kilobytes, megabytes, gigabytes, and on systems that support the
+.Ar long long
+type, terrabytes.
+The suffix used determines the units, and multiple values and
+units may be used in combination (e.g. 1m500k = 1.5 megabytes).
+A value with no suffix is interpreted as bytes, B as 512-byte
+blocks, K as kilobytes, M as megabytes, G as gigabytes and T as
+terrabytes.
+Case is ignored.
+The error value is returned if there is a login capabilities database
+error, if an invalid suffix is used, or if a numeric value cannot be
+interpreted.
+.It Fn login_getcapbool
+This function returns a boolean value tied to a particular flag.
+It returns 0 if the given capability tag is not present or is
+negated by the presence of a "tag@" (See
+.Xr getcap 3
+for more information on boolean flags), and returns 1 if the tag
+is found.
+.It Fn login_getstyle
+This function is used by the login authorisation system to determine
+the style of login available in a particular case.
+The function accepts three parameters, the login_cap entry itself and
+two optional parameters, and authorisation type 'auth' and 'style', and
+applies these to determine the authorisation style that best suites
+these rules.
+.Bl -bullet -indent offset
+.It
+If 'auth' is neither NULL nor an empty string, look for a tag of type
+"auth-<auth>" in the capability record.
+If not present, then look for the default default tag "auth=".
+.It
+If no valid authorisation list was found from the previous step, then
+default to "passwd" as the authorisation list.
+.It
+If 'style' is not NULL or empty, look for it in the list of authorisation
+methods found from the pprevious step.
+If 'style' is NULL or an empty string, then default to "passwd"
+authorisation.
+.It
+If 'style' is found in the chosen list of authorisation methods, then
+return that, otherwise return NULL.
+.El
+.Pp
+This scheme allows the administrator to determine the types of
+authorisation methods accepted by the system, depending on the
+means by which the access occurs.
+For example, the administrator may require skey or kerberos as
+the authentication method used for access to the system via the
+network, and standard methods via direct dialup or console
+logins, significantly reducing the risk of password discovery
+by "snooping" network packets.
+.El
+.Sh SEE ALSO
+.Xr login_class 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5 ,
+.Xr getcap 3
diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c
new file mode 100644
index 0000000..21ff02f1
--- /dev/null
+++ b/lib/libutil/login_cap.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <login_cap.h>
+
+#ifdef RLIM_LONG
+# define STRTOV strtol
+#else
+# define STRTOV strtoq
+#endif
+
+static int lc_object_count = 0;
+
+static size_t internal_stringsz = 0;
+static char * internal_string = NULL;
+static size_t internal_arraysz = 0;
+static char ** internal_array = NULL;
+
+static char *
+allocstr(char * str)
+{
+ char * p;
+ size_t sz = strlen(str) + 1; /* realloc() only if necessary */
+ if (sz <= internal_stringsz)
+ p = internal_string;
+ else if ((p = realloc(internal_string, sz)) != NULL) {
+ internal_stringsz = sz;
+ internal_string = strcpy(p, str);
+ }
+ return p;
+}
+
+static char **
+allocarray(size_t sz)
+{
+ char ** p;
+ if (sz <= internal_arraysz)
+ p = internal_array;
+ else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
+ internal_arraysz = sz;
+ internal_array = p;
+ }
+ return p;
+}
+
+
+/*
+ * arrayize()
+ * Turn a simple string <str> seperated by any of
+ * the set of <chars> into an array. The last element
+ * of the array will be NULL, as is proper.
+ * Free using freearraystr()
+ */
+
+static char **
+arrayize(char *str, const char *chars, int *size)
+{
+ int i;
+ char *ptr;
+ char **res = NULL;
+
+ for (i = 0, ptr = str; *ptr; i++) {
+ int count = strcspn(ptr, chars);
+ ptr = ptr + count + 1;
+ }
+
+ if ((ptr = allocstr(str)) == NULL) {
+ res = NULL;
+ i = 0;
+ } else if ((res = allocarray(++i)) == NULL) {
+ free(str);
+ i = 0;
+ } else {
+ for (i = 0; *ptr; i++) {
+ int count = strcspn(ptr, chars);
+ res[i] = ptr;
+ ptr += count;
+ if (*ptr)
+ *ptr++ = '\0';
+ }
+ res[i] = 0;
+ }
+ if (size)
+ *size = i;
+ return res;
+}
+
+static void
+freearraystr(char ** array)
+{
+ /*
+ * the array[0] should be free'd, and then array.
+ */
+ if (array) {
+ free(array[0]);
+ free(array);
+ }
+}
+
+
+/*
+ * login_close()
+ * Frees up all resources relating to a login class
+ *
+ */
+
+void
+login_close(login_cap_t * lc)
+{
+ if (lc) {
+ free(lc->lc_style);
+ free(lc->lc_class);
+ free(lc);
+ if (--lc_object_count == 0) {
+ free(internal_string);
+ free(internal_array);
+ internal_array = NULL;
+ internal_string = NULL;
+ cgetclose();
+ }
+ }
+}
+
+
+/*
+ * login_getclassbyname() get the login class by its name.
+ * If the name given is NULL or empty, the default class
+ * LOGIN_DEFCLASS (ie. "default") is fetched. If the
+ * 'dir' argument contains a non-NULL non-empty string,
+ * then the file _FILE_LOGIN_CONF is picked up from that
+ * directory instead of the system login database.
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclassbyname(char const * name, char const * dir)
+{
+ login_cap_t *lc = malloc(sizeof(login_cap_t));
+
+ if (lc != NULL) {
+ int i = 0;
+ char userpath[MAXPATHLEN];
+ static char *login_dbarray[] = { NULL, NULL, NULL };
+
+ if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN)
+ login_dbarray[i++] = userpath;
+ else
+ login_dbarray[i++] = _PATH_LOGIN_CONF;
+ login_dbarray[i ] = NULL;
+
+ lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
+
+ if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) &&
+ cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) {
+ free(lc);
+ lc = NULL;
+ } else {
+ ++lc_object_count;
+ lc->lc_class = strdup(name);
+ }
+ }
+
+ return lc;
+}
+
+
+
+/*
+ * login_getclass()
+ * Get the login class for a given password entry from
+ * the system (only) login class database.
+ * If the password entry's class field is not set, or
+ * the class specified does not exist, then use the
+ * default of LOGIN_DEFCLASS (ie. "default").
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclass(const struct passwd *pwd)
+{
+ const char * class = (pwd == NULL) ? NULL : pwd->pw_class;
+ if (pwd->pw_class == NULL || *pwd->pw_class == '\0')
+ class = (pwd->pw_uid == 0) ? "root" : NULL; /* Kludge for 'root' user(s) */
+ return login_getclassbyname(class, 0);
+}
+
+
+/*
+ * login_getuserclass()
+ * Get the login class for a given password entry, allowing user
+ * overrides via ~/.login_conf.
+ * ### WAS: If the password entry's class field is not set,
+ * ####### or the class specified does not exist, then use
+ * If an entry with the recordid "me" does not exist, then use
+ * the default of LOGIN_DEFCLASS (ie. "default").
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getuserclass(const struct passwd *pwd)
+{
+ const char * class = "me"; /* (pwd == NULL) ? NULL : pwd->pw_class; */
+ const char * home = (pwd == NULL) ? NULL : pwd->pw_dir;
+ return login_getclassbyname(class, home);
+}
+
+
+
+/*
+ * login_getcapstr()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability, a defualt if not found, or
+ * an error string on error.
+ */
+
+char *
+login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
+{
+ char *res;
+ int ret;
+
+ if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
+ return def;
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
+ return def;
+ } else if (ret >= 0)
+ return res;
+ else
+ return error;
+}
+
+
+/*
+ * login_getcaplist()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability split into an array of
+ * strings.
+ */
+
+char **
+login_getcaplist(login_cap_t *lc, const char * cap, const char * chars)
+{
+ char * lstring;
+
+ if (chars == NULL)
+ chars = ". \t";
+ if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL)
+ return arrayize(lstring, chars, NULL);
+ return NULL;
+}
+
+
+/*
+ * login_getpath()
+ * From the login_cap_t <lc>, get the capability <cap> which is
+ * formatted as either a space or comma delimited list of paths
+ * and append them all into a string and separate by semicolons.
+ * If there is an error of any kind, return <error>.
+ */
+
+char *
+login_getpath(login_cap_t *lc, const char *cap, char * error)
+{
+ char *ptr, *str = login_getcapstr(lc, (char*)cap, NULL, NULL);
+
+ if (str == NULL || (ptr = allocstr(str)) == NULL)
+ str = error;
+ else {
+ while (*ptr) {
+ int count = strcspn(ptr, ", \t");
+ ptr += count;
+ if (*ptr)
+ *ptr++ = ':';
+ }
+ }
+ return str;
+}
+
+
+/*
+ * login_getcaptime()
+ * From the login_cap_t <lc>, get the capability <cap>, which is
+ * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
+ * present in <lc>, return <def>; if there is an error of some kind,
+ * return <error>.
+ */
+
+rlim_t
+login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *res, *ep;
+ int ret;
+ rlim_t tot = 0, tim;
+
+ errno = 0;
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * Look for <cap> in lc_cap.
+ * If it's not there (-1), return <def>.
+ * If there's an error, return <error>.
+ */
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
+ return def;
+ else if (ret < 0)
+ return error;
+
+ /*
+ * "inf" and "infinity" are two special cases for this.
+ */
+ if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
+ return RLIM_INFINITY;
+
+ /*
+ * Now go through the string, turning something like 1h2m3s into
+ * an integral value. Whee.
+ */
+
+ errno = 0;
+ while (*res) {
+ tim = STRTOV(res, &ep, 0);
+ if ((ep == NULL) || (ep == res) || errno) {
+ return error;
+ }
+ /* Look for suffixes */
+ switch (*ep++) {
+ case 0:
+ ep--; break; /* end of string */
+ case 's': case 'S': /* seconds */
+ break;
+ case 'm': case 'M': /* minutes */
+ tim *= 60L;
+ break;
+ case 'h': case 'H': /* hours */
+ tim *= (60L * 60L);
+ break;
+ case 'd': case 'D': /* days */
+ tim *= (60L * 60L * 24L);
+ break;
+ case 'w': case 'W': /* weeks */
+ tim *= (60L * 60L * 24L * 7L);
+ case 'y': case 'Y': /* Years */
+ /* I refuse to take leap years into account here. Sue me. */
+ tim *= (60L * 60L * 24L * 365L);
+ default:
+ return error;
+ }
+ res = ep;
+ tot += tim;
+ }
+ return tot;
+}
+
+
+/*
+ * login_getcapnum()
+ * From the login_cap_t <lc>, extract the numerical value <cap>.
+ * If it is not present, return <def> for a default, and return
+ * <error> if there is an error.
+ * Like login_getcaptime(), only it only converts to a number, not
+ * to a time; "infinity" and "inf" are 'special.'
+ */
+
+rlim_t
+login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *ep, *res;
+ int ret;
+ rlim_t val;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * For BSDI compatibility, try for the tag=<val> first
+ */
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
+ long lval;
+ /*
+ * String capability not present, so try for tag#<val> as numeric
+ */
+ if ((ret = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1)
+ return def; /* Not there, so return default */
+ else if (ret < 0)
+ return error;
+ return (rlim_t)lval;
+ }
+ else if (ret < 0)
+ return error;
+
+ if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
+ return RLIM_INFINITY;
+
+ errno = 0;
+ val = STRTOV(res, &ep, 0);
+ if ((ep == NULL) || (ep == res) || errno)
+ return error;
+ return val;
+}
+
+
+/*
+ * login_getcapsize()
+ * From the login_cap_t <lc>, extract the capability <cap>, which is
+ * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
+ * If not present, return <def>, or <error> if there is an error of
+ * some sort.
+ */
+
+rlim_t
+login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) {
+ char *ep, *res;
+ int ret;
+ rlim_t val;
+ rlim_t mult;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
+ return def;
+ else if (ret < 0)
+ return error;
+
+ errno = 0;
+ val = STRTOV(res, &ep, 0);
+ if ((res == NULL) || (res == ep) || errno)
+ return error;
+ switch (*ep) {
+ case 0: /* end of string */
+ mult = 1; break;
+ case 'b': case 'B': /* 512-byte blocks */
+ mult = 512; break;
+ case 'k': case 'K': /* 1024-byte Kilobytes */
+ mult = 1024; break;
+ case 'm': case 'M': /* 1024-k kbytes */
+ mult = 1024 * 1024; break;
+ case 'g': case 'G': /* 1Gbyte */
+ mult = 1024 * 1024 * 1024; break;
+#ifndef RLIM_LONG
+ case 't': case 'T': /* 1TBte */
+ mult = 1024LL * 1024LL * 1024LL * 1024LL; break;
+#endif
+ default:
+ return error;
+ }
+ return val * mult;
+}
+
+
+/*
+ * login_getcapbool()
+ * From the login_cap_t <lc>, check for the existance of the capability
+ * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
+ * the whether or not <cap> exists there.
+ */
+
+int
+login_getcapbool(login_cap_t *lc, const char *cap, int def)
+{
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+ return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL);
+}
+
+
+/*
+ * login_getstyle()
+ * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
+ * and optionally a style <style>, find the style that best suits these
+ * rules:
+ * 1. If <auth> is non-null, look for an "auth-<auth>=" string
+ * in the capability; if not present, default to "auth=".
+ * 2. If there is no auth list found from (1), default to
+ * "passwd" as an authorization list.
+ * 3. If <style> is non-null, look for <style> in the list of
+ * authorization methods found from (2); if <style> is NULL, default
+ * to LOGIN_DEFSTYLE ("passwd").
+ * 4. If the chosen style is found in the chosen list of authorization
+ * methods, return that; otherwise, return NULL.
+ * E.g.:
+ * login_getstyle(lc, NULL, "ftp");
+ * login_getstyle(lc, "login", NULL);
+ * login_getstyle(lc, "skey", "network");
+ */
+
+char *
+login_getstyle(login_cap_t *lc, char *style, const char *auth)
+{
+ int i;
+ char **authtypes = NULL;
+ char *auths= NULL;
+ char realauth[64];
+
+ static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
+
+ if (auth != NULL && *auth != '\0' &&
+ snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth)
+ authtypes = login_getcaplist(lc, realauth, NULL);
+
+ if (authtypes == NULL)
+ authtypes = login_getcaplist(lc, "auth", NULL);
+
+ if (authtypes == NULL)
+ authtypes = defauthtypes;
+
+ /*
+ * We have at least one authtype now; auths is a comma-seperated
+ * (or space-separated) list of authentication types. We have to
+ * convert from this to an array of char*'s; authtypes then gets this.
+ */
+ i = 0;
+ if (style != NULL && *style != '\0') {
+ while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
+ i++;
+ }
+ lc->lc_style = NULL;
+ if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
+ lc->lc_style = auths;
+
+ return lc->lc_style;
+}
+
+
diff --git a/lib/libutil/login_class.3 b/lib/libutil/login_class.3
new file mode 100644
index 0000000..370bfbf
--- /dev/null
+++ b/lib/libutil/login_class.3
@@ -0,0 +1,187 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" 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. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd December 28, 1996
+.Os FreeBSD
+.Dt LOGIN_CLASS 3
+.Sh NAME
+.Nm setclasscontext ,
+.Nm setusercontext ,
+.Nm setclassresources ,
+.Nm setclassenvironment
+.Nd functions for using the login class capabilities database.
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <login_cap.h>
+.Ft int
+.Fn setclasscontext "char *classname" "unsigned int flags"
+.Ft int
+.Fn setusercontext "login_cap_t *lc" "const struct passwd *pwd" "uid_t uid" "unsigned int flags"
+.Ft void
+.Fn setclassresources "login_cap_t *lc"
+.Ft void
+.Fn setclassenvironment "login_cap_t *lc" "const struct passwd *pwd" "int paths"
+.Pp
+.Sh DESCRIPTION
+These functions provide a higher level interface to the login class
+database than those documented in
+.Xr login_cap 3 .
+These functions are used to set resource limits, environment and
+accounting settings for users on logging into the system and when
+selecting an appropriate set of environment and resource settings
+for system daemons based on login classes.
+These functions may only be called if the current process is
+running with root priviledges.
+If the LOGIN_SETLOGIN flag is used this function calls
+.Xr setlogin 2 ,
+and due care must be taken as detailed in the manpage for that
+function and this affects all processes running in the same session
+and not just the current process.
+.Pp
+.Fn setclasscontext
+sets various class context values (resource limits, umask and
+process priorities) based on values for a specific named class.
+.Pp
+The function
+.Fn setusercontext
+sets class context values based on a given login_cap_t
+object, a specific passwd record (if login_cap_t is NULL),
+sets the current session's login and the current process
+user and group ownership.
+Each of these functions is selectable via bit-flags passed
+in the
+.Ar flags
+parameter, which is comprised of one or more of the following:
+.Bl -tag -width LOGIN_SETRESOURCES
+.It LOGIN_SETLOGIN
+Set the login associated with the current session to the user
+specified in the passwd structure.
+.Xr setlogin 2 .
+The
+.Ar pwd
+parameter must not be NULL if this option is used.
+.It LOGIN_SETUSER
+Set ownship of the current process to the uid specified in the
+.Ar uid
+parameter using
+.Xr setuid 2 .
+.It LOGIN_SETGROUP
+Set group ownership of the current process to the group id
+specified in the passwd structure using
+.Xr setgid 2 ,
+and calls
+.Xr initgroups 3
+to set up the group access list for the current process.
+The
+.Ar pwd
+parameter must not be NULL if this option is used.
+.It LOGIN_SETRESOURCES
+Set resource limits for the current process based on values
+specified in the system login class database.
+Class capability tags used, with and without -cur (soft limit)
+or -max (hard limit) suffixes and the corresponding resource
+setting:
+.Bd -literal
+cputime RLIMIT_CPU
+filesize RLIMIT_FSIZE
+datasize RLIMIT_DATA
+stacksize RLIMIT_STACK
+coredumpsize RLIMIT_CORE
+memoryuse RLIMIT_RSS
+memorylocked RLIMIT_MEMLOCK
+maxproc RLIMIT_NPROC
+openfiles RLIMIT_NOFILE
+.Ed
+.It LOGIN_SETPRIORITY
+Set the scheduling priority for the current process based on the
+value specified in the system login class database.
+Class capability tags used:
+.Bd -literal
+priority
+.Ed
+.It LOGIN_SETUMASK
+Set the umask for the current process to a value in the user or
+system login class database.
+Class capability tags used:
+.Bd -literal
+umask
+.Ed
+.It LOGIN_SETPATH
+Set the "path" and "manpath" environment variables based on values
+in the user or system login class database.
+Class capability tags used with the corresponding environment
+variables set:
+.Bd -literal
+path PATH
+manpath MANPATH
+.Ed
+.It LOGIN_SETENV
+Set various environment variables based on values in the user or
+system login class database.
+Class capability tags used with the corresponding environment
+variables set:
+.Bd -literal
+lang LANG
+charset MM_CHARSET
+timezone TZ
+term TERM
+.Ed
+.Pp
+Additional environment variables may be set using the list type
+capability "setenv=var1 val1,var2 val2..,varN valN".
+.It LOGIN_SETALL
+Enables all of the above settings.
+.El
+.Pp
+Note that when setting environment variables and a valid passwd
+pointer is provided in the
+.Ar pwd
+parameter, the characters
+.Ql \&~
+and
+.Ql \&$
+are substituted for the user's home directory and login name
+respectively.
+.Pp
+The
+.Fn setclassresources
+and
+.Fn setclassenvironment
+functions are subsets of the setcontext functions above, but may
+be useful in isolation.
+.Sh RETURN VALUES
+.Fn setclasscontext
+and
+.Fn setusercontext
+return -1 if an error occured, or 0 on success.
+If an error occurs when attempting to set the user, login, group
+or resources, a message is reported to
+.Xr syslog 3 ,
+with LOG_ERR priority and directed to the currently active facility.
+.Sh SEE ALSO
+.Xr setlogin 2 ,
+.Xr setuid 2 ,
+.Xr setgid 2 ,
+.Xr initgroups 3 ,
+.Xr login_cap 3 ,
+.Xr login.conf 5 ,
+.Xr termcap 5 ,
+.Xr getcap 3
diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c
new file mode 100644
index 0000000..1dc6cc4
--- /dev/null
+++ b/lib/libutil/login_class.c
@@ -0,0 +1,371 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * High-level routines relating to use of the user capabilities database
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <login_cap.h>
+#include <paths.h>
+
+
+#undef UNKNOWN
+#define UNKNOWN "su"
+
+
+static struct login_res {
+ const char * what;
+ rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
+ int why;
+} resources[] = {
+ { "cputime", login_getcaptime, RLIMIT_CPU },
+ { "filesize", login_getcapsize, RLIMIT_FSIZE },
+ { "datasize", login_getcapsize, RLIMIT_DATA },
+ { "stacksize", login_getcapsize, RLIMIT_STACK },
+ { "coredumpsize", login_getcapsize, RLIMIT_CORE },
+ { "memoryuse", login_getcapsize, RLIMIT_RSS },
+ { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
+ { "maxproc", login_getcapnum, RLIMIT_NPROC },
+ { "openfiles", login_getcapnum, RLIMIT_NOFILE },
+ { NULL, 0, 0 }
+};
+
+
+
+void
+setclassresources(login_cap_t *lc)
+{
+ struct login_res *lr = resources;
+
+ while (lr->what != NULL) {
+ struct rlimit rlim,
+ newlim;
+ char cur[40],
+ max[40];
+ rlim_t rcur,
+ rmax;
+
+ sprintf(cur, "%s-cur", lr->what);
+ sprintf(max, "%s-max", lr->what);
+
+ /*
+ * The login.conf file can have <limit>, <limit>-max, and
+ * <limit>-cur entries.
+ * What we do is get the current current- and maximum- limits.
+ * Then, we try to get an entry for <limit> from the capability,
+ * using the current and max limits we just got as the
+ * default/error values.
+ * *Then*, we try looking for <limit>-cur and <limit>-max,
+ * again using the appropriate values as the default/error
+ * conditions.
+ */
+
+ getrlimit(lr->why, &rlim);
+ rcur = rlim.rlim_cur;
+ rmax = rlim.rlim_max;
+
+ rcur = (*lr->who)(lc, lr->what, rcur, rcur);
+ rmax = (*lr->who)(lc, lr->what, rmax, rmax);
+ newlim.rlim_cur = (*lr->who)(lc, cur, rcur, rcur);
+ newlim.rlim_max = (*lr->who)(lc, max, rmax, rmax);
+
+ if (setrlimit(lr->why, &newlim) == -1)
+ syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
+
+ ++lr;
+ }
+}
+
+static struct login_vars {
+ const char * tag;
+ const char * var;
+ const char * def;
+} pathvars[] = {
+ { "path", "PATH", NULL },
+ { "manpath", "MANPATH", NULL },
+ { NULL, NULL, NULL }
+}, envars[] = {
+ { "lang", "LANG", NULL },
+ { "charset", "MM_CHARSET", NULL },
+ { "timezone", "TZ", NULL },
+ { "term", "TERM", UNKNOWN },
+ { NULL, NULL, NULL }
+};
+
+static char *
+substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
+{
+ char * np = NULL;
+
+ if (var != NULL) {
+ int tildes = 0;
+ int dollas = 0;
+ char * p;
+
+ if (pwd != NULL) {
+ /*
+ * Count the number of ~'s in var to substitute
+ */
+ p = var;
+ while ((p = strchr(p, '~')) != NULL) {
+ ++tildes;
+ ++p;
+ }
+
+ /*
+ * Count the number of $'s in var to substitute
+ */
+ p = var;
+ while ((p = strchr(p, '$')) != NULL) {
+ ++dollas;
+ ++p;
+ }
+ }
+
+ np = malloc(strlen(var) + (dollas * nlen) - dollas + (tildes * (pch+hlen)) - tildes + 1);
+
+ if (np != NULL) {
+ p = strcpy(np, var);
+
+ if (pwd != NULL) {
+ /*
+ * This loop does user username and homedir substitutions
+ * for unescaped $ (username) and ~ (homedir)
+ */
+ while (*(p += strcspn(p, "~$")) != '\0') {
+ int l = strlen(p);
+
+ if (p > var && *(p-1) == '\\') /* Escaped: */
+ memmove(p - 1, p, l + 1); /* Slide-out the backslash */
+ else if (*p == '~') {
+ memmove(p + 1, p + hlen + pch, l); /* Subst homedir */
+ memmove(p, pwd->pw_dir, hlen);
+ if (pch)
+ p[hlen] = '/';
+ p += hlen + pch;
+ }
+ else /* if (*p == '$') */ {
+ memmove(p + 1, p + nlen, l); /* Subst username */
+ memmove(p, pwd->pw_name, nlen);
+ p += nlen;
+ }
+ }
+ }
+ }
+ }
+ return np;
+}
+
+
+void
+setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
+{
+ struct login_vars * vars = paths ? pathvars : envars;
+ int hlen = pwd ? strlen(pwd->pw_dir) : 0;
+ int nlen = pwd ? strlen(pwd->pw_name) : 0;
+ char pch = 0;
+
+ if (hlen && pwd->pw_dir[hlen-1] != '/')
+ ++pch;
+
+ while (vars->tag != NULL) {
+ char * var = paths ? login_getpath(lc, vars->tag, NULL)
+ : login_getcapstr(lc, vars->tag, NULL, NULL);
+
+ char * np = substvar(var, pwd, hlen, pch, nlen);
+
+ if (np != NULL) {
+ setenv(vars->var, np, 1);
+ free(np);
+ } else if (vars->def != NULL) {
+ setenv(vars->var, vars->def, 0);
+ }
+ ++vars;
+ }
+
+ /*
+ * If we're not processing paths, then see if there is a setenv list by
+ * which the admin and/or user may set an arbitrary set of env vars.
+ */
+ if (!paths) {
+ char ** set_env = login_getcaplist(lc, "setenv", ",");
+ if (set_env != NULL) {
+ while (*set_env != NULL) {
+ char *p = strchr(*set_env, '=');
+ if (p != NULL) {
+ char * np = substvar(set_env[1], pwd, hlen, pch, nlen);
+ if (np != NULL) {
+ setenv(set_env[0], np, 1);
+ free(np);
+ }
+ }
+ ++set_env;
+ }
+ }
+ }
+
+}
+
+
+/*
+ * setclasscontext()
+ *
+ * For the login class <class>, set various class context values
+ * (limits, mainly) to the values for that class. Which values are
+ * set are controlled by <flags> -- see <login_class.h> for the
+ * possible values.
+ *
+ * setclasscontext() can only set resources, priority, and umask.
+ */
+
+int
+setclasscontext(const char *classname, unsigned int flags)
+{
+ int rc;
+ login_cap_t * lc = login_getclassbyname(classname, NULL);
+ flags &= (LOGIN_SETRESOURCES| LOGIN_SETPRIORITY|LOGIN_SETUMASK);
+ rc = setusercontext(lc, NULL, 0, flags);
+ login_close(lc);
+ return rc;
+}
+
+
+/*
+ * setusercontext()
+ *
+ * Given a login class <lc> and a user in <pwd>, with a uid <uid>,
+ * set the context as in setclasscontext(). <flags> controls which
+ * values are set.
+ *
+ * The difference between setclasscontext() and setusercontext() is
+ * that the former sets things up for an already-existing process,
+ * while the latter sets things up from a root context. Such as might
+ * be called from login(1).
+ *
+ */
+
+int
+setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
+{
+ int i;
+ login_cap_t * llc = NULL;
+
+ if (lc == NULL)
+ {
+ if (pwd == NULL || (lc = login_getclass(pwd)) == NULL) {
+ return -1;
+ }
+ llc = lc; /* free this when we're done */
+ }
+
+ if (flags & LOGIN_SETPATH)
+ pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;
+
+ /*
+ * Set the process priority
+ */
+ if (flags & LOGIN_SETPRIORITY) {
+ int pri = (int)login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
+ pri = (pri < PRIO_MIN) ? PRIO_MIN : (pri > PRIO_MAX) ? PRIO_MAX : pri;
+ if (setpriority(PRIO_PROCESS, 0, pri) != 0)
+ syslog(LOG_WARNING, "setpriority '%s': %m", pwd->pw_name);
+ }
+
+ /*
+ * Set resources
+ */
+ if (flags & LOGIN_SETRESOURCES)
+ setclassresources(lc);
+
+ /*
+ * Set the sessions login
+ */
+ if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
+ syslog(LOG_ERR, "setlogin '%s': %m", pwd->pw_name);
+ login_close(llc);
+ return -1; /* You can't be too paranoid */
+ }
+
+ /*
+ * Setup the user's group permissions
+ */
+ if (flags & LOGIN_SETGROUP) {
+ /* XXX is it really a good idea to let errors here go? */
+ if (setgid(pwd->pw_gid) != 0)
+ syslog(LOG_WARNING, "setgid %ld: %m", (long)pwd->pw_gid);
+ if (initgroups(pwd->pw_name, pwd->pw_gid) == -1)
+ syslog(LOG_WARNING, "initgroups '%s': %m", pwd->pw_name);
+ }
+
+ /*
+ * This needs to be done after all of the above.
+ */
+ if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
+ syslog(LOG_ERR, "setuid %ld: %m", uid);
+ login_close(llc);
+ return -1; /* Paranoia again */
+ }
+
+ /*
+ * FreeBSD extension: here we (might) loop and do this twice.
+ * First, for the class we have been given, and next for
+ * any user overrides in ~/.login.conf the user's home directory.
+ */
+ if (flags & LOGIN_SETUMASK)
+ umask(LOGIN_DEFUMASK); /* Set default umask up front */
+
+ i = 0;
+ while (i < 2 && lc != NULL) {
+
+ if (flags & LOGIN_SETUMASK) {
+ rlim_t tmp = login_getcapnum(lc, "umask", RLIM_INFINITY, RLIM_INFINITY);
+ if (tmp != RLIM_INFINITY)
+ umask((mode_t)tmp);
+ }
+
+ if (flags & LOGIN_SETPATH)
+ setclassenvironment(lc, pwd, 1);
+
+ if (flags & LOGIN_SETENV)
+ setclassenvironment(lc, pwd, 0);
+
+ if (i++ == 0) /* Play it again, Sam */
+ lc = (pwd == NULL) ? NULL : login_getuserclass(pwd);
+ }
+
+ login_close(lc); /* User's private 'me' class */
+ login_close(llc); /* Class we opened */
+
+ return 0;
+}
+
diff --git a/lib/libutil/login_ok.3 b/lib/libutil/login_ok.3
new file mode 100644
index 0000000..c459d94
--- /dev/null
+++ b/lib/libutil/login_ok.3
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" 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. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd January 2, 1997
+.Os FreeBSD
+.Dt LOGIN_OK 3
+.Sh NAME
+.Nm auth_ttyok
+.Nm auth_hostok
+.Nm auth_timeok
+.Nd Functions for checking login class based login restrictions
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <time.h>
+.Fd #include <login_cap.h>
+.Ft int
+.Fn auth_ttyok "login_cap_t *lc" "const char *tty"
+.Ft int
+.Fn auth_hostok "login_cap_t *lc" "const char *host" "char const *ip"
+.Ft int
+.Fn auth_timeok "login_cap_t *lc" "time_t t"
+.Sh DESCRIPTION
+This set of functions checks to see if login is allowed based on login
+class capability entries in the login database,
+.Xr login.conf 5 .
+.Pp
+.Fn auth_ttyok
+checks to see if the named tty is available to users of a specific
+class, and is either in the "ttys.allow" access list, and not in
+the "ttys.deny" access list.
+An empty "ttys.allowed" list (or if no such capability exists for
+the give login class) logins via any tty device are allowed unless
+the "ttys.deny" list exists and is non-empty, and the device or its
+tty group (see
+.Xr ttys 5 )
+is not in the list.
+Access to ttys may be allowed or restricted specifically by tty device
+name, a device name which includes a wildcard (e.g. ttyD* or cuaD*),
+or may name a ttygroup, when group=<name> tags have been assigned in
+.Pa /etc/ttys .
+Matching of ttys and ttygroups is case sensitive.
+Passing a NULL or empty string as the
+.Ar tty
+parameter causes the function to return a non-zero value.
+.Pp
+.Fn auth_hostok
+checks for any host restrictions for remote logins.
+The function checks on both a host name and IP address (given in its
+text form, typically n.n.n.n) against the "host.allow" and "host.deny"
+login class capabilities.
+As with ttys and their groups, wildcards and character classes may be
+used in the host allow and deny capability records.
+The
+.Xr fnmatch 3
+function is used for matching, and the matching on hostnames is case
+insensitive.
+Note that this function expects that the hostname is fully expanded
+(i.e. the local domain name added if necessary) and the IP address
+is in its canonical form.
+No hostname or address lookups are attempted.
+.Pp
+It is possible to call this function with either the hostname or
+the IP address missing (i.e. NULL) and matching will be performed
+only on the basis of the parameter given.
+Passing NULL or empty strings in both parameters will result in
+a non-zero return value.
+.Pp
+The
+.Fn auth_timeok
+function checks to see that a given time value is within the
+"times.allow" login class capability and not within the
+"times.deny" access lists.
+An empty or non-existent "times.allow" list allows access at any
+time, except if a given time is falls within a period in the
+"times.deny" list.
+The format of time period records contained in both "times.allow"
+and "times.deny" capability fields is explained in detail in the
+.Xr login_times 3
+manual page.
+.Sh RETURN VALUES
+A non-zero return value from any of these functions indicates that
+login access is granted.
+A zero return value means either that the item being tested is not
+in the "allow" access list, or is within the "deny" access list.
+.Sh SEE ALSO
+.Xr login.conf 5 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr login_times 3 ,
+.Xr termcap 5 ,
+.Xr getcap 3
diff --git a/lib/libutil/login_ok.c b/lib/libutil/login_ok.c
new file mode 100644
index 0000000..cf778da
--- /dev/null
+++ b/lib/libutil/login_ok.c
@@ -0,0 +1,242 @@
+/*-
+ * Copyright (c) 1996 by
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Support allow/deny lists in login class capabilities
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ttyent.h>
+#include <fnmatch.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <login_cap.h>
+
+
+/* -- support functions -- */
+
+/* login_strinlist()
+ * This function is intentionally public - reused by TAS.
+ * Returns TRUE (non-zero) if a string matches a pattern
+ * in a given array of patterns. 'flags' is passed directly
+ * to fnmatch(3).
+ */
+
+int
+login_strinlist(char **list, char const *str, int flags)
+{
+ int rc = 0;
+
+ if (str != NULL && *str != '\0')
+ {
+ int i = 0;
+ while (rc == 0 && list[i] != NULL)
+ rc = fnmatch(list[i], str, flags) == 0;
+ }
+ return rc;
+}
+
+
+/* login_str2inlist()
+ * Locate either or two strings in a given list
+ */
+
+int
+login_str2inlist(char **ttlst, const char *str1, const char *str2, int flags)
+{
+ int rc = 0;
+
+ if (login_strinlist(ttlst, str1, flags))
+ rc = 1;
+ else if (login_strinlist(ttlst, str2, flags))
+ rc = 1;
+ return rc;
+}
+
+
+/* login_timelist()
+ * This function is intentinoally public - reused by TAS.
+ * Returns an allocated list of time periods given an array
+ * of time periods in ascii form.
+ */
+
+login_time_t *
+login_timelist(login_cap_t *lc, char const *cap, int *ltno, login_time_t **ltptr)
+{
+ int j = 0;
+ struct login_time * lt = NULL;
+ char **tl = login_getcaplist(lc, cap, NULL);
+
+ if (tl)
+ {
+ while (tl[j++] != NULL)
+ ;
+ if (*ltno >= j)
+ lt = *ltptr;
+ else if ((lt = realloc(*ltptr, j)) != NULL)
+ {
+ *ltno = j;
+ *ltptr = lt;
+ }
+ if (lt != NULL)
+ {
+ int i = 0;
+ --j;
+ while (i < j)
+ {
+ lt[i] = parse_lt(tl[i]);
+ ++i;
+ }
+ lt[i].lt_dow = LTM_NONE;
+ }
+ }
+ return lt;
+}
+
+
+/* login_ttyok()
+ * This function is a variation of auth_ttyok(), but it checks two
+ * arbitrary capability lists not necessarily related to access.
+ * This hook is provided for the accounted/exclude accounting lists.
+ */
+
+int
+login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap, const char *denycap)
+{
+ int rc = 1;
+
+ if (lc != NULL && tty != NULL && *tty != '\0')
+ {
+ struct ttyent * te = getttynam(tty); /* Need group name */
+ char * grp = te ? te->ty_group : NULL;
+ char **ttl = login_getcaplist(lc, allowcap, NULL);
+
+ if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0))
+ rc = 0; /* tty or ttygroup not in allow list */
+ else
+ {
+ ttl = login_getcaplist(lc, denycap, NULL);
+ if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
+ rc = 0; /* tty or ttygroup in deny list */
+ }
+ }
+ return rc;
+}
+
+
+/* auth_ttyok()
+ * Determine whether or not login on a tty is accessible for
+ * a login class
+ */
+
+int
+auth_ttyok(login_cap_t *lc, const char * tty)
+{
+ return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
+}
+
+
+/* login_hostok()
+ * This function is a variation of auth_hostok(), but it checks two
+ * arbitrary capability lists not necessarily related to access.
+ * This hook is provided for the accounted/exclude accounting lists.
+ */
+
+int
+login_hostok(login_cap_t *lc, const char *host, const char *ip, const char *allowcap, const char *denycap)
+{
+ int rc = 1; /* Default is ok */
+
+ if (lc != NULL && ((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0')))
+ {
+ char **hl = login_getcaplist(lc, allowcap, NULL);
+
+ if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD))
+ rc = 0; /* host or IP not in allow list */
+ else
+ {
+ hl = login_getcaplist(lc, "host.deny", NULL);
+ if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
+ rc = 0; /* host or IP in deny list */
+ }
+ }
+ return rc;
+}
+
+
+/* auth_hostok()
+ * Determine whether or not login from a host is ok
+ */
+
+int
+auth_hostok(login_cap_t *lc, const char *host, const char *ip)
+{
+ return login_hostok(lc, host, ip, "host.allow", "host.deny");
+}
+
+
+/* auth_timeok()
+ * Determine whether or not login is ok at a given time
+ */
+
+int
+auth_timeok(login_cap_t *lc, time_t t)
+{
+ int rc = 1; /* Default is ok */
+
+ if (lc != NULL && t != (time_t)0 && t != (time_t)-1)
+ {
+ struct tm * tptr = localtime(&t);
+
+ static int ltimesno = 0;
+ static struct login_time * ltimes = NULL;
+
+ if (tptr != NULL)
+ {
+ struct login_time *lt = login_timelist(lc, "times.allow", &ltimesno, &ltimes);
+
+ if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
+ rc = 0; /* not in allowed times list */
+ else
+ {
+ lt = login_timelist(lc, "times.deny", &ltimesno, &ltimes);
+
+ if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
+ rc = 0; /* in deny times list */
+ }
+ if (ltimes)
+ {
+ free(ltimes);
+ ltimes = NULL;
+ ltimesno = 0;
+ }
+ }
+ }
+ return rc;
+}
+
diff --git a/lib/libutil/login_times.3 b/lib/libutil/login_times.3
new file mode 100644
index 0000000..d8e1156
--- /dev/null
+++ b/lib/libutil/login_times.3
@@ -0,0 +1,155 @@
+.\" Copyright (c) 1995 David Nugent <davidn@blaze.net.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" 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. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" David Nugent.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $Id$
+.\"
+.Dd January 2, 1997
+.Os FreeBSD
+.Dt LOGIN_TIMES 3
+.Sh NAME
+.Nm parse_lt
+.Nm in_ltm
+.Nm in_ltms
+.Nd Functions for parsing and checking login time periods
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <time.h>
+.Fd #include <login_cap.h>
+.Ft login_time_t
+.Fn parse_lt "const char *str"
+.Ft int
+.Fn in_ltm "const login_time_t *lt" "struct tm *t" "time_t *ends"
+.Ft int
+.Fn in_ltms "const login_time_t *lt" "struct tm *t" "time_t *ends"
+.Sh DESCRIPTION
+This set of functions may be used for parsing and checking login and
+session times against a predefined list of allowed login times as
+used in
+.Xr login.conf 5 .
+.Pp
+The format of allowed and disallowed session times specified in the
+.Ar times.allow
+and
+.Ar times.deny
+capability fields in a login class are comprised of a prefix which
+specifies one or more 2- or 3-character day codes, followed by
+a start and end time in 24 hour format separated by a hyphen.
+Day codes may be concatenated together to select specific days, or
+the special mnemonics "Any" and "All" (for any/all days of the week),
+"Wk" for any day of the week (excluding Saturdays and Sundays) and
+"Wd" for any weekend day may be used.
+.Pp
+For example, the following time period:
+.Dl MoThFrSa1400-2200
+is interpreted as Monday, Thursday through Saturday between the hours
+of 2pm and 10pm.
+.Dl Wd0600-1800
+means Saturday and Sunday, between the hours of 6am through 6pm, and
+.Dl Any0400-1600
+means any day of the week, between 4am and 4pm.
+.Pp
+Note that all time periods reference system local time.
+.Pp
+The
+.Fn parse_lt
+function converts the ascii representation of a time period into
+a structure of type
+.Ft login_time_t .
+This is defined as:
+.Bd -literal
+typedef struct login_time
+{
+ u_short lt_start; /* Start time */
+ u_short lt_end; /* End time */
+ u_char lt_dow; /* Days of week */
+} login_time_t;
+.Ed
+.Pp
+The
+.Ar lt_start
+and
+.Ar lt_end
+fields contain the number of minutes past midnight at which the
+described period begins and ends.
+The
+.Ar lt_dow
+field is a bit field, containing one bit for each day of the week
+and one bit unused.
+A series
+.Em LTM_*
+macros may be used for testing bits individually and in combination.
+If no bits are set in this field - ie. it contains the value
+.Em LTM_NONE -
+then the entire period is assumed invalid.
+This is used as a convention to mark the termination of an array
+of login_time_t values.
+If
+.Fn parse_lt
+returns a
+.Ar login_time_t
+with
+.Ar lt_dow
+equal to
+.Em LTM_NONE
+then a parsing error was encountered.
+.Pp
+The remaining functions provide the ability to test a given time_t or
+struct tm value against a specific time period or array of time
+periods.
+.Fn in_ltm
+determines whether the given time described by the struct tm
+passed as the second parameter falls within the period described
+by the first parameter.
+A boolean value is returned, indicating whether or not the time
+specified falls within the period.
+If the time does fall within the time period, and the third
+parameter to the function is not NULL, the time at which the
+period ends relative to the time passed is returned.
+.Pp
+The
+.Fn in_ltms
+function is similar to
+.Fn in_ltm
+except that the first parameter must be a pointer to an array
+of login_time_t objects, which is up to LC_MAXTIMES (64)
+elements in length, and terminated by an element with its
+.Ar lt_dow
+field set to
+.Em LTM_NONE.
+.Sh RETURN VALUES
+.Fn parse_lt
+returns a filled in structure of type login_time_t containing the
+parsed time period.
+If a parsing error occurs, the lt_dow field is set to
+.Em LTM_NONE
+(i.e. 0).
+.Pp
+.Fn in_ltm
+returns non-zero if the given time falls within the period described
+by the login_time_t passed as the first parameter.
+.Pp
+.Fn in_ltms
+returns the index of the first time period found in which the given
+time falls, or -1 if none of them apply.
+.Sh SEE ALSO
+.Xr login.conf 5 ,
+.Xr login_cap 3 ,
+.Xr login_class 3 ,
+.Xr termcap 5 ,
+.Xr getcap 3
diff --git a/lib/libutil/login_times.c b/lib/libutil/login_times.c
new file mode 100644
index 0000000..098200e
--- /dev/null
+++ b/lib/libutil/login_times.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1996 by
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Login period parsing and comparison functions.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include <login_cap.h>
+
+static struct
+{
+ const char * dw;
+ u_char cn;
+ u_char fl;
+} dws[] =
+{
+ { "su", 2, LTM_SUN }, { "mo", 2, LTM_MON }, { "tu", 2, LTM_TUE },
+ { "we", 2, LTM_WED }, { "th", 2, LTM_THU }, { "fr", 2, LTM_FRI },
+ { "sa", 2, LTM_SAT }, { "any",3, LTM_ANY }, { "all",3, LTM_ANY },
+ { "wk", 2, LTM_WK }, { "wd", 2, LTM_WD }, { NULL, 0, 0 }
+};
+
+static char *
+parse_time(char * ptr, u_short * t)
+{
+ u_short val;
+
+ for (val = 0; *ptr && isdigit(*ptr); ptr++)
+ val = (u_short)(val * 10 + (*ptr - '0'));
+
+ *t = (u_short)((val / 100) * 60 + (val % 100));
+ return ptr;
+}
+
+login_time_t
+parse_lt(const char * str)
+{
+ login_time_t t;
+
+ memset(&t, 0, sizeof t);
+ t.lt_dow = LTM_NONE;
+ if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0)
+ {
+ int i;
+ login_time_t m = t;
+ char * p;
+ char buf[64];
+
+ /* Make local copy and force lowercase to simplify parsing
+ */
+ p = strncpy(buf, str, sizeof buf);
+ buf[sizeof buf - 1] = '\0';
+ for (i = 0; buf[i]; i++)
+ buf[i] = (char)tolower(buf[i]);
+
+ while (isalpha(*p))
+ {
+ for (i = 0; dws[i].dw && strncmp(p, dws[i].dw, dws[i].cn) != 0 ; i++)
+ ;
+ if (dws[i].dw == NULL)
+ break;
+ m.lt_dow |= dws[i].fl;
+ p += dws[i].cn;
+ }
+
+ if (m.lt_dow == LTM_NONE) /* No (valid) prefix, assume any */
+ m.lt_dow |= LTM_ANY;
+
+ if (isdigit(*p))
+ p = parse_time(p, &m.lt_start);
+ else
+ m.lt_start = 0;
+ if (*p == '-')
+ p = parse_time(++p, &m.lt_end);
+ else
+ m.lt_end = 1440;
+
+ t = m;
+ }
+ return t;
+}
+
+
+int
+in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
+{
+ int rc = 0;
+
+ if (tt != NULL)
+ {
+ /* First, examine the day of the week
+ */
+ if ((u_char)(0x01 << tt->tm_wday) & ltm->lt_dow)
+ {
+ /* Convert `current' time to minute of the day
+ */
+ u_short now = (u_short)((tt->tm_hour * 60) + tt->tm_min);
+ if (tt->tm_sec > 30)
+ ++now;
+ if (now >= ltm->lt_start && now < ltm->lt_end)
+ {
+ rc = 2;
+ if (ends != NULL)
+ {
+ /* If requested, return ending time for this period
+ */
+ tt->tm_hour = (int)(ltm->lt_end / 60);
+ tt->tm_min = (int)(ltm->lt_end % 60);
+ *ends = mktime(tt);
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+int
+in_lt(const login_time_t * ltm, time_t * t)
+{
+ return in_ltm(ltm, localtime(t), t);
+}
+
+int
+in_ltms(const login_time_t * ltm, struct tm * tm, time_t * t)
+{
+ int i = 0;
+
+ while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE)
+ {
+ if (in_ltm(ltm + i, tm, t))
+ return i;
+ i++;
+ }
+ return -1;
+}
+
+int
+in_lts(const login_time_t * ltm, time_t * t)
+{
+ return in_ltms(ltm, localtime(t), t);
+}
+
OpenPOWER on IntegriCloud