Library functions relating to the login class capabilities database,

including manpages.
See also login_cap.h.
This commit is contained in:
David Nugent 1997-01-04 16:50:08 +00:00
parent a87a87a21c
commit 68bbf3adb0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=21288
11 changed files with 2644 additions and 2 deletions

View File

@ -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 \

71
lib/libutil/login_auth.3 Normal file
View File

@ -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

383
lib/libutil/login_auth.c Normal file
View File

@ -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;
}

378
lib/libutil/login_cap.3 Normal file
View File

@ -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

564
lib/libutil/login_cap.c Normal file
View File

@ -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;
}

187
lib/libutil/login_class.3 Normal file
View File

@ -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

371
lib/libutil/login_class.c Normal file
View File

@ -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;
}

109
lib/libutil/login_ok.3 Normal file
View File

@ -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

242
lib/libutil/login_ok.c Normal file
View File

@ -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;
}

155
lib/libutil/login_times.3 Normal file
View File

@ -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

166
lib/libutil/login_times.c Normal file
View File

@ -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);
}