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
@ -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]);
|
||||
}
|
||||
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;
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* Convert newlines into NULs to allow
|
||||
* easier scanning of the file.
|
||||
*/
|
||||
while ((b = memchr(spoolbuf + spoolidx, '\n', r)) != NULL)
|
||||
*b = '\0';
|
||||
spoolidx += r;
|
||||
}
|
||||
} 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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')
|
||||
if (style != NULL) {
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (service == NULL)
|
||||
service = LOGIN_DEFSERVICE;
|
||||
|
||||
free_auth_info();
|
||||
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);
|
||||
|
||||
if (snprintf(buf, sizeof buf, _PATH_AUTHPROG "%s", style) >= sizeof buf)
|
||||
retval = -1;
|
||||
else {
|
||||
retval = auth_script(buf, style, "-s", service, name, class, NULL);
|
||||
if (retval >= 0)
|
||||
retval = auth_scan(AUTH_NONE);
|
||||
return *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, ...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
int pid, status;
|
||||
int argc = 0;
|
||||
int p[2]; /* pipes */
|
||||
char *argv[AUTHMAXARGS+1];
|
||||
|
||||
va_start(ap, path);
|
||||
while (argc < AUTHMAXARGS && (argv[argc++] = va_arg(ap, char*)) != NULL)
|
||||
;
|
||||
argv[argc] = NULL;
|
||||
r = _auth_script(NULL, 0, path, ap);
|
||||
va_end(ap);
|
||||
|
||||
fflush(NULL);
|
||||
|
||||
if (pipe(p) >= 0) {
|
||||
if ((pid = fork()) == -1) {
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
} else if (pid == 0) { /* Child */
|
||||
close(p[0]);
|
||||
dup2(p[1], 3);
|
||||
if (setenv("PATH", _PATH_DEFPATH, 1)==0 && setenv("SHELL", _PATH_BSHELL, 1)==0)
|
||||
execv(path, argv);
|
||||
_exit(1);
|
||||
} else {
|
||||
close(p[1]);
|
||||
collect_info(p[0]);
|
||||
if (waitpid(pid, &status, 0) != -1 && WIFEXITED(status) && !WEXITSTATUS(status))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_env()
|
||||
* Processes the stored "setenv" lines from the stored authentication
|
||||
* output.
|
||||
*/
|
||||
|
||||
int
|
||||
auth_env(void)
|
||||
auth_script_data(const char *data, int nbytes, const char *path, ...)
|
||||
{
|
||||
int i;
|
||||
int r;
|
||||
va_list ap;
|
||||
|
||||
for (i = 0; i < auth_info.env_count; i++) {
|
||||
char *nam = auth_info.env[i];
|
||||
char *ptr = nam + strcspn(nam, " \t=");
|
||||
if (*ptr) {
|
||||
*ptr++ = '\0';
|
||||
ptr += strspn(ptr, " \t");
|
||||
}
|
||||
setenv(nam, ptr, 1);
|
||||
}
|
||||
return 0;
|
||||
va_start(ap, path);
|
||||
r = _auth_script(data, nbytes, path, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static void
|
||||
add_rmlist(const char *file)
|
||||
{
|
||||
if (auth_info.reject)
|
||||
return 0;
|
||||
return ok | auth_info.auths;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_rmfiles()
|
||||
* Removes any files that the authentication program said needed to be
|
||||
* removed, said files having come from a previous execution of
|
||||
* auth_script().
|
||||
*/
|
||||
int
|
||||
auth_scan(int okay)
|
||||
{
|
||||
int idx = 0;
|
||||
char *line;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return okay;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
auth_setopt(const char *n, const char *v)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
auth_clropts(void)
|
||||
{
|
||||
struct authopts *e;
|
||||
|
||||
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;
|
||||
struct rmfiles *rm;
|
||||
|
||||
while ((rm = rmfirst) != NULL) {
|
||||
unlink(rm->file);
|
||||
rmfirst = rm->next;
|
||||
free(rm);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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,9 +62,10 @@ static size_t internal_arraysz = 0;
|
||||
static char ** internal_array = NULL;
|
||||
|
||||
static char *
|
||||
allocstr(char * str)
|
||||
allocstr(char *str)
|
||||
{
|
||||
char * p;
|
||||
char *p;
|
||||
|
||||
size_t sz = strlen(str) + 1; /* realloc() only if necessary */
|
||||
if (sz <= internal_stringsz)
|
||||
p = strcpy(internal_string, str);
|
||||
@ -64,10 +76,12 @@ allocstr(char * str)
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static char **
|
||||
allocarray(size_t sz)
|
||||
{
|
||||
char ** p;
|
||||
char **p;
|
||||
|
||||
if (sz <= internal_arraysz)
|
||||
p = internal_array;
|
||||
else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
|
||||
@ -93,6 +107,7 @@ arrayize(char *str, const char *chars, int *size)
|
||||
char *ptr;
|
||||
char **res = NULL;
|
||||
|
||||
/* count the sub-strings */
|
||||
for (i = 0, ptr = str; *ptr; i++) {
|
||||
int count = strcspn(ptr, chars);
|
||||
ptr += count;
|
||||
@ -100,27 +115,31 @@ arrayize(char *str, const char *chars, int *size)
|
||||
++ptr;
|
||||
}
|
||||
|
||||
if ((ptr = allocstr(str)) == NULL) {
|
||||
res = NULL;
|
||||
i = 0;
|
||||
} else if ((res = allocarray(++i)) == NULL) {
|
||||
/* alloc the array */
|
||||
if ((ptr = allocstr(str)) != NULL) {
|
||||
if ((res = allocarray(++i)) == NULL)
|
||||
free(str);
|
||||
i = 0;
|
||||
} else {
|
||||
for (i = 0; *ptr; i++) {
|
||||
else {
|
||||
/* now split the string */
|
||||
while (*ptr) {
|
||||
int count = strcspn(ptr, chars);
|
||||
res[i] = ptr;
|
||||
res[i++] = ptr;
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
res[i] = 0;
|
||||
res[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = i;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_close()
|
||||
* Frees up all resources relating to a login class
|
||||
@ -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;
|
||||
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];
|
||||
|
||||
static char *login_dbarray[] = { NULL, NULL, NULL };
|
||||
|
||||
if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN)
|
||||
login_dbarray[i++] = userpath;
|
||||
else
|
||||
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;
|
||||
login_dbarray[i] = NULL;
|
||||
|
||||
memset(lc, 0, sizeof(login_cap_t));
|
||||
lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
|
||||
|
||||
if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) &&
|
||||
cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) {
|
||||
free(lc);
|
||||
lc = NULL;
|
||||
} else {
|
||||
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;
|
||||
lc->lc_class = strdup(name);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
const char *cls = NULL;
|
||||
|
||||
if (pwd != NULL) {
|
||||
if ((class = pwd->pw_class) == NULL || *class == '\0')
|
||||
class = (pwd->pw_uid == 0) ? "root" : NULL;
|
||||
cls = pwd->pw_class;
|
||||
if (cls == NULL || *cls == '\0')
|
||||
cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
|
||||
}
|
||||
return login_getclassbyname(class, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -252,12 +326,9 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
|
||||
if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
|
||||
return def;
|
||||
|
||||
if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
|
||||
if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
} else if (ret >= 0)
|
||||
return res;
|
||||
else
|
||||
return error;
|
||||
return (ret >= 0) ? res : error;
|
||||
}
|
||||
|
||||
|
||||
@ -269,9 +340,9 @@ 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";
|
||||
@ -292,9 +363,9 @@ 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)
|
||||
if ((str = login_getcapstr(lc, (char*)cap, NULL, NULL)) == NULL)
|
||||
str = error;
|
||||
else {
|
||||
char *ptr = str;
|
||||
@ -310,6 +381,109 @@ login_getpath(login_cap_t *lc, const char *cap, char * error)
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getcaptime()
|
||||
* From the login_cap_t <lc>, get the capability <cap>, which is
|
||||
@ -321,8 +495,8 @@ 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;
|
||||
char *res, *ep, *oval;
|
||||
int r;
|
||||
rlim_t tot;
|
||||
|
||||
errno = 0;
|
||||
@ -335,15 +509,15 @@ login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
* If there's an error, return <error>.
|
||||
*/
|
||||
|
||||
if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
else if (ret < 0)
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* "inf" and "infinity" are two special cases for this.
|
||||
*/
|
||||
if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
|
||||
/* "inf" and "infinity" are special cases */
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
/*
|
||||
@ -353,37 +527,47 @@ login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t tim = STRTOV(res, &ep, 0);
|
||||
if ((ep == NULL) || (ep == res) || errno) {
|
||||
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 */
|
||||
ep--;
|
||||
break; /* end of string */
|
||||
case 's': case 'S': /* seconds */
|
||||
break;
|
||||
case 'm': case 'M': /* minutes */
|
||||
tim *= 60L;
|
||||
mult = 60;
|
||||
break;
|
||||
case 'h': case 'H': /* hours */
|
||||
tim *= (60L * 60L);
|
||||
mult = 60L * 60L;
|
||||
break;
|
||||
case 'd': case 'D': /* days */
|
||||
tim *= (60L * 60L * 24L);
|
||||
mult = 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);
|
||||
mult = 60L * 60L * 24L * 7L;
|
||||
case 'y': case 'Y': /* 365-day years */
|
||||
mult = 60L * 60L * 24L * 365L;
|
||||
default:
|
||||
return error;
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += tim;
|
||||
tot += rmultiply(tim, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
@ -401,7 +585,7 @@ rlim_t
|
||||
login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
{
|
||||
char *ep, *res;
|
||||
int ret;
|
||||
int r;
|
||||
rlim_t val;
|
||||
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
@ -410,31 +594,37 @@ login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
/*
|
||||
* For BSDI compatibility, try for the tag=<val> first
|
||||
*/
|
||||
if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
|
||||
if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
|
||||
long lval;
|
||||
/*
|
||||
* String capability not present, so try for tag#<val> as numeric
|
||||
*/
|
||||
if ((ret = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1)
|
||||
/* 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 (ret < 0)
|
||||
return error;
|
||||
else if (r >= 0)
|
||||
return (rlim_t)lval;
|
||||
}
|
||||
else if (ret < 0)
|
||||
return error;
|
||||
|
||||
if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
|
||||
if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
val = STRTOV(res, &ep, 0);
|
||||
if ((ep == NULL) || (ep == res) || errno)
|
||||
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,54 +634,67 @@ 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 ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
|
||||
return def;
|
||||
else if (ret < 0)
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* "inf" and "infinity" are two special cases for this.
|
||||
*/
|
||||
if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t val = STRTOV(res, &ep, 0);
|
||||
if ((res == NULL) || (res == ep) || errno)
|
||||
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--;
|
||||
mult = 1;
|
||||
break;
|
||||
case 'b': case 'B': /* 512-byte blocks */
|
||||
mult = 512; break;
|
||||
mult = 512;
|
||||
break;
|
||||
case 'k': case 'K': /* 1024-byte Kilobytes */
|
||||
mult = 1024; break;
|
||||
mult = 1024;
|
||||
break;
|
||||
case 'm': case 'M': /* 1024-k kbytes */
|
||||
mult = 1024 * 1024; break;
|
||||
mult = 1024 * 1024;
|
||||
break;
|
||||
case 'g': case 'G': /* 1Gbyte */
|
||||
mult = 1024 * 1024 * 1024; break;
|
||||
#ifndef RLIM_LONG
|
||||
mult = 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 't': case 'T': /* 1TBte */
|
||||
mult = 1024LL * 1024LL * 1024LL * 1024LL; break;
|
||||
#endif
|
||||
mult = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
default:
|
||||
return error;
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += (val * mult);
|
||||
tot += rmultiply(siz, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
@ -542,9 +745,10 @@ login_getstyle(login_cap_t *lc, char *style, const char *auth)
|
||||
|
||||
static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
|
||||
|
||||
if (auth != NULL && *auth != '\0' &&
|
||||
snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth)
|
||||
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);
|
||||
@ -562,11 +766,13 @@ login_getstyle(login_cap_t *lc, char *style, const char *auth)
|
||||
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;
|
||||
|
||||
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
|
||||
@ -47,20 +49,23 @@
|
||||
#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_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;
|
||||
@ -71,19 +76,20 @@ typedef struct login_cap {
|
||||
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
|
||||
#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,7 +45,7 @@
|
||||
|
||||
|
||||
static struct login_res {
|
||||
const char * what;
|
||||
const char *what;
|
||||
rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
int why;
|
||||
} resources[] = {
|
||||
@ -53,34 +53,25 @@ static struct login_res {
|
||||
{ "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 },
|
||||
{ "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;
|
||||
|
||||
while (lr->what != NULL) {
|
||||
struct rlimit rlim,
|
||||
newlim;
|
||||
char cur[40],
|
||||
max[40];
|
||||
rlim_t rcur,
|
||||
rmax;
|
||||
|
||||
sprintf(cur, "%s-cur", lr->what);
|
||||
sprintf(max, "%s-max", lr->what);
|
||||
for (lr = resources; lr->what != NULL; ++lr) {
|
||||
struct rlimit rlim;
|
||||
|
||||
/*
|
||||
* The login.conf file can have <limit>, <limit>-max, and
|
||||
@ -94,28 +85,37 @@ setclassresources(login_cap_t *lc)
|
||||
* conditions.
|
||||
*/
|
||||
|
||||
getrlimit(lr->why, &rlim);
|
||||
rcur = rlim.rlim_cur;
|
||||
rmax = rlim.rlim_max;
|
||||
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;
|
||||
|
||||
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);
|
||||
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)
|
||||
if (setrlimit(lr->why, &rlim) == -1)
|
||||
syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
|
||||
|
||||
++lr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct login_vars {
|
||||
const char * tag;
|
||||
const char * var;
|
||||
const char * def;
|
||||
const char *tag;
|
||||
const char *var;
|
||||
const char *def;
|
||||
} pathvars[] = {
|
||||
{ "path", "PATH", NULL },
|
||||
{ "cdpath", "CDPATH", NULL },
|
||||
{ "manpath", "MANPATH", NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
}, envars[] = {
|
||||
@ -129,34 +129,27 @@ static struct login_vars {
|
||||
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;
|
||||
char *p;
|
||||
|
||||
if (pwd != NULL) {
|
||||
/*
|
||||
* Count the number of ~'s in var to substitute
|
||||
*/
|
||||
/* Count the number of ~'s in var to substitute */
|
||||
p = var;
|
||||
while ((p = strchr(p, '~')) != NULL) {
|
||||
for (p = var; (p = strchr(p, '~')) != NULL; p++)
|
||||
++tildes;
|
||||
++p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of $'s in var to substitute
|
||||
*/
|
||||
/* Count the number of $'s in var to substitute */
|
||||
p = var;
|
||||
while ((p = strchr(p, '$')) != NULL) {
|
||||
for (p = var; (p = strchr(p, '$')) != NULL; p++)
|
||||
++dollas;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
np = malloc(strlen(var) + (dollas * nlen) - dollas + (tildes * (pch+hlen)) - tildes + 1);
|
||||
np = malloc(strlen(var) + (dollas * nlen)
|
||||
- dollas + (tildes * (pch+hlen))
|
||||
- tildes + 1);
|
||||
|
||||
if (np != NULL) {
|
||||
p = strcpy(np, var);
|
||||
@ -188,6 +181,7 @@ substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
@ -195,7 +189,7 @@ substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
|
||||
void
|
||||
setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
|
||||
{
|
||||
struct login_vars * vars = paths ? pathvars : envars;
|
||||
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;
|
||||
@ -223,13 +217,14 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
|
||||
* which the admin and/or user may set an arbitrary set of env vars.
|
||||
*/
|
||||
if (!paths) {
|
||||
char ** set_env = login_getcaplist(lc, "setenv", ",");
|
||||
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;
|
||||
char *np;
|
||||
|
||||
*p++ = '\0';
|
||||
if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
|
||||
@ -259,14 +254,47 @@ 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_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)
|
||||
if (lc == NULL) {
|
||||
if (pwd != NULL && (lc = login_getpwclass(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
|
||||
*/
|
||||
/* we need a passwd entry to set these */
|
||||
if (pwd == NULL)
|
||||
flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN);
|
||||
|
||||
/* 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);
|
||||
p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set resources
|
||||
*/
|
||||
if (flags & LOGIN_SETRESOURCES)
|
||||
setclassresources(lc);
|
||||
/* 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
|
||||
*/
|
||||
/* Set the sessions login */
|
||||
if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
|
||||
syslog(LOG_ERR, "setlogin '%s': %m", pwd->pw_name);
|
||||
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 (flags & LOGIN_SETPATH)
|
||||
setclassenvironment(lc, pwd, 1);
|
||||
|
||||
if (flags & LOGIN_SETENV)
|
||||
setclassenvironment(lc, pwd, 0);
|
||||
|
||||
if (i++ == 0) /* Play it again, Sam */
|
||||
lc = (pwd == NULL) ? NULL : login_getuserclass(pwd);
|
||||
}
|
||||
|
||||
login_close(lc); /* User's private 'me' class */
|
||||
login_close(llc); /* Class we opened */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
|
||||
mymask = setlogincontext(lc, pwd, mymask, flags);
|
||||
login_close(llc);
|
||||
|
||||
/* 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
|
||||
@ -52,9 +53,9 @@ login_strinlist(char **list, char const *str, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (str != NULL && *str != '\0')
|
||||
{
|
||||
if (str != NULL && *str != '\0') {
|
||||
int i = 0;
|
||||
|
||||
while (rc == 0 && list[i] != NULL)
|
||||
rc = fnmatch(list[i], str, flags) == 0;
|
||||
}
|
||||
@ -62,7 +63,8 @@ login_strinlist(char **list, char const *str, int flags)
|
||||
}
|
||||
|
||||
|
||||
/* login_str2inlist()
|
||||
/*
|
||||
* login_str2inlist()
|
||||
* Locate either or two strings in a given list
|
||||
*/
|
||||
|
||||
@ -79,39 +81,36 @@ login_str2inlist(char **ttlst, const char *str1, const char *str2, int flags)
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
struct login_time *lt = NULL;
|
||||
char **tl;
|
||||
|
||||
if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
|
||||
|
||||
if (tl)
|
||||
{
|
||||
while (tl[j++] != NULL)
|
||||
;
|
||||
if (*ltno >= j)
|
||||
lt = *ltptr;
|
||||
else if ((lt = realloc(*ltptr, j)) != NULL)
|
||||
{
|
||||
else if ((lt = realloc(*ltptr, j)) != NULL) {
|
||||
*ltno = j;
|
||||
*ltptr = lt;
|
||||
}
|
||||
if (lt != NULL)
|
||||
{
|
||||
if (lt != NULL) {
|
||||
int i = 0;
|
||||
--j;
|
||||
while (i < j)
|
||||
{
|
||||
|
||||
for (--j; i < j; i++)
|
||||
lt[i] = parse_lt(tl[i]);
|
||||
++i;
|
||||
}
|
||||
lt[i].lt_dow = LTM_NONE;
|
||||
}
|
||||
}
|
||||
@ -119,37 +118,44 @@ login_timelist(login_cap_t *lc, char const *cap, int *ltno, login_time_t **ltptr
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
else {
|
||||
|
||||
ttl = login_getcaplist(lc, denycap, NULL);
|
||||
if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
|
||||
rc = 0; /* tty or ttygroup in deny list */
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* auth_ttyok()
|
||||
/*
|
||||
* auth_ttyok()
|
||||
* Determine whether or not login on a tty is accessible for
|
||||
* a login class
|
||||
*/
|
||||
@ -161,35 +167,40 @@ auth_ttyok(login_cap_t *lc, const char * tty)
|
||||
}
|
||||
|
||||
|
||||
/* 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 */
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
else {
|
||||
|
||||
hl = login_getcaplist(lc, "host.deny", NULL);
|
||||
if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
|
||||
rc = 0; /* host or IP in deny list */
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* auth_hostok()
|
||||
/*
|
||||
* auth_hostok()
|
||||
* Determine whether or not login from a host is ok
|
||||
*/
|
||||
|
||||
@ -200,7 +211,8 @@ auth_hostok(login_cap_t *lc, const char *host, const char *ip)
|
||||
}
|
||||
|
||||
|
||||
/* auth_timeok()
|
||||
/*
|
||||
* auth_timeok()
|
||||
* Determine whether or not login is ok at a given time
|
||||
*/
|
||||
|
||||
@ -209,34 +221,31 @@ auth_timeok(login_cap_t *lc, time_t t)
|
||||
{
|
||||
int rc = 1; /* Default is ok */
|
||||
|
||||
if (lc != NULL && t != (time_t)0 && t != (time_t)-1)
|
||||
{
|
||||
struct tm * tptr = localtime(&t);
|
||||
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 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;
|
||||
|
||||
lt = login_timelist(lc, "times.allow", <imesno, <imes);
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
|
||||
rc = 0; /* not in allowed times list */
|
||||
else
|
||||
{
|
||||
lt = login_timelist(lc, "times.deny", <imesno, <imes);
|
||||
else {
|
||||
|
||||
lt = login_timelist(lc, "times.deny", <imesno, <imes);
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
|
||||
rc = 0; /* in deny times list */
|
||||
}
|
||||
if (ltimes)
|
||||
{
|
||||
if (ltimes) {
|
||||
free(ltimes);
|
||||
ltimes = NULL;
|
||||
ltimesno = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,7 +34,7 @@
|
||||
|
||||
static struct
|
||||
{
|
||||
const char * dw;
|
||||
const char *dw;
|
||||
u_char cn;
|
||||
u_char fl;
|
||||
} dws[] =
|
||||
@ -54,9 +54,11 @@ parse_time(char * ptr, u_short * t)
|
||||
val = (u_short)(val * 10 + (*ptr - '0'));
|
||||
|
||||
*t = (u_short)((val / 100) * 60 + (val % 100));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
login_time_t
|
||||
parse_lt(const char * str)
|
||||
{
|
||||
@ -64,24 +66,23 @@ parse_lt(const char * str)
|
||||
|
||||
memset(&t, 0, sizeof t);
|
||||
t.lt_dow = LTM_NONE;
|
||||
if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0)
|
||||
{
|
||||
if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0) {
|
||||
int i;
|
||||
login_time_t m = t;
|
||||
char * p;
|
||||
char *p;
|
||||
char buf[64];
|
||||
|
||||
/* Make local copy and force lowercase to simplify parsing
|
||||
*/
|
||||
/* 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++)
|
||||
;
|
||||
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;
|
||||
@ -111,24 +112,18 @@ in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (tt != NULL)
|
||||
{
|
||||
/* First, examine the day of the week
|
||||
*/
|
||||
if ((u_char)(0x01 << tt->tm_wday) & ltm->lt_dow)
|
||||
{
|
||||
/* Convert `current' time to minute of the day
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (now >= ltm->lt_start && now < ltm->lt_end) {
|
||||
rc = 2;
|
||||
if (ends != NULL)
|
||||
{
|
||||
/* If requested, return ending time for this period
|
||||
*/
|
||||
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);
|
||||
@ -139,6 +134,7 @@ in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
in_lt(const login_time_t * ltm, time_t * t)
|
||||
{
|
||||
@ -150,8 +146,7 @@ in_ltms(const login_time_t * ltm, struct tm * tm, time_t * t)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE)
|
||||
{
|
||||
while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE) {
|
||||
if (in_ltm(ltm + i, tm, t))
|
||||
return i;
|
||||
i++;
|
||||
|
Loading…
Reference in New Issue
Block a user