More mblogin fixes for FreeBSD
This commit is contained in:
parent
09de95f205
commit
81c0cc8f10
@ -3,7 +3,7 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
* Purpose ...............: MBSE BBS Shadow Password Suite
|
* Purpose ...............: MBSE BBS Shadow Password Suite
|
||||||
* Original Source .......: Shadow Password Suite
|
* Original Source .......: Shadow Password Suite
|
||||||
* Original Copyrioght ...: Julianne Frances Haugh and others.
|
* Original Copyright ....: Julianne Frances Haugh and others.
|
||||||
*
|
*
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
* Copyright (C) 1997-2001
|
* Copyright (C) 1997-2001
|
||||||
@ -31,23 +31,21 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
|
||||||
#include "mblogin.h"
|
#include "mblogin.h"
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include "getdef.h"
|
#include "getdef.h"
|
||||||
#include "chowntty.h"
|
#include "chowntty.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* is_my_tty -- determine if "tty" is the same as TTY stdin is using
|
* is_my_tty -- determine if "tty" is the same as TTY stdin is using
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int is_my_tty(const char *tty)
|
int is_my_tty(const char *tty)
|
||||||
{
|
{
|
||||||
struct stat by_name, by_fd;
|
struct stat by_name, by_fd;
|
||||||
@ -61,31 +59,18 @@ int is_my_tty(const char *tty)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* chown_tty() sets the login tty to be owned by the new user ID
|
* chown_tty() sets the login tty to be owned by the new user ID
|
||||||
* with TTYPERM modes
|
* with TTYPERM modes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void chown_tty(const char *tty, const struct passwd *info)
|
void chown_tty(const char *tty, const struct passwd *info)
|
||||||
{
|
{
|
||||||
char buf[200], full_tty[200];
|
char buf[200], full_tty[200];
|
||||||
char *group; /* TTY group name or number */
|
gid_t gid;
|
||||||
struct group *grent;
|
|
||||||
gid_t gid;
|
|
||||||
|
|
||||||
/*
|
gid = info->pw_gid;
|
||||||
* See if login.defs has some value configured for the port group
|
|
||||||
* ID. Otherwise, use the user's primary group ID.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (! (group = getdef_str ("TTYGROUP")))
|
|
||||||
gid = info->pw_gid;
|
|
||||||
else if (group[0] >= '0' && group[0] <= '9')
|
|
||||||
gid = atoi (group);
|
|
||||||
else if ((grent = getgrnam (group)))
|
|
||||||
gid = grent->gr_gid;
|
|
||||||
else
|
|
||||||
gid = info->pw_gid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the permissions on the TTY to be owned by the user with
|
* Change the permissions on the TTY to be owned by the user with
|
||||||
@ -103,7 +88,7 @@ void chown_tty(const char *tty, const struct passwd *info)
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chown(tty, info->pw_uid, gid) || chmod(tty, getdef_num("TTYPERM", 0600))) {
|
if (chown(tty, info->pw_uid, gid) || chmod(tty, 0600)) {
|
||||||
snprintf(buf, sizeof buf, "Unable to change tty %s", tty);
|
snprintf(buf, sizeof buf, "Unable to change tty %s", tty);
|
||||||
syslog(LOG_WARNING, "unable to change tty `%s' for user `%s'\n", tty, info->pw_name);
|
syslog(LOG_WARNING, "unable to change tty `%s' for user `%s'\n", tty, info->pw_name);
|
||||||
closelog();
|
closelog();
|
||||||
|
326
mbsebbs/limits.c
326
mbsebbs/limits.c
@ -40,273 +40,13 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <syslog.h>
|
|
||||||
#include <utmp.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include "getdef.h"
|
|
||||||
#include "utmp.h"
|
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_RESOURCE_H
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#define LIMITS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LIMITS
|
void setup_limits(const struct passwd *info)
|
||||||
|
|
||||||
#ifndef LIMITS_FILE
|
|
||||||
#define LIMITS_FILE "/etc/limits"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOGIN_ERROR_RLIMIT 1
|
|
||||||
#define LOGIN_ERROR_LOGIN 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Set a limit on a resource */
|
|
||||||
/*
|
|
||||||
* rlimit - RLIMIT_XXXX
|
|
||||||
* value - string value to be read
|
|
||||||
* multiplier - value*multiplier is the actual limit
|
|
||||||
*/
|
|
||||||
int setrlimit_value(unsigned int rlimit, const char *value, unsigned int multiplier)
|
|
||||||
{
|
|
||||||
struct rlimit rlim;
|
|
||||||
long limit;
|
|
||||||
char **endptr = (char **) &value;
|
|
||||||
const char *value_orig = value;
|
|
||||||
|
|
||||||
limit = strtol(value, endptr, 10);
|
|
||||||
if (limit == 0 && value_orig == *endptr) /* no chars read */
|
|
||||||
return 0;
|
|
||||||
limit *= multiplier;
|
|
||||||
rlim.rlim_cur = limit;
|
|
||||||
rlim.rlim_max = limit;
|
|
||||||
if (setrlimit(rlimit, &rlim))
|
|
||||||
return LOGIN_ERROR_RLIMIT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int set_prio(const char *value)
|
|
||||||
{
|
|
||||||
int prio;
|
|
||||||
char **endptr = (char **) &value;
|
|
||||||
|
|
||||||
prio = strtol(value, endptr, 10);
|
|
||||||
if ((prio == 0) && (value == *endptr))
|
|
||||||
return 0;
|
|
||||||
if (setpriority(PRIO_PROCESS, 0, prio))
|
|
||||||
return LOGIN_ERROR_RLIMIT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int set_umask(const char *value)
|
|
||||||
{
|
|
||||||
mode_t mask;
|
|
||||||
char **endptr = (char **) &value;
|
|
||||||
|
|
||||||
mask = strtol(value, endptr, 8) & 0777;
|
|
||||||
if ((mask == 0) && (value == *endptr))
|
|
||||||
return 0;
|
|
||||||
umask(mask);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Function setup_user_limits - checks/set limits for the curent login
|
|
||||||
* Original idea from Joel Katz's lshell. Ported to shadow-login
|
|
||||||
* by Cristian Gafton - gafton@sorosis.ro
|
|
||||||
*
|
|
||||||
* We are passed a string of the form ('BASH' constants for ulimit)
|
|
||||||
* [Aa][Cc][Dd][Ff][Mm][Nn][Rr][Ss][Tt][Uu][Ll][Pp]
|
|
||||||
* (eg. 'C2F256D2048N5' or 'C2 F256 D2048 N5')
|
|
||||||
* where:
|
|
||||||
* [Aa]: a = RLIMIT_AS max address space (KB)
|
|
||||||
* [Cc]: c = RLIMIT_CORE max core file size (KB)
|
|
||||||
* [Dd]: d = RLIMIT_DATA max data size (KB)
|
|
||||||
* [Ff]: f = RLIMIT_FSIZE max file size (KB)
|
|
||||||
* [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
|
|
||||||
* [Nn]: n = RLIMIT_NOFILE max number of open files
|
|
||||||
* [Rr]: r = RLIMIT_RSS max resident set size (KB)
|
|
||||||
* [Ss]: s = RLIMIT_STACK max stack size (KB)
|
|
||||||
* [Tt]: t = RLIMIT_CPU max CPU time (MIN)
|
|
||||||
* [Uu]: u = RLIMIT_NPROC max number of processes
|
|
||||||
* [Kk]: k = file creation masK (umask)
|
|
||||||
* [Ll]: l = max number of logins for this user
|
|
||||||
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
|
|
||||||
*
|
|
||||||
* Return value:
|
|
||||||
* 0 = okay, of course
|
|
||||||
* LOGIN_ERROR_RLIMIT = error setting some RLIMIT
|
|
||||||
* LOGIN_ERROR_LOGIN = error - too many logins for this user
|
|
||||||
*
|
|
||||||
* buf - the limits string
|
|
||||||
* name - the username
|
|
||||||
*/
|
|
||||||
int do_user_limits(const char *buf, const char *name)
|
|
||||||
{
|
|
||||||
const char *pp;
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
pp = buf;
|
|
||||||
|
|
||||||
while (*pp != '\0') switch(*pp++) {
|
|
||||||
#ifdef RLIMIT_AS
|
|
||||||
case 'a':
|
|
||||||
case 'A':
|
|
||||||
/* RLIMIT_AS - max address space (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_AS, pp, 1024);
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_CPU
|
|
||||||
case 't':
|
|
||||||
case 'T':
|
|
||||||
/* RLIMIT_CPU - max CPU time (MIN) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_CPU, pp, 60);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_DATA
|
|
||||||
case 'd':
|
|
||||||
case 'D':
|
|
||||||
/* RLIMIT_DATA - max data size (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_DATA, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_FSIZE
|
|
||||||
case 'f':
|
|
||||||
case 'F':
|
|
||||||
/* RLIMIT_FSIZE - Maximum filesize (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_FSIZE, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_NPROC
|
|
||||||
case 'u':
|
|
||||||
case 'U':
|
|
||||||
/* RLIMIT_NPROC - max number of processes */
|
|
||||||
retval |= setrlimit_value(RLIMIT_NPROC, pp, 1);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_CORE
|
|
||||||
case 'c':
|
|
||||||
case 'C':
|
|
||||||
/* RLIMIT_CORE - max core file size (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_CORE, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_MEMLOCK
|
|
||||||
case 'm':
|
|
||||||
case 'M':
|
|
||||||
/* RLIMIT_MEMLOCK - max locked-in-memory address space (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_MEMLOCK, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_NOFILE
|
|
||||||
case 'n':
|
|
||||||
case 'N':
|
|
||||||
/* RLIMIT_NOFILE - max number of open files */
|
|
||||||
retval |= setrlimit_value(RLIMIT_NOFILE, pp, 1);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_RSS
|
|
||||||
case 'r':
|
|
||||||
case 'R':
|
|
||||||
/* RLIMIT_RSS - max resident set size (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_RSS, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef RLIMIT_STACK
|
|
||||||
case 's':
|
|
||||||
case 'S':
|
|
||||||
/* RLIMIT_STACK - max stack size (KB) */
|
|
||||||
retval |= setrlimit_value(RLIMIT_STACK, pp, 1024);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 'k':
|
|
||||||
case 'K':
|
|
||||||
retval |= set_umask(pp);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
case 'L':
|
|
||||||
/* LIMIT the number of concurent logins, not for MBSE BBS. */
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
case 'P':
|
|
||||||
retval |= set_prio(pp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int setup_user_limits(const char *uname)
|
|
||||||
{
|
|
||||||
/* TODO: allow and use @group syntax --cristiang */
|
|
||||||
FILE *fil;
|
|
||||||
char buf[1024];
|
|
||||||
char name[1024];
|
|
||||||
char limits[1024];
|
|
||||||
char deflimits[1024];
|
|
||||||
char tempbuf[1024];
|
|
||||||
|
|
||||||
/* init things */
|
|
||||||
memzero(buf, sizeof(buf));
|
|
||||||
memzero(name, sizeof(name));
|
|
||||||
memzero(limits, sizeof(limits));
|
|
||||||
memzero(deflimits, sizeof(deflimits));
|
|
||||||
memzero(tempbuf, sizeof(tempbuf));
|
|
||||||
|
|
||||||
/* start the checks */
|
|
||||||
fil = fopen(LIMITS_FILE, "r");
|
|
||||||
if (fil == NULL) {
|
|
||||||
#if 0 /* no limits file is ok, not everyone is a BOFH :-). --marekm */
|
|
||||||
SYSLOG((LOG_WARN, NO_LIMITS, uname, LIMITS_FILE));
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* The limits file have the following format:
|
|
||||||
* - '#' (comment) chars only as first chars on a line;
|
|
||||||
* - username must start on first column
|
|
||||||
* A better (smarter) checking should be done --cristiang */
|
|
||||||
while (fgets(buf, 1024, fil) != NULL) {
|
|
||||||
if (buf[0]=='#' || buf[0]=='\n')
|
|
||||||
continue;
|
|
||||||
memzero(tempbuf, sizeof(tempbuf));
|
|
||||||
/* a valid line should have a username, then spaces,
|
|
||||||
* then limits
|
|
||||||
* we allow the format:
|
|
||||||
* username L2 D2048 R4096
|
|
||||||
* where spaces={' ',\t}. Also, we reject invalid limits.
|
|
||||||
* Imposing a limit should be done with care, so a wrong
|
|
||||||
* entry means no care anyway :-). A '-' as a limits
|
|
||||||
* strings means no limits --cristiang */
|
|
||||||
if (sscanf(buf, "%s%[ACDFMNRSTULPacdfmnrstulp0-9 \t-]",
|
|
||||||
name, tempbuf) == 2) {
|
|
||||||
if (strcmp(name, uname) == 0) {
|
|
||||||
strcpy(limits, tempbuf);
|
|
||||||
break;
|
|
||||||
} else if (strcmp(name, "*") == 0) {
|
|
||||||
strcpy(deflimits, tempbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(fil);
|
|
||||||
if (limits[0] == '\0') {
|
|
||||||
/* no user specific limits */
|
|
||||||
if (deflimits[0] == '\0') /* no default limits */
|
|
||||||
return 0;
|
|
||||||
strcpy(limits, deflimits); /* use the default limits */
|
|
||||||
}
|
|
||||||
return do_user_limits(limits, uname);
|
|
||||||
}
|
|
||||||
#endif /* LIMITS */
|
|
||||||
|
|
||||||
|
|
||||||
void setup_usergroups(const struct passwd *info)
|
|
||||||
{
|
{
|
||||||
const struct group *grp;
|
const struct group *grp;
|
||||||
mode_t oldmask;
|
mode_t oldmask;
|
||||||
@ -325,67 +65,3 @@ void setup_usergroups(const struct passwd *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* set the process nice, ulimit, and umask from the password file entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
void setup_limits(const struct passwd *info)
|
|
||||||
{
|
|
||||||
char *cp;
|
|
||||||
int i;
|
|
||||||
long l;
|
|
||||||
|
|
||||||
if (getdef_bool("USERGROUPS_ENAB"))
|
|
||||||
setup_usergroups(info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See if the GECOS field contains values for NICE, UMASK or ULIMIT.
|
|
||||||
* If this feature is enabled in /etc/login.defs, we make those
|
|
||||||
* values the defaults for this login session.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (getdef_bool("QUOTAS_ENAB")) {
|
|
||||||
#ifdef LIMITS
|
|
||||||
if (info->pw_uid != 0)
|
|
||||||
if (setup_user_limits(info->pw_name) & LOGIN_ERROR_LOGIN) {
|
|
||||||
fprintf(stderr, _("Too many logins.\n"));
|
|
||||||
sleep(2);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (cp = info->pw_gecos ; cp != NULL ; cp = strchr (cp, ',')) {
|
|
||||||
if (*cp == ',')
|
|
||||||
cp++;
|
|
||||||
|
|
||||||
if (strncmp (cp, "pri=", 4) == 0) {
|
|
||||||
i = atoi (cp + 4);
|
|
||||||
if (i >= -20 && i <= 20)
|
|
||||||
(void) nice (i);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strncmp (cp, "ulimit=", 7) == 0) {
|
|
||||||
l = strtol (cp + 7, (char **) 0, 10);
|
|
||||||
set_filesize_limit(l);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strncmp (cp, "umask=", 6) == 0) {
|
|
||||||
i = strtol (cp + 6, (char **) 0, 8) & 0777;
|
|
||||||
(void) umask (i);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void set_filesize_limit(int blocks)
|
|
||||||
{
|
|
||||||
struct rlimit rlimit_fsize;
|
|
||||||
|
|
||||||
rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
|
|
||||||
setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -4,14 +4,6 @@
|
|||||||
#define _LIMITS_H_
|
#define _LIMITS_H_
|
||||||
|
|
||||||
|
|
||||||
int setrlimit_value(unsigned int, const char *, unsigned int);
|
|
||||||
int set_prio(const char *);
|
|
||||||
int set_umask(const char *);
|
|
||||||
int check_logins(const char *, const char *);
|
|
||||||
int do_user_limits(const char *, const char *);
|
|
||||||
int setup_user_limits(const char *);
|
|
||||||
void setup_usergroups(const struct passwd *);
|
|
||||||
void setup_limits(const struct passwd *);
|
void setup_limits(const struct passwd *);
|
||||||
void set_filesize_limit(int);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
* Purpose ...............: MBSE BBS Shadow Password Suite
|
* Purpose ...............: MBSE BBS Shadow Password Suite
|
||||||
* Original Source .......: Shadow Password Suite
|
* Original Source .......: Shadow Password Suite
|
||||||
* Original Copyrioght ...: Julianne Frances Haugh and others.
|
* Original Copyright ....: Julianne Frances Haugh and others.
|
||||||
*
|
*
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
* Copyright (C) 1997-2002
|
* Copyright (C) 1997-2002
|
||||||
@ -46,13 +46,14 @@ void login_exit(int sig)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* login_prompt - prompt the user for their login name
|
* login_prompt - prompt the user for their login name
|
||||||
*
|
*
|
||||||
* login_prompt() displays the standard login prompt. If ISSUE_FILE
|
* login_prompt() displays the standard login prompt. If ISSUE_FILE
|
||||||
* is set in login.defs, this file is displayed before the prompt.
|
* is set in login.defs, this file is displayed before the prompt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void login_prompt(const char *prompt, char *name, int namesize)
|
void login_prompt(const char *prompt, char *name, int namesize)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@ -85,7 +86,8 @@ void login_prompt(const char *prompt, char *name, int namesize)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (prompt) {
|
if (prompt) {
|
||||||
cp = getdef_str("ISSUE_FILE");
|
// cp = getdef_str("ISSUE_FILE");
|
||||||
|
cp = NULL;
|
||||||
if (cp && (fp = fopen(cp, "r"))) {
|
if (cp && (fp = fopen(cp, "r"))) {
|
||||||
while ((i = getc(fp)) != EOF)
|
while ((i = getc(fp)) != EOF)
|
||||||
putc(i, stdout);
|
putc(i, stdout);
|
||||||
@ -101,7 +103,6 @@ void login_prompt(const char *prompt, char *name, int namesize)
|
|||||||
* Read the user's response. The trailing newline will be
|
* Read the user's response. The trailing newline will be
|
||||||
* removed.
|
* removed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
memzero(buf, sizeof buf);
|
memzero(buf, sizeof buf);
|
||||||
if (fgets(buf, sizeof buf, stdin) != buf)
|
if (fgets(buf, sizeof buf, stdin) != buf)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -74,6 +74,15 @@
|
|||||||
#include "setugid.h"
|
#include "setugid.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Login parameters
|
||||||
|
*/
|
||||||
|
#define LOGIN_DELAY 3
|
||||||
|
#define LOGIN_TIMEOUT 300
|
||||||
|
#define LOGIN_RETRIES 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Needed for MkLinux DR1/2/2.1 - J.
|
* Needed for MkLinux DR1/2/2.1 - J.
|
||||||
*/
|
*/
|
||||||
@ -140,7 +149,7 @@ extern char **environ;
|
|||||||
static void usage(void);
|
static void usage(void);
|
||||||
static void setup_tty(void);
|
static void setup_tty(void);
|
||||||
static void check_flags(int, char * const *);
|
static void check_flags(int, char * const *);
|
||||||
static void check_nologin(void);
|
static void check_nologin(char *);
|
||||||
static void init_env(void);
|
static void init_env(void);
|
||||||
static RETSIGTYPE alarm_handler(int);
|
static RETSIGTYPE alarm_handler(int);
|
||||||
int main(int, char **);
|
int main(int, char **);
|
||||||
@ -163,9 +172,6 @@ usage(void)
|
|||||||
if (!amroot)
|
if (!amroot)
|
||||||
exit(1);
|
exit(1);
|
||||||
fprintf(stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
|
fprintf(stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
|
||||||
#ifdef RLOGIN
|
|
||||||
fprintf(stderr, _(" %s [-p] -r host\n"), Prog);
|
|
||||||
#endif
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,9 +213,12 @@ static void setup_tty(void)
|
|||||||
termio.c_iflag &= ~IXANY;
|
termio.c_iflag &= ~IXANY;
|
||||||
termio.c_oflag |= (XTABS|OPOST|ONLCR);
|
termio.c_oflag |= (XTABS|OPOST|ONLCR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FreeBSD__
|
||||||
/* leave these values unchanged if not specified in login.defs */
|
/* leave these values unchanged if not specified in login.defs */
|
||||||
termio.c_cc[VERASE] = getdef_num("ERASECHAR", termio.c_cc[VERASE]);
|
termio.c_cc[VERASE] = getdef_num("ERASECHAR", termio.c_cc[VERASE]);
|
||||||
termio.c_cc[VKILL] = getdef_num("KILLCHAR", termio.c_cc[VKILL]);
|
termio.c_cc[VKILL] = getdef_num("KILLCHAR", termio.c_cc[VKILL]);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ttymon invocation prefers this, but these settings won't come into
|
* ttymon invocation prefers this, but these settings won't come into
|
||||||
@ -239,7 +248,10 @@ static void check_flags(int argc, char * const *argv)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void check_nologin(void)
|
/*
|
||||||
|
* nologin file is $MBSE_ROOT/etc/nologin
|
||||||
|
*/
|
||||||
|
static void check_nologin(char *path)
|
||||||
{
|
{
|
||||||
char *fname;
|
char *fname;
|
||||||
|
|
||||||
@ -251,8 +263,9 @@ static void check_nologin(void)
|
|||||||
* forgotten about it ...
|
* forgotten about it ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fname = getdef_str("NOLOGINS_FILE");
|
fname = calloc(PATH_MAX, sizeof(char));
|
||||||
if (fname != NULL && access(fname, F_OK) == 0) {
|
sprintf(fname, "%s/etc/nologin", path);
|
||||||
|
if (access(fname, F_OK) == 0) {
|
||||||
FILE *nlfp;
|
FILE *nlfp;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@ -273,23 +286,22 @@ static void check_nologin(void)
|
|||||||
} else
|
} else
|
||||||
printf("\nSystem closed for routine maintenance\n");
|
printf("\nSystem closed for routine maintenance\n");
|
||||||
|
|
||||||
/*
|
free(fname);
|
||||||
* Non-root users must exit. Root gets the message, but
|
closelog();
|
||||||
* gets to login.
|
exit(0);
|
||||||
*/
|
|
||||||
if (pwent.pw_uid != 0) {
|
|
||||||
closelog();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
printf("\n[Disconnect bypassed -- root login allowed.]\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void init_env(void)
|
static void init_env(void)
|
||||||
{
|
{
|
||||||
char *cp, *tmp;
|
#ifndef __FreeBSD__
|
||||||
|
char *cp;
|
||||||
|
#endif
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
if ((tmp = getenv("LANG"))) {
|
if ((tmp = getenv("LANG"))) {
|
||||||
addenv("LANG", tmp);
|
addenv("LANG", tmp);
|
||||||
@ -311,8 +323,12 @@ static void init_env(void)
|
|||||||
|
|
||||||
if ((tmp = getenv("HZ"))) {
|
if ((tmp = getenv("HZ"))) {
|
||||||
addenv("HZ", tmp);
|
addenv("HZ", tmp);
|
||||||
|
#ifndef __FreeBSD__
|
||||||
} else if ((cp = getdef_str("ENV_HZ")))
|
} else if ((cp = getdef_str("ENV_HZ")))
|
||||||
addenv(cp, NULL);
|
addenv(cp, NULL);
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -471,24 +487,8 @@ int main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
openlog("mblogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
openlog("mblogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
|
||||||
|
|
||||||
setup_tty();
|
setup_tty();
|
||||||
|
umask(007);
|
||||||
umask(getdef_num("UMASK", 077));
|
|
||||||
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Use the ULIMIT in the login.defs file, and if
|
|
||||||
* there isn't one, use the default value. The
|
|
||||||
* user may have one for themselves, but otherwise,
|
|
||||||
* just take what you get.
|
|
||||||
*/
|
|
||||||
|
|
||||||
long limit = getdef_long("ULIMIT", -1L);
|
|
||||||
|
|
||||||
if (limit != -1)
|
|
||||||
set_filesize_limit(limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pflg)
|
if (pflg)
|
||||||
while (*envp) /* add inherited environment, */
|
while (*envp) /* add inherited environment, */
|
||||||
@ -509,6 +509,8 @@ int main(int argc, char **argv)
|
|||||||
addenv("MBSE_ROOT", pw->pw_dir);
|
addenv("MBSE_ROOT", pw->pw_dir);
|
||||||
sprintf(userfile, "%s/etc/users.data", pw->pw_dir);
|
sprintf(userfile, "%s/etc/users.data", pw->pw_dir);
|
||||||
|
|
||||||
|
check_nologin(pw->pw_dir);
|
||||||
|
|
||||||
init_env();
|
init_env();
|
||||||
|
|
||||||
if (optind < argc) { /* get the user name */
|
if (optind < argc) { /* get the user name */
|
||||||
@ -572,13 +574,13 @@ int main(int argc, char **argv)
|
|||||||
top:
|
top:
|
||||||
/* only allow ALARM sec. for login */
|
/* only allow ALARM sec. for login */
|
||||||
signal(SIGALRM, alarm_handler);
|
signal(SIGALRM, alarm_handler);
|
||||||
timeout = getdef_num("LOGIN_TIMEOUT", ALARM);
|
timeout = LOGIN_TIMEOUT;
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
alarm(timeout);
|
alarm(timeout);
|
||||||
|
|
||||||
environ = newenvp; /* make new environment active */
|
environ = newenvp; /* make new environment active */
|
||||||
delay = getdef_num("FAIL_DELAY", 1);
|
delay = LOGIN_DELAY;
|
||||||
retries = getdef_num("LOGIN_RETRIES", RETRIES);
|
retries = LOGIN_RETRIES;
|
||||||
|
|
||||||
while (1) { /* repeatedly get login/password pairs */
|
while (1) { /* repeatedly get login/password pairs */
|
||||||
failed = 0; /* haven't failed authentication yet */
|
failed = 0; /* haven't failed authentication yet */
|
||||||
@ -588,35 +590,32 @@ top:
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
preauth_flag = 0;
|
preauth_flag = 0;
|
||||||
#ifndef LOGIN_PROMPT
|
|
||||||
#ifdef __linux__ /* hostname login: - like in util-linux login */
|
|
||||||
login_prompt(_("\n%s login: "), username, sizeof username);
|
|
||||||
#else
|
|
||||||
login_prompt(_("login: "), username, sizeof username);
|
login_prompt(_("login: "), username, sizeof username);
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
login_prompt(LOGIN_PROMPT, username, sizeof username);
|
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we try usernames on unix names and Fidonet style
|
* Here we try usernames on unix names and Fidonet style
|
||||||
* names that are stored in the bbs userdatabase.
|
* names that are stored in the bbs userdatabase.
|
||||||
|
* The name "bbs" is for new users, don't check the bbs userfile.
|
||||||
*/
|
*/
|
||||||
FoundName = 0;
|
if (strcmp(username, "bbs") == 0) {
|
||||||
if ((ufp = fopen(userfile, "r"))) {
|
FoundName = 1;
|
||||||
fread(&usrconfighdr, sizeof(usrconfighdr), 1, ufp);
|
} else {
|
||||||
while (fread(&usrconfig, usrconfighdr.recsize, 1, ufp) == 1) {
|
FoundName = 0;
|
||||||
if ((strcasecmp(usrconfig.sUserName, username) == 0) ||
|
if ((ufp = fopen(userfile, "r"))) {
|
||||||
(strcasecmp(usrconfig.sHandle, username) == 0) ||
|
fread(&usrconfighdr, sizeof(usrconfighdr), 1, ufp);
|
||||||
(strcmp(usrconfig.Name, username) == 0)) {
|
while (fread(&usrconfig, usrconfighdr.recsize, 1, ufp) == 1) {
|
||||||
FoundName = 1;
|
if ((strcasecmp(usrconfig.sUserName, username) == 0) ||
|
||||||
STRFCPY(username, usrconfig.Name);
|
(strcasecmp(usrconfig.sHandle, username) == 0) ||
|
||||||
break;
|
(strcmp(usrconfig.Name, username) == 0)) {
|
||||||
|
FoundName = 1;
|
||||||
|
STRFCPY(username, usrconfig.Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
fclose(ufp);
|
||||||
}
|
}
|
||||||
fclose(ufp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((! (pwd = getpwnam(username))) || (FoundName == 0)) {
|
if ((! (pwd = getpwnam(username))) || (FoundName == 0)) {
|
||||||
@ -664,7 +663,7 @@ top:
|
|||||||
* username at least once... Should probably use LOG_AUTHPRIV
|
* username at least once... Should probably use LOG_AUTHPRIV
|
||||||
* for those who really want to log them. --marekm
|
* for those who really want to log them. --marekm
|
||||||
*/
|
*/
|
||||||
syslog(LOG_WARNING, BAD_PASSWD, (pwd || getdef_bool("LOG_UNKFAIL_ENAB")) ? username : "UNKNOWN", fromhost);
|
syslog(LOG_WARNING, BAD_PASSWD, "UNKNOWN", fromhost);
|
||||||
failed = 1;
|
failed = 1;
|
||||||
|
|
||||||
auth_ok:
|
auth_ok:
|
||||||
@ -694,28 +693,6 @@ auth_ok:
|
|||||||
if (! failed)
|
if (! failed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (getdef_str("FTMP_FILE") != NULL) {
|
|
||||||
const char *failent_user;
|
|
||||||
#if HAVE_UTMPX_H
|
|
||||||
failent = utxent;
|
|
||||||
gettimeofday(&(failent.ut_tv), NULL);
|
|
||||||
#else
|
|
||||||
failent = utent;
|
|
||||||
time(&failent.ut_time);
|
|
||||||
#endif
|
|
||||||
if (pwd) {
|
|
||||||
failent_user = pwent.pw_name;
|
|
||||||
} else {
|
|
||||||
if (getdef_bool("LOG_UNKFAIL_ENAB"))
|
|
||||||
failent_user = username;
|
|
||||||
else
|
|
||||||
failent_user = "UNKNOWN";
|
|
||||||
}
|
|
||||||
strncpy(failent.ut_user, failent_user, sizeof(failent.ut_user));
|
|
||||||
#ifdef USER_PROCESS
|
|
||||||
failent.ut_type = USER_PROCESS;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
memzero(username, sizeof username);
|
memzero(username, sizeof username);
|
||||||
|
|
||||||
if (--retries <= 0)
|
if (--retries <= 0)
|
||||||
@ -760,8 +737,6 @@ auth_ok:
|
|||||||
// }
|
// }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_nologin();
|
|
||||||
|
|
||||||
if (getenv("IFS")) /* don't export user IFS ... */
|
if (getenv("IFS")) /* don't export user IFS ... */
|
||||||
addenv("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
|
addenv("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
|
||||||
|
|
||||||
@ -783,8 +758,8 @@ auth_ok:
|
|||||||
#endif
|
#endif
|
||||||
goto top; /* go do all this all over again */
|
goto top; /* go do all this all over again */
|
||||||
}
|
}
|
||||||
if (getdef_bool("LASTLOG_ENAB")) /* give last login and log this one */
|
|
||||||
dolastlog(&lastlog, &pwent, utent.ut_line, hostname);
|
dolastlog(&lastlog, &pwent, utent.ut_line, hostname);
|
||||||
|
|
||||||
#ifdef SVR4_SI86_EUA
|
#ifdef SVR4_SI86_EUA
|
||||||
sysi86(SI86LIMUSER, EUA_ADD_USER); /* how do we test for fail? */
|
sysi86(SI86LIMUSER, EUA_ADD_USER); /* how do we test for fail? */
|
||||||
@ -865,9 +840,8 @@ auth_ok:
|
|||||||
else
|
else
|
||||||
syslog(LOG_INFO, REG_LOGIN, username, fromhost);
|
syslog(LOG_INFO, REG_LOGIN, username, fromhost);
|
||||||
closelog();
|
closelog();
|
||||||
if ((tmp = getdef_str("FAKE_SHELL")) != NULL) {
|
|
||||||
shell(tmp, pwent.pw_shell); /* fake shell */
|
sleep(3);
|
||||||
}
|
|
||||||
shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
|
shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -222,9 +222,6 @@ void pwd_init(void)
|
|||||||
#ifdef RLIMIT_STACK
|
#ifdef RLIMIT_STACK
|
||||||
setrlimit(RLIMIT_STACK, &rlim);
|
setrlimit(RLIMIT_STACK, &rlim);
|
||||||
#endif
|
#endif
|
||||||
#else /* !HAVE_SYS_RESOURCE_H */
|
|
||||||
set_filesize_limit(30000);
|
|
||||||
/* don't know how to set the other limits... */
|
|
||||||
#endif /* !HAVE_SYS_RESOURCE_H */
|
#endif /* !HAVE_SYS_RESOURCE_H */
|
||||||
|
|
||||||
signal(SIGALRM, SIG_IGN);
|
signal(SIGALRM, SIG_IGN);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
* Purpose ...............: MBSE BBS Shadow Password Suite
|
* Purpose ...............: MBSE BBS Shadow Password Suite
|
||||||
* Original Source .......: Shadow Password Suite
|
* Original Source .......: Shadow Password Suite
|
||||||
* Original Copyrioght ...: Julianne Frances Haugh and others.
|
* Original Copyright ....: Julianne Frances Haugh and others.
|
||||||
*
|
*
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
* Copyright (C) 1997-2002
|
* Copyright (C) 1997-2002
|
||||||
@ -100,8 +100,7 @@ int pw_auth(const char *cipher, const char *user, int reason, const char *input)
|
|||||||
* get the cleartext password for us.
|
* get the cleartext password for us.
|
||||||
*/
|
*/
|
||||||
if (reason != PW_FTP && reason != PW_REXEC && !input) {
|
if (reason != PW_FTP && reason != PW_REXEC && !input) {
|
||||||
if (! (cp = getdef_str ("LOGIN_STRING")))
|
cp = PROMPT;
|
||||||
cp = PROMPT;
|
|
||||||
snprintf(prompt, sizeof prompt, cp, user);
|
snprintf(prompt, sizeof prompt, cp, user);
|
||||||
clear = getpass(prompt);
|
clear = getpass(prompt);
|
||||||
if (!clear) {
|
if (!clear) {
|
||||||
|
@ -109,8 +109,6 @@ void read_env_file(const char *filename)
|
|||||||
*/
|
*/
|
||||||
void setup_env(struct passwd *info)
|
void setup_env(struct passwd *info)
|
||||||
{
|
{
|
||||||
char *cp, *envf;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the current working directory to be the home directory
|
* Change the current working directory to be the home directory
|
||||||
* of the user. It is a fatal error for this process to be unable
|
* of the user. It is a fatal error for this process to be unable
|
||||||
@ -118,32 +116,23 @@ void setup_env(struct passwd *info)
|
|||||||
* directory.
|
* directory.
|
||||||
*
|
*
|
||||||
* We no longer do it as root - should work better on NFS-mounted
|
* We no longer do it as root - should work better on NFS-mounted
|
||||||
* home directories. Some systems default to HOME=/, so we make
|
* home directories.
|
||||||
* this a configurable option. --marekm
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (chdir(info->pw_dir) == -1) {
|
if (chdir(info->pw_dir) == -1) {
|
||||||
static char temp_pw_dir[] = "/";
|
fprintf(stderr, _("Unable to cd to \"%s\"\n"), info->pw_dir);
|
||||||
if (!getdef_bool("DEFAULT_HOME") || chdir("/") == -1) {
|
syslog(LOG_WARNING, "unable to cd to `%s' for user `%s'\n", info->pw_dir, info->pw_name);
|
||||||
fprintf(stderr, _("Unable to cd to \"%s\"\n"), info->pw_dir);
|
closelog();
|
||||||
syslog(LOG_WARNING, "unable to cd to `%s' for user `%s'\n", info->pw_dir, info->pw_name);
|
exit (1);
|
||||||
closelog();
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
puts(_("No directory, logging in with HOME=/"));
|
|
||||||
info->pw_dir = temp_pw_dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the HOME environmental variable and export it.
|
* Create the HOME environmental variable and export it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
addenv("HOME", info->pw_dir);
|
addenv("HOME", info->pw_dir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the SHELL environmental variable and export it.
|
* Create the SHELL environmental variable and export it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (info->pw_shell == (char *) 0 || ! *info->pw_shell) {
|
if (info->pw_shell == (char *) 0 || ! *info->pw_shell) {
|
||||||
static char temp_pw_shell[] = "/bin/sh";
|
static char temp_pw_shell[] = "/bin/sh";
|
||||||
info->pw_shell = temp_pw_shell;
|
info->pw_shell = temp_pw_shell;
|
||||||
@ -154,9 +143,7 @@ void setup_env(struct passwd *info)
|
|||||||
/*
|
/*
|
||||||
* Create the PATH environmental variable and export it.
|
* Create the PATH environmental variable and export it.
|
||||||
*/
|
*/
|
||||||
|
addenv("PATH=/bin:/usr/bin", NULL);
|
||||||
cp = getdef_str( info->pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
|
|
||||||
addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Export the user name. For BSD derived systems, it's "USER", for
|
* Export the user name. For BSD derived systems, it's "USER", for
|
||||||
@ -165,34 +152,5 @@ void setup_env(struct passwd *info)
|
|||||||
|
|
||||||
addenv("USER", info->pw_name);
|
addenv("USER", info->pw_name);
|
||||||
addenv("LOGNAME", info->pw_name);
|
addenv("LOGNAME", info->pw_name);
|
||||||
|
|
||||||
/*
|
|
||||||
* MAILDIR environment variable for Qmail
|
|
||||||
*/
|
|
||||||
// if ((cp=getdef_str("QMAIL_DIR")))
|
|
||||||
// addenv_path("MAILDIR", info->pw_dir, cp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the MAIL environmental variable and export it. login.defs
|
|
||||||
* knows the prefix.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// if ((cp=getdef_str("MAIL_DIR")))
|
|
||||||
// addenv_path("MAIL", cp, info->pw_name);
|
|
||||||
// else if ((cp=getdef_str("MAIL_FILE")))
|
|
||||||
// addenv_path("MAIL", info->pw_dir, cp);
|
|
||||||
// else {
|
|
||||||
//#if defined(MAIL_SPOOL_FILE)
|
|
||||||
// addenv_path("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
|
|
||||||
//#elif defined(MAIL_SPOOL_DIR)
|
|
||||||
// addenv_path("MAIL", MAIL_SPOOL_DIR, info->pw_name);
|
|
||||||
//#endif
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read environment from optional config file. --marekm
|
|
||||||
*/
|
|
||||||
if ((envf = getdef_str("ENVIRON_FILE")))
|
|
||||||
read_env_file(envf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user