Library functions relating to the login class capabilities database,
including manpages. See also login_cap.h.
This commit is contained in:
parent
a87a87a21c
commit
68bbf3adb0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=21288
@ -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
71
lib/libutil/login_auth.3
Normal 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
383
lib/libutil/login_auth.c
Normal 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
378
lib/libutil/login_cap.3
Normal 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
564
lib/libutil/login_cap.c
Normal 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
187
lib/libutil/login_class.3
Normal 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
371
lib/libutil/login_class.c
Normal 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
109
lib/libutil/login_ok.3
Normal 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
242
lib/libutil/login_ok.c
Normal 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", <imesno, <imes);
|
||||
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
|
||||
rc = 0; /* not in allowed times list */
|
||||
else
|
||||
{
|
||||
lt = login_timelist(lc, "times.deny", <imesno, <imes);
|
||||
|
||||
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
155
lib/libutil/login_times.3
Normal 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
166
lib/libutil/login_times.c
Normal 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user