Summary of login.conf support changes:
o Incorporated BSDI code and enhancements, better logging for error checking (which has been shown to be a problem, and is therefore justified, imho); also some minor things we were missing, including better quad_t math, which checks for under/overflows. o setusercontext() now allows user resource limit overrides, but does this AFTER dropping root privs, to restrict the user to droping hard limits and set soft limits within the kernel's allowed user limits. o umask() only set once, and only if requested. o add _secure_path(), and use in login.conf to guard against symlinks etc. and non-root owned or non-user owned files being used. Derived from BSDI contributed code. o revamped authentication code to BSDI's latest api, which includes deleting authenticate() and adding auth_check() and a few other functions. This is still marked as depecated in BSDI, but is included for completeness. No other source in the tree uses this anyway, so it is now bracketed with #ifdef LOGIN_CAP_AUTH which is by default not defined. Only auth_checknologin() and auth_cat() are actually used in module login_auth.c. o AUTH_NONE definition removed (collided with other includes in the tree). [bde] o BSDI's login_getclass() now accepts a char *classname parameter rather than struct passwd *pwd. We now do likewise, but added login_getpwclass() for (sort of) backwards compatiblity, namely because we handle root as a special case for the default class. This will require quite a few changes elsewhere in the source tree. o We no longer pretend to support rlim_t as a long type. o Revised code formatting to be more bsd-ish style.
This commit is contained in:
parent
fa2887ae7f
commit
56c0434453
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=25670
@ -4,11 +4,13 @@ LIB= util
|
||||
SHLIB_MAJOR= 2
|
||||
SHLIB_MINOR= 2
|
||||
CFLAGS+=-Wall -DLIBC_SCCS -I${.CURDIR} -I/sys
|
||||
#CFLAGS+=LOGIN_CAP_AUTH
|
||||
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 \
|
||||
uucplock.c
|
||||
_secure_path.c uucplock.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 uucplock.3
|
||||
login_cap.3 login_class.3 login_times.3 login_ok.3 \
|
||||
_secure_path.3 uucplock.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 \
|
||||
|
70
lib/libutil/_secure_path.3
Normal file
70
lib/libutil/_secure_path.3
Normal file
@ -0,0 +1,70 @@
|
||||
.\" Copyright (c) 1997 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 May 2, 1997
|
||||
.Os FreeBSD
|
||||
.Dt _SECURE_PATH 3
|
||||
.Sh NAME
|
||||
.Nm _secure_path
|
||||
.Nd determine if a file appears to be secure
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sys/types.h>
|
||||
.Fd #include <libutil.h>
|
||||
.Ft int
|
||||
.Fn _secure_path "const char *path" "uid_t uid" "gid_t gid"
|
||||
.Pp
|
||||
.Sh DESCRIPTION
|
||||
This function does some basic security checking on a given path.
|
||||
It is intended to be used by processes running with root privileges
|
||||
in order to decide whether or not to trust the contents of a given
|
||||
file.
|
||||
It uses a method often used to detect system compromise.
|
||||
.Pp
|
||||
A file is considered 'secure' if it meets the following conditions:
|
||||
.Bl -enum
|
||||
.It
|
||||
The file exists, and is a regular file (not a symlink, device
|
||||
special or named pipe, etc.),
|
||||
.It
|
||||
Is not world writable.
|
||||
.It
|
||||
Is owned by the given uid, if uid is not -1,
|
||||
.It
|
||||
Is not group wriable or it has group ownership by the given
|
||||
gid, if gid is not -1.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
This function returns zero if the file exists and may be
|
||||
considered secure, -2 if the file does not exist, and
|
||||
-1 otherwise to indicate a security failure.
|
||||
.Xr syslog 3 ,
|
||||
is used to log any failure of this function, including the
|
||||
reason, at LOG_ERR priority.
|
||||
.Sh BUGS
|
||||
The checks carried out are rudamentary and no attempt is made
|
||||
to eliminate race conditions between use of this function and
|
||||
access to the file referenced.
|
||||
.Sh SEE ALSO
|
||||
.Xr lstat 3 ,
|
||||
.Xr syslog 3 .
|
||||
.Sh HISTORY
|
||||
Code from which this function was derived was contributed to the
|
||||
FreeBSD project by Berkeley Software Design, Inc.
|
72
lib/libutil/_secure_path.c
Normal file
72
lib/libutil/_secure_path.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* Based on code copyright (c) 1995,1997 by
|
||||
* Berkeley Software Design, Inc.
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
|
||||
/*
|
||||
* Check for common security problems on a given path
|
||||
* It must be:
|
||||
* 1. A regular file, and exists
|
||||
* 2. Owned and writaable only by root (or given owner)
|
||||
* 3. Group ownership is given group or is non-group writable
|
||||
*
|
||||
* Returns: -2 if file does not exist,
|
||||
* -1 if security test failure
|
||||
* 0 otherwise
|
||||
*/
|
||||
|
||||
int
|
||||
_secure_path(const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
int r = -1;
|
||||
struct stat sb;
|
||||
const char *msg = NULL;
|
||||
|
||||
if (lstat(path, &sb) < 0) {
|
||||
if (errno == ENOENT) /* special case */
|
||||
r = -2; /* if it is just missing, skip the log entry */
|
||||
else
|
||||
msg = "%s: cannot stat %s: %m";
|
||||
}
|
||||
else if (!S_ISREG(sb.st_mode))
|
||||
msg = "%s: %s is not a regular file";
|
||||
else if (sb.st_mode & S_IWOTH)
|
||||
msg = "%s: %s is world writable";
|
||||
else if (uid != -1 && sb.st_uid != uid) {
|
||||
if (uid == 0)
|
||||
msg = "%s: %s is not owned by root";
|
||||
else
|
||||
msg = "%s: %s is not owned by uid %d";
|
||||
} else if (gid != -1 && sb.st_gid != gid && (sb.st_mode & S_IWGRP))
|
||||
msg = "%s: %s is group writeable by non-authorised groups";
|
||||
else
|
||||
r = 0;
|
||||
if (msg != NULL)
|
||||
syslog(LOG_ERR, msg, "_secure_path", path, uid);
|
||||
return r;
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* $Id: libutil.h,v 1.5 1997/03/30 12:11:27 brian Exp $
|
||||
* $Id: libutil.h,v 1.6 1997/03/31 22:47:53 brian Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LIBUTIL_H_
|
||||
@ -44,6 +44,7 @@ int forkpty __P((int *amaster, char *name,
|
||||
char *uu_lockerr __P((int uu_lockresult));
|
||||
int uu_lock __P((char *ttyname));
|
||||
int uu_unlock __P((char *ttyname));
|
||||
int _secure_path __P((const char *path, uid_t uid, gid_t gid));
|
||||
__END_DECLS
|
||||
|
||||
#define UU_LOCK_INUSE (1)
|
||||
|
@ -4,6 +4,10 @@
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions copyright (c) 1995,1997 by
|
||||
* Berkeley Software Design, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -21,17 +25,19 @@
|
||||
*
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*
|
||||
* $Id$
|
||||
* $Id: login_auth.c,v 1.6 1997/02/22 15:08:18 peter Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -40,297 +46,575 @@
|
||||
#include <login_cap.h>
|
||||
#include <stdarg.h>
|
||||
#include <paths.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <err.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#ifdef RLIM_LONG
|
||||
# define STRTOV strtol
|
||||
#else
|
||||
# define STRTOV strtoq
|
||||
#endif
|
||||
#ifdef LOGIN_CAP_AUTH
|
||||
/*
|
||||
* Comment from BSDI's authenticate.c module:
|
||||
* NOTE: THIS MODULE IS TO BE DEPRECATED. FUTURE VERSIONS OF BSD/OS WILL
|
||||
* HAVE AN UPDATED API, THOUGH THESE FUNCTIONS WILL CONTINUE TO BE AVAILABLE
|
||||
* FOR BACKWARDS COMPATABILITY
|
||||
*/
|
||||
|
||||
#define AUTHMAXLINES 1024
|
||||
#define AUTHMAXARGS 16
|
||||
|
||||
struct auth_info {
|
||||
int reject;
|
||||
int auths;
|
||||
int env_count;
|
||||
char **env;
|
||||
int file_count;
|
||||
char **files;
|
||||
#define AUTHMAXSPOOL (8 * 1024) /* Max size of authentication data */
|
||||
#define AUTHCOMM_FD 3 /* Handle used to read/write auth data */
|
||||
|
||||
struct rmfiles {
|
||||
struct rmfiles *next;
|
||||
char file[1];
|
||||
};
|
||||
|
||||
static struct auth_info auth_info;
|
||||
struct authopts {
|
||||
struct authopts *next;
|
||||
char opt[1];
|
||||
};
|
||||
|
||||
static char *spoolbuf = NULL;
|
||||
static int spoolidx = 0;
|
||||
static struct rmfiles *rmfirst = NULL;
|
||||
static struct authopts *optfirst = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* 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 ;).
|
||||
* Setup a known environment for all authentication scripts.
|
||||
*/
|
||||
|
||||
static void
|
||||
free_auth_info(void)
|
||||
{
|
||||
int i;
|
||||
static char *auth_environ[] = {
|
||||
"PATH=" _PATH_DEFPATH,
|
||||
"SHELL=" _PATH_BSHELL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
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]);
|
||||
|
||||
|
||||
/*
|
||||
* nextline()
|
||||
* Get the next line from the data buffer collected from
|
||||
* the authentication program. This function relies on the
|
||||
* fact that lines are nul terminated.
|
||||
*/
|
||||
|
||||
static char *
|
||||
nextline(int *idx)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
|
||||
if (spoolbuf != NULL && *idx < spoolidx) {
|
||||
ptr = spoolbuf + *idx;
|
||||
*idx += strlen(ptr) + 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* spooldata()
|
||||
* Read data returned on authentication backchannel and
|
||||
* stuff it into our spool buffer. We also replace \n with nul
|
||||
* to make parsing easier later.
|
||||
*/
|
||||
#define STRSIZEOF(x) (sizeof(x)-1)
|
||||
static void
|
||||
collect_info(int fd)
|
||||
|
||||
static int
|
||||
spooldata(int fd)
|
||||
{
|
||||
char *line;
|
||||
FILE *fp;
|
||||
char *ptr;
|
||||
size_t len;
|
||||
int line_count = 0;
|
||||
|
||||
fp = fdopen(fd, "r");
|
||||
if (spoolbuf)
|
||||
free(spoolbuf);
|
||||
spoolidx = 0;
|
||||
|
||||
while ((line = fgetln(fp, &len)) != NULL) {
|
||||
if (++line_count > AUTHMAXLINES)
|
||||
break;
|
||||
if (len && line[len-1] == '\n')
|
||||
--len;
|
||||
line[len] = '\0'; /* Terminate */
|
||||
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++;
|
||||
if (spoolbuf == NULL && (spoolbuf = malloc(AUTHMAXSPOOL)) == NULL)
|
||||
syslog(LOG_ERR, "authbuffer malloc: %m");
|
||||
|
||||
else while (spoolidx < sizeof(spoolbuf) - 1) {
|
||||
int r = read(fd, spoolbuf + spoolidx, sizeof(spoolbuf)-spoolidx);
|
||||
char *b;
|
||||
|
||||
if (r <= 0) {
|
||||
spoolbuf[spoolidx] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (strncasecmp(line, BI_REMOVE, STRSIZEOF(BI_REMOVE)) == 0) {
|
||||
ptr = line + STRSIZEOF(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++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convert newlines into NULs to allow
|
||||
* easier scanning of the file.
|
||||
*/
|
||||
while ((b = memchr(spoolbuf + spoolidx, '\n', r)) != NULL)
|
||||
*b = '\0';
|
||||
spoolidx += r;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* authenticate()
|
||||
* auth_check()
|
||||
* 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,
|
||||
* Lastly, calls auth_scan(0) 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)
|
||||
auth_check(const char *name, const char *clss, const char *style,
|
||||
const char *service, int *status)
|
||||
{
|
||||
int retval;
|
||||
int _status;
|
||||
|
||||
if (style == NULL || *style == '\0')
|
||||
retval = -1;
|
||||
else {
|
||||
char buf[sizeof(_PATH_AUTHPROG) + 64];
|
||||
if (status == NULL)
|
||||
status = &_status;
|
||||
*status = 0;
|
||||
|
||||
if (service == NULL || *service == '\0')
|
||||
service = LOGIN_DEFSERVICE;
|
||||
if (style != NULL) {
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
free_auth_info();
|
||||
if (service == NULL)
|
||||
service = LOGIN_DEFSERVICE;
|
||||
|
||||
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);
|
||||
snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
|
||||
if (auth_script(path, style, "-s", service, name, clss, 0))
|
||||
status = 0;
|
||||
else
|
||||
*status = auth_scan(0);
|
||||
|
||||
return *status & AUTH_ALLOW;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
auth_response(const char *name, const char *class, const char *style,
|
||||
const char *service, int *status,
|
||||
const char *challenge, const char *response)
|
||||
{
|
||||
int _status;
|
||||
|
||||
if (status == NULL)
|
||||
status = &_status;
|
||||
*status = 0;
|
||||
|
||||
if (style != NULL) {
|
||||
int datalen;
|
||||
char *data;
|
||||
|
||||
if (service == NULL)
|
||||
service = LOGIN_DEFSERVICE;
|
||||
|
||||
datalen = strlen(challenge) + strlen(response) + 2;
|
||||
|
||||
if ((data = malloc(datalen)) == NULL) {
|
||||
syslog(LOG_ERR, "auth_response: %m");
|
||||
warnx("internal resource failure");
|
||||
} else {
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(data, datalen, "%s%c%s", challenge, 0, response);
|
||||
snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
|
||||
if (auth_script_data(data, datalen, path, style, "-s", service,
|
||||
name, class, 0))
|
||||
*status = 0;
|
||||
else
|
||||
*status = auth_scan(0);
|
||||
free(data);
|
||||
return (*status & AUTH_ALLOW);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
auth_approve(login_cap_t *lc, const char *name, const char *service)
|
||||
{
|
||||
int r = -1;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (lc == NULL) {
|
||||
if (strlen(name) > MAXPATHLEN) {
|
||||
syslog(LOG_ERR, "%s: username too long", name);
|
||||
warnx("username too long");
|
||||
} else {
|
||||
struct passwd *pwd;
|
||||
char *p;
|
||||
|
||||
pwd = getpwnam(name);
|
||||
if (pwd == NULL && (p = strchr(name, '.')) != NULL) {
|
||||
int i = p - name;
|
||||
|
||||
if (i >= MAXPATHLEN)
|
||||
i = MAXPATHLEN - 1;
|
||||
strncpy(path, name, i);
|
||||
path[i] = '\0';
|
||||
pwd = getpwnam(path); /* Fixed bug in BSDI code... */
|
||||
}
|
||||
if ((lc = login_getpwclass(pwd ? pwd->pw_class : NULL)) == NULL)
|
||||
warnx("unable to classify user '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
if (lc != NULL) {
|
||||
char *approve;
|
||||
char *s;
|
||||
|
||||
if (service != NULL)
|
||||
service = LOGIN_DEFSERVICE;
|
||||
|
||||
snprintf(path, sizeof(path), "approve-%s", service);
|
||||
|
||||
if ((approve = login_getcapstr(lc, s = path, NULL, NULL)) == NULL &&
|
||||
(approve = login_getcapstr(lc, s = "approve", NULL, NULL)) == NULL)
|
||||
r = AUTH_OKAY;
|
||||
else {
|
||||
|
||||
if (approve[0] != '/') {
|
||||
syslog(LOG_ERR, "Invalid %s script: %s", s, approve);
|
||||
warnx("invalid path to approval script");
|
||||
} else {
|
||||
char *s;
|
||||
|
||||
s = strrchr(approve, '/') + 1;
|
||||
if (auth_script(approve, s, name,
|
||||
lc->lc_class, service, 0) == 0 &&
|
||||
(r = auth_scan(AUTH_OKAY) & AUTH_ALLOW) != 0)
|
||||
auth_env();
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
auth_env(void)
|
||||
{
|
||||
int idx = 0;
|
||||
char *line;
|
||||
|
||||
while ((line = nextline(&idx)) != NULL) {
|
||||
if (!strncasecmp(line, BI_SETENV, sizeof(BI_SETENV)-1)) {
|
||||
line += sizeof(BI_SETENV) - 1;
|
||||
if (*line && isspace(*line)) {
|
||||
char *name;
|
||||
char ch, *p;
|
||||
|
||||
while (*line && isspace(*line))
|
||||
++line;
|
||||
name = line;
|
||||
while (*line && !isspace(*line))
|
||||
++line;
|
||||
ch = *(p = line);
|
||||
if (*line)
|
||||
++line;
|
||||
if (setenv(name, line, 1))
|
||||
warn("setenv(%s, %s)", name, line);
|
||||
*p = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
auth_value(const char *what)
|
||||
{
|
||||
int idx = 0;
|
||||
char *line;
|
||||
|
||||
while ((line = nextline(&idx)) != NULL) {
|
||||
if (!strncasecmp(line, BI_VALUE, sizeof(BI_VALUE)-1)) {
|
||||
char *name;
|
||||
|
||||
line += sizeof(BI_VALUE) - 1;
|
||||
while (*line && isspace(*line))
|
||||
++line;
|
||||
name = line;
|
||||
if (*line) {
|
||||
int i;
|
||||
char ch, *p;
|
||||
|
||||
ch = *(p = line);
|
||||
*line++ = '\0';
|
||||
i = strcmp(name, what);
|
||||
*p = ch;
|
||||
if (i == 0)
|
||||
return auth_mkvalue(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
auth_mkvalue(const char *value)
|
||||
{
|
||||
char *big, *p;
|
||||
|
||||
big = malloc(strlen(value) * 4 + 1);
|
||||
if (big != NULL) {
|
||||
for (p = big; *value; ++value) {
|
||||
switch (*value) {
|
||||
case '\r':
|
||||
*p++ = '\\';
|
||||
*p++ = 'r';
|
||||
break;
|
||||
case '\n':
|
||||
*p++ = '\\';
|
||||
*p++ = 'n';
|
||||
break;
|
||||
case '\\':
|
||||
*p++ = '\\';
|
||||
*p++ = *value;
|
||||
break;
|
||||
case '\t':
|
||||
case ' ':
|
||||
if (p == big)
|
||||
*p++ = '\\';
|
||||
*p++ = *value;
|
||||
break;
|
||||
default:
|
||||
if (!isprint(*value)) {
|
||||
*p++ = '\\';
|
||||
*p++ = ((*value >> 6) & 0x3) + '0';
|
||||
*p++ = ((*value >> 3) & 0x7) + '0';
|
||||
*p++ = ((*value ) & 0x7) + '0';
|
||||
} else
|
||||
*p++ = *value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
big = realloc(big, strlen(big) + 1);
|
||||
}
|
||||
return big;
|
||||
}
|
||||
|
||||
|
||||
#define NARGC 63
|
||||
static int
|
||||
_auth_script(const char *data, int nbytes, const char *path, va_list ap)
|
||||
{
|
||||
int r, argc, status;
|
||||
int pfd[2];
|
||||
pid_t pid;
|
||||
struct authopts *e;
|
||||
char *argv[NARGC+1];
|
||||
|
||||
r = -1;
|
||||
argc = 0;
|
||||
for (e = optfirst; argc < (NARGC - 1) && e != NULL; e = e->next) {
|
||||
argv[argc++] = "-v";
|
||||
argv[argc++] = e->opt;
|
||||
}
|
||||
while (argc < NARGC && (argv[argc] = va_arg(ap, char *)) != NULL)
|
||||
++argc;
|
||||
argv[argc] = NULL;
|
||||
|
||||
if (argc >= NARGC && va_arg(ap, char *))
|
||||
syslog(LOG_ERR, "too many arguments");
|
||||
else if (_secure_path(path, 0, 0) < 0) {
|
||||
syslog(LOG_ERR, "%s: path not secure", path);
|
||||
warnx("invalid script: %s", path);
|
||||
} else if (socketpair(PF_LOCAL, SOCK_STREAM, 0, pfd) < 0) {
|
||||
syslog(LOG_ERR, "unable to create backchannel %m");
|
||||
warnx("internal resource failure");
|
||||
} else switch (pid = fork()) {
|
||||
case -1: /* fork() failure */
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
syslog(LOG_ERR, "fork %s: %m", path);
|
||||
warnx("internal resource failure");
|
||||
break;
|
||||
case 0: /* child process */
|
||||
close(pfd[0]);
|
||||
if (pfd[1] != AUTHCOMM_FD) {
|
||||
if (dup2(pfd[1], AUTHCOMM_FD) < 0)
|
||||
err(1, "dup backchannel");
|
||||
close(pfd[1]);
|
||||
}
|
||||
for (r = getdtablesize(); --r > AUTHCOMM_FD; )
|
||||
close(r);
|
||||
execve(path, argv, auth_environ);
|
||||
syslog(LOG_ERR, "exec %s: %m", path);
|
||||
err(1, path);
|
||||
default: /* parent */
|
||||
close(pfd[1]);
|
||||
if (data && nbytes)
|
||||
write(pfd[0], data, nbytes);
|
||||
r = spooldata(pfd[0]);
|
||||
close(pfd[0]);
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
syslog(LOG_ERR, "%s: waitpid: %m", path);
|
||||
warnx("internal failure");
|
||||
r = -1;
|
||||
} else {
|
||||
if (r != 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
r = -1;
|
||||
}
|
||||
/* kill the buffer if it is of no use */
|
||||
if (r != 0) {
|
||||
free(spoolbuf);
|
||||
spoolbuf = NULL;
|
||||
spoolidx = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* reject [challenge|silent]
|
||||
* 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.
|
||||
* Terribly exciting, isn't it?
|
||||
* Output cannot exceed AUTHMAXSPOOL characters.
|
||||
*/
|
||||
|
||||
int
|
||||
auth_script(const char * path, ...)
|
||||
auth_script(const char *path, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int pid, status;
|
||||
int argc = 0;
|
||||
int p[2]; /* pipes */
|
||||
char *argv[AUTHMAXARGS+1];
|
||||
int r;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, path);
|
||||
while (argc < AUTHMAXARGS && (argv[argc++] = va_arg(ap, char*)) != NULL)
|
||||
;
|
||||
argv[argc] = NULL;
|
||||
va_end(ap);
|
||||
va_start(ap, path);
|
||||
r = _auth_script(NULL, 0, path, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
int
|
||||
auth_script_data(const char *data, int nbytes, const char *path, ...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, path);
|
||||
r = _auth_script(data, nbytes, path, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_rmlist(const char *file)
|
||||
{
|
||||
struct rmfiles *rm;
|
||||
|
||||
if ((rm = malloc(sizeof(struct rmfiles) + strlen(file) + 1)) == NULL)
|
||||
syslog(LOG_ERR, "add_rmfile malloc: %m");
|
||||
else {
|
||||
strcpy(rm->file, file);
|
||||
rm->next = rmfirst;
|
||||
rmfirst = rm;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_env()
|
||||
* Processes the stored "setenv" lines from the stored authentication
|
||||
* output.
|
||||
*/
|
||||
|
||||
int
|
||||
auth_env(void)
|
||||
auth_scan(int okay)
|
||||
{
|
||||
int i;
|
||||
int idx = 0;
|
||||
char *line;
|
||||
|
||||
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");
|
||||
while ((line = nextline(&idx)) != NULL) {
|
||||
if (!strncasecmp(line, BI_REJECT, sizeof(BI_REJECT)-1)) {
|
||||
line += sizeof(BI_REJECT) - 1;
|
||||
while (*line && isspace(*line))
|
||||
++line;
|
||||
if (*line) {
|
||||
if (!strcasecmp(line, "silent"))
|
||||
return AUTH_SILENT;
|
||||
if (!strcasecmp(line, "challenge"))
|
||||
return AUTH_CHALLENGE;
|
||||
}
|
||||
return 0;
|
||||
} else if (!strncasecmp(line, BI_AUTH, sizeof(BI_AUTH)-1)) {
|
||||
line += sizeof(BI_AUTH) - 1;
|
||||
while (*line && isspace(*line))
|
||||
++line;
|
||||
if (*line == '\0')
|
||||
okay |= AUTH_OKAY;
|
||||
else if (!strcasecmp(line, "root"))
|
||||
okay |= AUTH_ROOTOKAY;
|
||||
else if (!strcasecmp(line, "secure"))
|
||||
okay |= AUTH_SECURE;
|
||||
}
|
||||
else if (!strncasecmp(line, BI_REMOVE, sizeof(BI_REMOVE)-1)) {
|
||||
line += sizeof(BI_REMOVE) - 1;
|
||||
while (*line && isspace(*line))
|
||||
++line;
|
||||
if (*line)
|
||||
add_rmlist(line);
|
||||
}
|
||||
}
|
||||
setenv(nam, ptr, 1);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return okay;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
auth_setopt(const char *n, const char *v)
|
||||
{
|
||||
if (auth_info.reject)
|
||||
return 0;
|
||||
return ok | auth_info.auths;
|
||||
int r;
|
||||
struct authopts *e;
|
||||
|
||||
if ((e = malloc(sizeof(*e) + strlen(n) + strlen(v) + 1)) == NULL)
|
||||
r = -1;
|
||||
else {
|
||||
sprintf(e->opt, "%s=%s", n, v);
|
||||
e->next = optfirst;
|
||||
optfirst = e;
|
||||
r = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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().
|
||||
*/
|
||||
void
|
||||
auth_clropts(void)
|
||||
{
|
||||
struct authopts *e;
|
||||
|
||||
int
|
||||
while ((e = optfirst) != NULL) {
|
||||
optfirst = e->next;
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
struct rmfiles *rm;
|
||||
|
||||
while ((rm = rmfirst) != NULL) {
|
||||
unlink(rm->file);
|
||||
rmfirst = rm->next;
|
||||
free(rm);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* auth_checknologin()
|
||||
@ -370,6 +654,7 @@ auth_checknologin(login_cap_t *lc)
|
||||
* reading, it prints it out to stdout, and then exits. Otherwise,
|
||||
* it returns 0 (meaning no nologin file).
|
||||
*/
|
||||
|
||||
int
|
||||
auth_cat(const char *file)
|
||||
{
|
||||
@ -379,7 +664,7 @@ auth_cat(const char *file)
|
||||
if ((fd = open(file, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
while ((count = read(fd, buf, sizeof(buf))) > 0)
|
||||
write(fileno(stdout), buf, count);
|
||||
(void)write(fileno(stdout), buf, count);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions copyright (c) 1995,1997
|
||||
* Berkeley Software Design, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -21,13 +25,14 @@
|
||||
*
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*
|
||||
* $Id: login_cap.c,v 1.10 1997/02/22 15:08:20 peter Exp $
|
||||
* $Id: login_cap.c,v 1.11 1997/02/27 00:24:05 ache Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -35,13 +40,19 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/param.h>
|
||||
#include <pwd.h>
|
||||
#include <libutil.h>
|
||||
#include <syslog.h>
|
||||
#include <login_cap.h>
|
||||
|
||||
#ifdef RLIM_LONG
|
||||
# define STRTOV strtol
|
||||
#else
|
||||
# define STRTOV strtoq
|
||||
#endif
|
||||
/*
|
||||
* allocstr()
|
||||
* Manage a single static pointer for handling a local char* buffer,
|
||||
* resizing as necessary to contain the string.
|
||||
*
|
||||
* allocarray()
|
||||
* Manage a static array for handling a group of strings, resizing
|
||||
* when necessary.
|
||||
*/
|
||||
|
||||
static int lc_object_count = 0;
|
||||
|
||||
@ -51,30 +62,33 @@ static size_t internal_arraysz = 0;
|
||||
static char ** internal_array = NULL;
|
||||
|
||||
static char *
|
||||
allocstr(char * str)
|
||||
allocstr(char *str)
|
||||
{
|
||||
char * p;
|
||||
size_t sz = strlen(str) + 1; /* realloc() only if necessary */
|
||||
if (sz <= internal_stringsz)
|
||||
p = strcpy(internal_string, str);
|
||||
else if ((p = realloc(internal_string, sz)) != NULL) {
|
||||
internal_stringsz = sz;
|
||||
internal_string = strcpy(p, str);
|
||||
}
|
||||
return p;
|
||||
char *p;
|
||||
|
||||
size_t sz = strlen(str) + 1; /* realloc() only if necessary */
|
||||
if (sz <= internal_stringsz)
|
||||
p = strcpy(internal_string, str);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -89,38 +103,43 @@ allocarray(size_t sz)
|
||||
static char **
|
||||
arrayize(char *str, const char *chars, int *size)
|
||||
{
|
||||
int i;
|
||||
char *ptr;
|
||||
char **res = NULL;
|
||||
int i;
|
||||
char *ptr;
|
||||
char **res = NULL;
|
||||
|
||||
for (i = 0, ptr = str; *ptr; i++) {
|
||||
int count = strcspn(ptr, chars);
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
++ptr;
|
||||
}
|
||||
|
||||
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';
|
||||
/* count the sub-strings */
|
||||
for (i = 0, ptr = str; *ptr; i++) {
|
||||
int count = strcspn(ptr, chars);
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
++ptr;
|
||||
}
|
||||
res[i] = 0;
|
||||
}
|
||||
if (size)
|
||||
*size = i;
|
||||
return res;
|
||||
|
||||
i = 0;
|
||||
/* alloc the array */
|
||||
if ((ptr = allocstr(str)) != NULL) {
|
||||
if ((res = allocarray(++i)) == NULL)
|
||||
free(str);
|
||||
else {
|
||||
/* now split the string */
|
||||
while (*ptr) {
|
||||
int count = strcspn(ptr, chars);
|
||||
res[i++] = ptr;
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
res[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = i;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_close()
|
||||
* Frees up all resources relating to a login class
|
||||
@ -130,20 +149,20 @@ arrayize(char *str, const char *chars, int *size)
|
||||
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_arraysz = 0;
|
||||
internal_string = NULL;
|
||||
internal_stringsz = 0;
|
||||
cgetclose();
|
||||
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_arraysz = 0;
|
||||
internal_string = NULL;
|
||||
internal_stringsz = 0;
|
||||
cgetclose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -159,38 +178,99 @@ login_close(login_cap_t * lc)
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getclassbyname(char const * name, char const * dir)
|
||||
login_getclassbyname(char const *name, const struct passwd *pwd)
|
||||
{
|
||||
login_cap_t *lc = malloc(sizeof(login_cap_t));
|
||||
login_cap_t *lc;
|
||||
|
||||
if (lc != NULL) {
|
||||
int i = 0;
|
||||
char userpath[MAXPATHLEN];
|
||||
static char *login_dbarray[] = { NULL, NULL, NULL };
|
||||
if ((lc = malloc(sizeof(login_cap_t))) != NULL) {
|
||||
int r, i = 0;
|
||||
const char *msg = NULL;
|
||||
const char *dir = (pwd == NULL) ? NULL : pwd->pw_dir;
|
||||
char userpath[MAXPATHLEN];
|
||||
|
||||
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;
|
||||
static char *login_dbarray[] = { NULL, NULL, NULL };
|
||||
|
||||
lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
|
||||
if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
|
||||
_FILE_LOGIN_CONF) < MAXPATHLEN) {
|
||||
login_dbarray[i] = userpath;
|
||||
if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
|
||||
i++; /* only use 'secure' data */
|
||||
}
|
||||
if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1)
|
||||
login_dbarray[i++] = _PATH_LOGIN_CONF;
|
||||
login_dbarray[i] = NULL;
|
||||
|
||||
if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) &&
|
||||
cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) {
|
||||
memset(lc, 0, sizeof(login_cap_t));
|
||||
lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
|
||||
|
||||
if (name == NULL || *name == '\0')
|
||||
name = LOGIN_DEFCLASS;
|
||||
|
||||
switch (cgetent(&lc->lc_cap, login_dbarray, (char*)name)) {
|
||||
case -1: /* Failed, entry does not exist */
|
||||
if (strcmp(name, LOGIN_MECLASS) == 0)
|
||||
break; /* Don't retry default on 'me' */
|
||||
if (i == 0)
|
||||
r = -1;
|
||||
else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0)
|
||||
close(r);
|
||||
/*
|
||||
* If there's at least one login class database,
|
||||
* and we aren't searching for a default class
|
||||
* then complain about a non-existent class.
|
||||
*/
|
||||
if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
|
||||
syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
|
||||
/* fall-back to default class */
|
||||
name = LOGIN_DEFCLASS;
|
||||
msg = "%s: no default/fallback class '%s'";
|
||||
if (cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0 && r >= 0)
|
||||
break;
|
||||
/* Fallthru - just return system defaults */
|
||||
case 0: /* success! */
|
||||
if ((lc->lc_class = strdup(name)) != NULL) {
|
||||
++lc_object_count;
|
||||
return lc;
|
||||
}
|
||||
msg = "%s: strdup: %m";
|
||||
break;
|
||||
case -2:
|
||||
msg = "%s: retrieving class information: %m";
|
||||
break;
|
||||
case -3:
|
||||
msg = "%s: 'tc=' reference loop '%s'";
|
||||
break;
|
||||
case 1:
|
||||
msg = "couldn't resolve 'tc=' reference in '%s'";
|
||||
break;
|
||||
default:
|
||||
msg = "%s: unexpected cgetent() error '%s': %m";
|
||||
break;
|
||||
}
|
||||
if (msg != NULL)
|
||||
syslog(LOG_ERR, msg, "login_getclass", name);
|
||||
free(lc);
|
||||
lc = NULL;
|
||||
} else {
|
||||
++lc_object_count;
|
||||
lc->lc_class = strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
return lc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* login_getclass()
|
||||
* Get the login class for the system (only) login class database.
|
||||
* Return a filled-out login_cap_t structure, including
|
||||
* class name, and the capability record buffer.
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getclass(const char *cls)
|
||||
{
|
||||
return login_getclassbyname(cls, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getclass()
|
||||
* Get the login class for a given password entry from
|
||||
@ -203,14 +283,16 @@ login_getclassbyname(char const * name, char const * dir)
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getclass(const struct passwd *pwd)
|
||||
login_getpwclass(const struct passwd *pwd)
|
||||
{
|
||||
const char * class = NULL;
|
||||
if (pwd != NULL) {
|
||||
if ((class = pwd->pw_class) == NULL || *class == '\0')
|
||||
class = (pwd->pw_uid == 0) ? "root" : NULL;
|
||||
}
|
||||
return login_getclassbyname(class, 0);
|
||||
const char *cls = NULL;
|
||||
|
||||
if (pwd != NULL) {
|
||||
cls = pwd->pw_class;
|
||||
if (cls == NULL || *cls == '\0')
|
||||
cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
|
||||
}
|
||||
return login_getclassbyname(cls, pwd);
|
||||
}
|
||||
|
||||
|
||||
@ -218,20 +300,12 @@ login_getclass(const struct passwd *pwd)
|
||||
* 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);
|
||||
return login_getclassbyname(LOGIN_MECLASS, pwd);
|
||||
}
|
||||
|
||||
|
||||
@ -246,18 +320,15 @@ login_getuserclass(const struct passwd *pwd)
|
||||
char *
|
||||
login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
|
||||
{
|
||||
char *res;
|
||||
int ret;
|
||||
char *res;
|
||||
int ret;
|
||||
|
||||
if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
|
||||
return def;
|
||||
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;
|
||||
if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
return (ret >= 0) ? res : error;
|
||||
}
|
||||
|
||||
|
||||
@ -269,15 +340,15 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
|
||||
*/
|
||||
|
||||
char **
|
||||
login_getcaplist(login_cap_t *lc, const char * cap, const char * chars)
|
||||
login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
|
||||
{
|
||||
char * lstring;
|
||||
char *lstring;
|
||||
|
||||
if (chars == NULL)
|
||||
chars = ", \t";
|
||||
if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL)
|
||||
return arrayize(lstring, chars, NULL);
|
||||
return NULL;
|
||||
if (chars == NULL)
|
||||
chars = ", \t";
|
||||
if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL)
|
||||
return arrayize(lstring, chars, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -292,21 +363,124 @@ login_getcaplist(login_cap_t *lc, const char * cap, const char * chars)
|
||||
char *
|
||||
login_getpath(login_cap_t *lc, const char *cap, char * error)
|
||||
{
|
||||
char *str = login_getcapstr(lc, (char*)cap, NULL, NULL);
|
||||
char *str;
|
||||
|
||||
if (str == NULL)
|
||||
str = error;
|
||||
else {
|
||||
char *ptr = str;
|
||||
if ((str = login_getcapstr(lc, (char*)cap, NULL, NULL)) == NULL)
|
||||
str = error;
|
||||
else {
|
||||
char *ptr = str;
|
||||
|
||||
while (*ptr) {
|
||||
int count = strcspn(ptr, ", \t");
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = ':';
|
||||
while (*ptr) {
|
||||
int count = strcspn(ptr, ", \t");
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isinfinite(const char *s)
|
||||
{
|
||||
static const char *infs[] = {
|
||||
"infinity",
|
||||
"inf",
|
||||
"unlimited",
|
||||
"unlimit",
|
||||
"-1",
|
||||
NULL
|
||||
};
|
||||
const char **i = &infs[0];
|
||||
|
||||
while (*i != NULL) {
|
||||
if (strcasecmp(s, *i) == 0)
|
||||
return 1;
|
||||
++i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u_quad_t
|
||||
rmultiply(u_quad_t n1, u_quad_t n2)
|
||||
{
|
||||
u_quad_t m, r;
|
||||
int b1, b2;
|
||||
|
||||
static int bpw = 0;
|
||||
|
||||
/* Handle simple cases */
|
||||
if (n1 == 0 || n2 == 0)
|
||||
return 0;
|
||||
if (n1 == 1)
|
||||
return n2;
|
||||
if (n2 == 1)
|
||||
return n1;
|
||||
|
||||
/*
|
||||
* sizeof() returns number of bytes needed for storage.
|
||||
* This may be different from the actual number of useful bits.
|
||||
*/
|
||||
if (!bpw) {
|
||||
bpw = sizeof(u_quad_t) * 8;
|
||||
while (((u_quad_t)1 << (bpw-1)) == 0)
|
||||
--bpw;
|
||||
}
|
||||
|
||||
/*
|
||||
* First check the magnitude of each number. If the sum of the
|
||||
* magnatude is way to high, reject the number. (If this test
|
||||
* is not done then the first multiply below may overflow.)
|
||||
*/
|
||||
for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
|
||||
;
|
||||
for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
|
||||
;
|
||||
if (b1 + b2 - 2 > bpw) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompose the multiplication to be:
|
||||
* h1 = n1 & ~1
|
||||
* h2 = n2 & ~1
|
||||
* l1 = n1 & 1
|
||||
* l2 = n2 & 1
|
||||
* (h1 + l1) * (h2 + l2)
|
||||
* (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
|
||||
*
|
||||
* Since h1 && h2 do not have the low bit set, we can then say:
|
||||
*
|
||||
* (h1>>1 * h2>>1 * 4) + ...
|
||||
*
|
||||
* So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
|
||||
* overflow.
|
||||
*
|
||||
* Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
|
||||
* then adding in residual amout will cause an overflow.
|
||||
*/
|
||||
|
||||
m = (n1 >> 1) * (n2 >> 1);
|
||||
if (m >= ((u_quad_t)1 << (bpw-2))) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
m *= 4;
|
||||
|
||||
r = (n1 & n2 & 1)
|
||||
+ (n2 & 1) * (n1 & ~(u_quad_t)1)
|
||||
+ (n1 & 1) * (n2 & ~(u_quad_t)1);
|
||||
|
||||
if ((u_quad_t)(m + r) < m) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
m += r;
|
||||
|
||||
return (m);
|
||||
}
|
||||
|
||||
|
||||
@ -321,70 +495,80 @@ login_getpath(login_cap_t *lc, const char *cap, char * 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;
|
||||
char *res, *ep, *oval;
|
||||
int r;
|
||||
rlim_t tot;
|
||||
|
||||
errno = 0;
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
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>.
|
||||
*/
|
||||
/*
|
||||
* 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;
|
||||
tot = 0;
|
||||
while (*res) {
|
||||
rlim_t tim = STRTOV(res, &ep, 0);
|
||||
if ((ep == NULL) || (ep == res) || errno) {
|
||||
return error;
|
||||
if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
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;
|
||||
|
||||
/* "inf" and "infinity" are special cases */
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
/*
|
||||
* Now go through the string, turning something like 1h2m3s into
|
||||
* an integral value. Whee.
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t tim = strtoq(res, &ep, 0);
|
||||
rlim_t mult = 1;
|
||||
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
invalid:
|
||||
syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, oval);
|
||||
errno = ERANGE;
|
||||
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 */
|
||||
mult = 60;
|
||||
break;
|
||||
case 'h': case 'H': /* hours */
|
||||
mult = 60L * 60L;
|
||||
break;
|
||||
case 'd': case 'D': /* days */
|
||||
mult = 60L * 60L * 24L;
|
||||
break;
|
||||
case 'w': case 'W': /* weeks */
|
||||
mult = 60L * 60L * 24L * 7L;
|
||||
case 'y': case 'Y': /* 365-day years */
|
||||
mult = 60L * 60L * 24L * 365L;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += rmultiply(tim, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += tim;
|
||||
}
|
||||
return tot;
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
||||
@ -400,41 +584,47 @@ login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
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;
|
||||
char *ep, *res;
|
||||
int r;
|
||||
rlim_t val;
|
||||
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
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
|
||||
* For BSDI compatibility, try for the tag=<val> first
|
||||
*/
|
||||
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 ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
|
||||
long lval;
|
||||
/* string capability not present, so try for tag#<val> as numeric */
|
||||
if ((r = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1)
|
||||
return def; /* Not there, so return default */
|
||||
else if (r >= 0)
|
||||
return (rlim_t)lval;
|
||||
}
|
||||
|
||||
if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
|
||||
return RLIM_INFINITY;
|
||||
if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = STRTOV(res, &ep, 0);
|
||||
if ((ep == NULL) || (ep == res) || errno)
|
||||
return error;
|
||||
return val;
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
val = strtoq(res, &ep, 0);
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, res);
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* login_getcapsize()
|
||||
* From the login_cap_t <lc>, extract the capability <cap>, which is
|
||||
@ -444,55 +634,68 @@ login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
*/
|
||||
|
||||
rlim_t
|
||||
login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) {
|
||||
char *ep, *res;
|
||||
int ret;
|
||||
rlim_t tot, mult;
|
||||
login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
{
|
||||
char *ep, *res, *oval;
|
||||
int r;
|
||||
rlim_t tot;
|
||||
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
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;
|
||||
|
||||
/*
|
||||
* "inf" and "infinity" are two special cases for this.
|
||||
*/
|
||||
if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
while (*res) {
|
||||
rlim_t val = STRTOV(res, &ep, 0);
|
||||
if ((res == NULL) || (res == ep) || errno)
|
||||
return error;
|
||||
switch (*ep++) {
|
||||
case 0: /* end of string */
|
||||
ep--;
|
||||
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;
|
||||
if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
res = ep;
|
||||
tot += (val * mult);
|
||||
}
|
||||
return tot;
|
||||
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t siz = strtoq(res, &ep, 0);
|
||||
rlim_t mult = 1;
|
||||
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
invalid:
|
||||
syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, oval);
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
switch (*ep++) {
|
||||
case 0: /* end of string */
|
||||
ep--;
|
||||
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;
|
||||
case 't': case 'T': /* 1TBte */
|
||||
mult = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += rmultiply(siz, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
||||
@ -506,9 +709,9 @@ login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) {
|
||||
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);
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -535,38 +738,41 @@ login_getcapbool(login_cap_t *lc, const char *cap, int def)
|
||||
char *
|
||||
login_getstyle(login_cap_t *lc, char *style, const char *auth)
|
||||
{
|
||||
int i;
|
||||
char **authtypes = NULL;
|
||||
char *auths= NULL;
|
||||
char realauth[64];
|
||||
int i;
|
||||
char **authtypes = NULL;
|
||||
char *auths= NULL;
|
||||
char realauth[64];
|
||||
|
||||
static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
|
||||
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 (auth != NULL && *auth != '\0') {
|
||||
if (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 = login_getcaplist(lc, "auth", NULL);
|
||||
|
||||
if (authtypes == NULL)
|
||||
authtypes = defauthtypes;
|
||||
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;
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
|
||||
return lc->lc_style;
|
||||
lc->lc_style = NULL;
|
||||
if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
|
||||
lc->lc_style = auths;
|
||||
|
||||
if (lc->lc_style != NULL)
|
||||
lc->lc_style = strdup(lc->lc_style);
|
||||
|
||||
return lc->lc_style;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,13 +22,15 @@
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*
|
||||
* Was login_cap.h,v 1.9 1997/05/07 20:00:01 eivind Exp
|
||||
* $Id$
|
||||
* $Id: login_cap.h,v 1.1 1997/05/10 12:49:30 davidn Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LOGIN_CAP_H_
|
||||
#define _LOGIN_CAP_H_
|
||||
|
||||
#define LOGIN_DEFCLASS "default"
|
||||
#define LOGIN_DEFROOTCLASS "root"
|
||||
#define LOGIN_MECLASS "me"
|
||||
#define LOGIN_DEFSTYLE "passwd"
|
||||
#define LOGIN_DEFSERVICE "login"
|
||||
#define LOGIN_DEFUMASK 022
|
||||
@ -37,53 +39,57 @@
|
||||
#define _FILE_LOGIN_CONF ".login_conf"
|
||||
#define _PATH_AUTHPROG "/usr/libexec/login_"
|
||||
|
||||
#define LOGIN_SETGROUP 0x0001 /* set group */
|
||||
#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */
|
||||
#define LOGIN_SETPATH 0x0004 /* set path */
|
||||
#define LOGIN_SETPRIORITY 0x0008 /* set priority */
|
||||
#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */
|
||||
#define LOGIN_SETUMASK 0x0020 /* set umask, obviously */
|
||||
#define LOGIN_SETUSER 0x0040 /* set user (via setuid) */
|
||||
#define LOGIN_SETENV 0x0080 /* set user environment */
|
||||
#define LOGIN_SETALL 0x00ff /* set everything */
|
||||
#define LOGIN_SETGROUP 0x0001 /* set group */
|
||||
#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */
|
||||
#define LOGIN_SETPATH 0x0004 /* set path */
|
||||
#define LOGIN_SETPRIORITY 0x0008 /* set priority */
|
||||
#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */
|
||||
#define LOGIN_SETUMASK 0x0020 /* set umask, obviously */
|
||||
#define LOGIN_SETUSER 0x0040 /* set user (via setuid) */
|
||||
#define LOGIN_SETENV 0x0080 /* set user environment */
|
||||
#define LOGIN_SETALL 0x00ff /* set everything */
|
||||
|
||||
#define BI_AUTH "authorize"
|
||||
#define BI_AUTH2 "authorise"
|
||||
#define BI_REJECT "reject"
|
||||
#define BI_REMOVE "remove"
|
||||
#define BI_ROOTOKAY "root"
|
||||
#define BI_SECURE "secure"
|
||||
#define BI_SETENV "setenv"
|
||||
#define BI_AUTH "authorize" /* accepted authentication */
|
||||
#define BI_REJECT "reject" /* rejected authentication */
|
||||
#define BI_CHALLENG "reject challenge" /* reject with a challenge */
|
||||
#define BI_SILENT "reject silent" /* reject silently */
|
||||
#define BI_REMOVE "remove" /* remove file on error */
|
||||
#define BI_ROOTOKAY "authorize root" /* root authenticated */
|
||||
#define BI_SECURE "authorize secure" /* okay on non-secure line */
|
||||
#define BI_SETENV "setenv" /* set environment variable */
|
||||
#define BI_VALUE "value" /* set local variable */
|
||||
|
||||
#ifndef AUTH_NONE /* Protect against <rpc/auth.h> */
|
||||
#define AUTH_NONE 0x00
|
||||
#endif
|
||||
#define AUTH_OKAY 0x01
|
||||
#define AUTH_ROOTOKAY 0x02 /* root login okay */
|
||||
#define AUTH_SECURE 0x04 /* secure login */
|
||||
#define AUTH_OKAY 0x01 /* user authenticated */
|
||||
#define AUTH_ROOTOKAY 0x02 /* root login okay */
|
||||
#define AUTH_SECURE 0x04 /* secure login */
|
||||
#define AUTH_SILENT 0x08 /* silent rejection */
|
||||
#define AUTH_CHALLENGE 0x10 /* a chellenge was given */
|
||||
|
||||
#define AUTH_ALLOW (AUTH_OKAY | AUTH_ROOTOKAY | AUTH_SECURE)
|
||||
|
||||
typedef struct login_cap {
|
||||
char *lc_class;
|
||||
char *lc_cap;
|
||||
char *lc_style;
|
||||
char *lc_class;
|
||||
char *lc_cap;
|
||||
char *lc_style;
|
||||
} login_cap_t;
|
||||
|
||||
typedef struct login_time {
|
||||
u_short lt_start; /* Start time */
|
||||
u_short lt_end; /* End time */
|
||||
#define LTM_NONE 0x00
|
||||
#define LTM_SUN 0x01
|
||||
#define LTM_MON 0x02
|
||||
#define LTM_TUE 0x04
|
||||
#define LTM_WED 0x08
|
||||
#define LTM_THU 0x10
|
||||
#define LTM_FRI 0x20
|
||||
#define LTM_SAT 0x40
|
||||
#define LTM_ANY 0x7F
|
||||
#define LTM_WK 0x3E
|
||||
#define LTM_WD 0x41
|
||||
u_char lt_dow; /* Days of week */
|
||||
u_short lt_start; /* Start time */
|
||||
u_short lt_end; /* End time */
|
||||
#define LTM_NONE 0x00
|
||||
#define LTM_SUN 0x01
|
||||
#define LTM_MON 0x02
|
||||
#define LTM_TUE 0x04
|
||||
#define LTM_WED 0x08
|
||||
#define LTM_THU 0x10
|
||||
#define LTM_FRI 0x20
|
||||
#define LTM_SAT 0x40
|
||||
#define LTM_ANY 0x7F
|
||||
#define LTM_WK 0x3E
|
||||
#define LTM_WD 0x41
|
||||
u_char lt_dow; /* Days of week */
|
||||
} login_time_t;
|
||||
|
||||
#define LC_MAXTIMES 64
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
@ -91,8 +97,9 @@ __BEGIN_DECLS
|
||||
struct passwd;
|
||||
|
||||
void login_close __P((login_cap_t *));
|
||||
login_cap_t *login_getclassbyname __P((const char *, const char *homedir));
|
||||
login_cap_t *login_getclass __P((const struct passwd *));
|
||||
login_cap_t *login_getclassbyname __P((const char *, const struct passwd *));
|
||||
login_cap_t *login_getclass __P((const char *));
|
||||
login_cap_t *login_getpwclass __P((const struct passwd *));
|
||||
login_cap_t *login_getuserclass __P((const struct passwd *));
|
||||
|
||||
char *login_getcapstr __P((login_cap_t*, const char *, char *, char *));
|
||||
@ -109,11 +116,20 @@ int setusercontext __P((login_cap_t*, const struct passwd*, uid_t, unsigned int)
|
||||
void setclassresources __P((login_cap_t *));
|
||||
void setclassenvironment __P((login_cap_t *, const struct passwd *, int));
|
||||
|
||||
int authenticate __P((const char*, const char*, const char*, const char*));
|
||||
int auth_script __P((const char*, ...));
|
||||
int auth_env __P((void));
|
||||
/* Most of these functions are deprecated */
|
||||
int auth_approve __P((login_cap_t*, const char*, const char*));
|
||||
int auth_check __P((const char *, const char *, const char *, const char *, int *));
|
||||
void auth_env __P((void));
|
||||
char *auth_mkvalue __P((const char *n));
|
||||
int auth_response __P((const char *, const char *, const char *, const char *, int *, const char *, const char *));
|
||||
void auth_rmfiles __P((void));
|
||||
int auth_scan __P((int));
|
||||
int auth_rmfiles __P((void));
|
||||
int auth_script __P((const char*, ...));
|
||||
int auth_script_data __P((const char *, int, const char *, ...));
|
||||
char *auth_valud __P((const char *));
|
||||
int auth_setopt __P((const char *, const char *));
|
||||
void auth_clropts __P((void));
|
||||
|
||||
void auth_checknologin __P((login_cap_t*));
|
||||
int auth_cat __P((const char*));
|
||||
|
||||
@ -127,7 +143,7 @@ login_time_t parse_lt __P((const char *));
|
||||
int in_ltm __P((const login_time_t *, struct tm *, time_t *));
|
||||
int in_ltms __P((const login_time_t *, struct tm *, time_t *));
|
||||
|
||||
/* auxiliary functions */
|
||||
/* helper functions */
|
||||
|
||||
int login_strinlist __P((char **, char const *, int));
|
||||
int login_str2inlist __P((char **, const char *, const char *, int));
|
||||
@ -138,4 +154,3 @@ int login_hostok __P((login_cap_t *, const char *, const char *, const char *, c
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _LOGIN_CAP_H_ */
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
* High-level routines relating to use of the user capabilities database
|
||||
*
|
||||
* $Id$
|
||||
* $Id: login_class.c,v 1.5 1997/02/22 15:08:22 peter Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -45,202 +45,197 @@
|
||||
|
||||
|
||||
static struct login_res {
|
||||
const char * what;
|
||||
rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
int why;
|
||||
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 }
|
||||
{ "cputime", login_getcaptime, RLIMIT_CPU },
|
||||
{ "filesize", login_getcapsize, RLIMIT_FSIZE },
|
||||
{ "datasize", login_getcapsize, RLIMIT_DATA },
|
||||
{ "stacksize", login_getcapsize, RLIMIT_STACK },
|
||||
{ "memoryuse", login_getcapsize, RLIMIT_RSS },
|
||||
{ "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
|
||||
{ "maxproc", login_getcapnum, RLIMIT_NPROC },
|
||||
{ "openfiles", login_getcapnum, RLIMIT_NOFILE },
|
||||
{ "coredumpsize", login_getcapsize, RLIMIT_CORE },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
void
|
||||
setclassresources(login_cap_t *lc)
|
||||
{
|
||||
struct login_res *lr = resources;
|
||||
struct login_res *lr;
|
||||
|
||||
if (lc == NULL)
|
||||
return;
|
||||
if (lc == NULL)
|
||||
return;
|
||||
|
||||
while (lr->what != NULL) {
|
||||
struct rlimit rlim,
|
||||
newlim;
|
||||
char cur[40],
|
||||
max[40];
|
||||
rlim_t rcur,
|
||||
rmax;
|
||||
for (lr = resources; lr->what != NULL; ++lr) {
|
||||
struct rlimit rlim;
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (getrlimit(lr->why, &rlim) != 0)
|
||||
syslog(LOG_ERR, "getting %s resource limit: %m", lr->what);
|
||||
else {
|
||||
char name_cur[40];
|
||||
char name_max[40];
|
||||
rlim_t rcur = rlim.rlim_cur;
|
||||
rlim_t rmax = rlim.rlim_max;
|
||||
|
||||
getrlimit(lr->why, &rlim);
|
||||
rcur = rlim.rlim_cur;
|
||||
rmax = rlim.rlim_max;
|
||||
sprintf(name_cur, "%s-cur", lr->what);
|
||||
sprintf(name_max, "%s-max", lr->what);
|
||||
|
||||
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);
|
||||
rcur = (*lr->who)(lc, lr->what, rcur, rcur);
|
||||
rmax = (*lr->who)(lc, lr->what, rmax, rmax);
|
||||
rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur);
|
||||
rlim.rlim_max = (*lr->who)(lc, name_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;
|
||||
}
|
||||
if (setrlimit(lr->why, &rlim) == -1)
|
||||
syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct login_vars {
|
||||
const char * tag;
|
||||
const char * var;
|
||||
const char * def;
|
||||
const char *tag;
|
||||
const char *var;
|
||||
const char *def;
|
||||
} pathvars[] = {
|
||||
{ "path", "PATH", NULL },
|
||||
{ "manpath", "MANPATH", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
{ "path", "PATH", NULL },
|
||||
{ "cdpath", "CDPATH", NULL },
|
||||
{ "manpath", "MANPATH", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
}, envars[] = {
|
||||
{ "lang", "LANG", NULL },
|
||||
{ "charset", "MM_CHARSET", NULL },
|
||||
{ "timezone", "TZ", NULL },
|
||||
{ "term", "TERM", UNKNOWN },
|
||||
{ NULL, NULL, NULL }
|
||||
{ "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;
|
||||
char *np = NULL;
|
||||
|
||||
if (var != NULL) {
|
||||
int tildes = 0;
|
||||
int dollas = 0;
|
||||
char * p;
|
||||
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 == '~') {
|
||||
int v = pch && *(p+1) != '/'; /* Avoid double // */
|
||||
memmove(p + hlen + v, p + 1, l); /* Subst homedir */
|
||||
memmove(p, pwd->pw_dir, hlen);
|
||||
if (v)
|
||||
p[hlen] = '/';
|
||||
p += hlen + v;
|
||||
}
|
||||
else /* if (*p == '$') */ {
|
||||
memmove(p + nlen, p + 1, l); /* Subst username */
|
||||
memmove(p, pwd->pw_name, nlen);
|
||||
p += nlen;
|
||||
}
|
||||
if (pwd != NULL) {
|
||||
/* Count the number of ~'s in var to substitute */
|
||||
p = var;
|
||||
for (p = var; (p = strchr(p, '~')) != NULL; p++)
|
||||
++tildes;
|
||||
/* Count the number of $'s in var to substitute */
|
||||
p = var;
|
||||
for (p = var; (p = strchr(p, '$')) != NULL; p++)
|
||||
++dollas;
|
||||
}
|
||||
|
||||
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 == '~') {
|
||||
int v = pch && *(p+1) != '/'; /* Avoid double // */
|
||||
memmove(p + hlen + v, p + 1, l); /* Subst homedir */
|
||||
memmove(p, pwd->pw_dir, hlen);
|
||||
if (v)
|
||||
p[hlen] = '/';
|
||||
p += hlen + v;
|
||||
}
|
||||
else /* if (*p == '$') */ {
|
||||
memmove(p + nlen, p + 1, l); /* Subst username */
|
||||
memmove(p, pwd->pw_name, nlen);
|
||||
p += nlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return np;
|
||||
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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) { /* Discard invalid entries */
|
||||
char * np;
|
||||
|
||||
*p++ = '\0';
|
||||
if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
|
||||
setenv(*set_env, np, 1);
|
||||
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) { /* Discard invalid entries */
|
||||
char *np;
|
||||
|
||||
*p++ = '\0';
|
||||
if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
|
||||
setenv(*set_env, np, 1);
|
||||
free(np);
|
||||
}
|
||||
}
|
||||
++set_env;
|
||||
}
|
||||
}
|
||||
++set_env;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -258,15 +253,48 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
|
||||
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;
|
||||
int rc;
|
||||
login_cap_t *lc;
|
||||
|
||||
lc = login_getclassbyname(classname, NULL);
|
||||
|
||||
flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY |
|
||||
LOGIN_SETUMASK | LOGIN_SETPATH;
|
||||
|
||||
rc = lc ? setusercontext(lc, NULL, 0, flags) : -1;
|
||||
login_close(lc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Private functionw which takes care of processing
|
||||
*/
|
||||
|
||||
static mode_t
|
||||
setlogincontext(login_cap_t *lc, const struct passwd *pwd,
|
||||
mode_t mymask, unsigned long flags)
|
||||
{
|
||||
if (lc) {
|
||||
/* Set resources */
|
||||
if (flags & LOGIN_SETRESOURCES)
|
||||
setclassresources(lc);
|
||||
/* See if there's a umask override */
|
||||
if (flags & LOGIN_SETUMASK)
|
||||
mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask);
|
||||
/* Set paths */
|
||||
if (flags & LOGIN_SETPATH)
|
||||
setclassenvironment(lc, pwd, 1);
|
||||
/* Set environment */
|
||||
if (flags & LOGIN_SETENV)
|
||||
setclassenvironment(lc, pwd, 0);
|
||||
}
|
||||
return mymask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* setusercontext()
|
||||
*
|
||||
@ -284,93 +312,76 @@ setclasscontext(const char *classname, unsigned int flags)
|
||||
int
|
||||
setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
|
||||
{
|
||||
int i;
|
||||
login_cap_t * llc = NULL;
|
||||
quad_t p;
|
||||
mode_t mymask;
|
||||
login_cap_t *llc = NULL;
|
||||
|
||||
if (lc == NULL)
|
||||
{
|
||||
if (pwd != NULL && (lc = login_getclass(pwd)) != NULL)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the user's group permissions
|
||||
*/
|
||||
if (flags & LOGIN_SETGROUP) {
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (lc == NULL) {
|
||||
if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
|
||||
llc = lc; /* free this when we're done */
|
||||
}
|
||||
|
||||
if (flags & LOGIN_SETPATH)
|
||||
setclassenvironment(lc, pwd, 1);
|
||||
pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;
|
||||
|
||||
if (flags & LOGIN_SETENV)
|
||||
setclassenvironment(lc, pwd, 0);
|
||||
/* we need a passwd entry to set these */
|
||||
if (pwd == NULL)
|
||||
flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN);
|
||||
|
||||
if (i++ == 0) /* Play it again, Sam */
|
||||
lc = (pwd == NULL) ? NULL : login_getuserclass(pwd);
|
||||
}
|
||||
/* Set the process priority */
|
||||
if (flags & LOGIN_SETPRIORITY) {
|
||||
p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
|
||||
|
||||
login_close(lc); /* User's private 'me' class */
|
||||
login_close(llc); /* Class we opened */
|
||||
p = (p < PRIO_MIN || p > PRIO_MAX) ? LOGIN_DEFPRI : p;
|
||||
if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
|
||||
syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
|
||||
pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This needs to be done after all of the above.
|
||||
* Do it last so we avoid getting killed and dropping core
|
||||
*/
|
||||
if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
|
||||
syslog(LOG_ERR, "setuid %ld: %m", uid);
|
||||
/* Setup the user's group permissions */
|
||||
if (flags & LOGIN_SETGROUP) {
|
||||
if (setgid(pwd->pw_gid) != 0) {
|
||||
syslog(LOG_ERR, "setgid(%ld): %m", (long)pwd->pw_gid);
|
||||
login_close(llc);
|
||||
return -1;
|
||||
}
|
||||
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
|
||||
syslog(LOG_ERR, "initgroups(%s,%ld): %m", pwd->pw_name,
|
||||
pwd->pw_gid);
|
||||
login_close(llc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
|
||||
mymask = setlogincontext(lc, pwd, mymask, flags);
|
||||
login_close(llc);
|
||||
return -1; /* Paranoia again */
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* This needs to be done after anything that needs root privs */
|
||||
if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
|
||||
syslog(LOG_ERR, "setuid(%ld): %m", uid);
|
||||
return -1; /* Paranoia again */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, we repeat some of the above for the user's private entries
|
||||
*/
|
||||
if ((lc = login_getuserclass(pwd)) != NULL) {
|
||||
mymask = setlogincontext(lc, pwd, mymask, flags);
|
||||
login_close(lc);
|
||||
}
|
||||
|
||||
/* Finally, set any umask we've found */
|
||||
if (flags & LOGIN_SETUMASK)
|
||||
umask(mymask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*
|
||||
* Support allow/deny lists in login class capabilities
|
||||
*
|
||||
* $Id$
|
||||
* $Id: login_ok.c,v 1.3 1997/02/22 15:08:25 peter Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -40,7 +40,8 @@
|
||||
|
||||
/* -- support functions -- */
|
||||
|
||||
/* login_strinlist()
|
||||
/*
|
||||
* 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
|
||||
@ -50,106 +51,111 @@
|
||||
int
|
||||
login_strinlist(char **list, char const *str, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
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;
|
||||
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()
|
||||
/*
|
||||
* 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;
|
||||
int rc = 0;
|
||||
|
||||
if (login_strinlist(ttlst, str1, flags))
|
||||
rc = 1;
|
||||
else if (login_strinlist(ttlst, str2, flags))
|
||||
rc = 1;
|
||||
return rc;
|
||||
if (login_strinlist(ttlst, str1, flags))
|
||||
rc = 1;
|
||||
else if (login_strinlist(ttlst, str2, flags))
|
||||
rc = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* login_timelist()
|
||||
/*
|
||||
* 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)
|
||||
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);
|
||||
int j = 0;
|
||||
struct login_time *lt = NULL;
|
||||
char **tl;
|
||||
|
||||
if (tl)
|
||||
{
|
||||
while (tl[j++] != NULL)
|
||||
;
|
||||
if (*ltno >= j)
|
||||
lt = *ltptr;
|
||||
else if ((lt = realloc(*ltptr, j)) != NULL)
|
||||
{
|
||||
*ltno = j;
|
||||
*ltptr = lt;
|
||||
if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
|
||||
|
||||
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;
|
||||
|
||||
for (--j; i < j; i++)
|
||||
lt[i] = parse_lt(tl[i]);
|
||||
lt[i].lt_dow = LTM_NONE;
|
||||
}
|
||||
}
|
||||
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;
|
||||
return lt;
|
||||
}
|
||||
|
||||
|
||||
/* login_ttyok()
|
||||
/*
|
||||
* 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)
|
||||
login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap,
|
||||
const char *denycap)
|
||||
{
|
||||
int rc = 1;
|
||||
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 (lc != NULL && tty != NULL && *tty != '\0') {
|
||||
struct ttyent *te;
|
||||
char *grp;
|
||||
char **ttl;
|
||||
|
||||
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 */
|
||||
te = getttynam(tty); /* Need group name */
|
||||
grp = te ? te->ty_group : NULL;
|
||||
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;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* auth_ttyok()
|
||||
/*
|
||||
* auth_ttyok()
|
||||
* Determine whether or not login on a tty is accessible for
|
||||
* a login class
|
||||
*/
|
||||
@ -157,86 +163,89 @@ login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap, const char *
|
||||
int
|
||||
auth_ttyok(login_cap_t *lc, const char * tty)
|
||||
{
|
||||
return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
|
||||
return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
|
||||
}
|
||||
|
||||
|
||||
/* login_hostok()
|
||||
/*
|
||||
* 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)
|
||||
login_hostok(login_cap_t *lc, const char *host, const char *ip,
|
||||
const char *allowcap, const char *denycap)
|
||||
{
|
||||
int rc = 1; /* Default is ok */
|
||||
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 (lc != NULL &&
|
||||
((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) {
|
||||
char **hl;
|
||||
|
||||
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 */
|
||||
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;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* auth_hostok()
|
||||
/*
|
||||
* 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");
|
||||
return login_hostok(lc, host, ip, "host.allow", "host.deny");
|
||||
}
|
||||
|
||||
|
||||
/* auth_timeok()
|
||||
/*
|
||||
* 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 */
|
||||
int rc = 1; /* Default is ok */
|
||||
|
||||
if (lc != NULL && t != (time_t)0 && t != (time_t)-1)
|
||||
{
|
||||
struct tm * tptr = localtime(&t);
|
||||
if (lc != NULL && t != (time_t)0 && t != (time_t)-1) {
|
||||
struct tm *tptr;
|
||||
|
||||
static int ltimesno = 0;
|
||||
static struct login_time * ltimes = NULL;
|
||||
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 ((tptr = localtime(&t)) != NULL) {
|
||||
struct login_time *lt;
|
||||
|
||||
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);
|
||||
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 {
|
||||
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
|
||||
rc = 0; /* in deny times list */
|
||||
}
|
||||
if (ltimes)
|
||||
{
|
||||
free(ltimes);
|
||||
ltimes = NULL;
|
||||
ltimesno = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
*
|
||||
* Login period parsing and comparison functions.
|
||||
*
|
||||
* $Id$
|
||||
* $Id: login_times.c,v 1.4 1997/02/22 15:08:27 peter Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -34,134 +34,129 @@
|
||||
|
||||
static struct
|
||||
{
|
||||
const char * dw;
|
||||
u_char cn;
|
||||
u_char fl;
|
||||
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 }
|
||||
{ "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;
|
||||
u_short val;
|
||||
|
||||
for (val = 0; *ptr && isdigit(*ptr); ptr++)
|
||||
val = (u_short)(val * 10 + (*ptr - '0'));
|
||||
for (val = 0; *ptr && isdigit(*ptr); ptr++)
|
||||
val = (u_short)(val * 10 + (*ptr - '0'));
|
||||
|
||||
*t = (u_short)((val / 100) * 60 + (val % 100));
|
||||
return ptr;
|
||||
*t = (u_short)((val / 100) * 60 + (val % 100));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
login_time_t
|
||||
parse_lt(const char * str)
|
||||
{
|
||||
login_time_t t;
|
||||
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];
|
||||
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]);
|
||||
/* 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;
|
||||
while (isalpha(*p)) {
|
||||
|
||||
i = 0;
|
||||
while (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;
|
||||
}
|
||||
|
||||
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;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
|
||||
{
|
||||
int rc = 0;
|
||||
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);
|
||||
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;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
in_lt(const login_time_t * ltm, time_t * t)
|
||||
{
|
||||
return in_ltm(ltm, localtime(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;
|
||||
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;
|
||||
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);
|
||||
return in_ltms(ltm, localtime(t), t);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user