home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 3
/
Meeting_Pearls_III.iso
/
Pearls
/
tcp
/
Networking
/
TCP
/
Server
/
wu-ftpd
/
src
/
amiga.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-25
|
14KB
|
710 lines
/*
* Amiga support routines for chroot() emulation,
* some MultiUser support routines, alarm() and
* setproctitle().
*
* © 1994 Blaz Zupan, <blaz.zupan@uni-mb.si>
* All Rights Reserved
*
*/
#include <exec/memory.h>
#include <devices/timer.h>
#include <libraries/multiuser.h>
#include <proto/multiuser.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/usergroup.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include "extensions.h"
#include "config.h"
#include "AmiTCP:src/netlib/netlib.h"
extern char *amigausername;
extern struct muBase *muBase;
/*
* This routine is an attempt to emulate the Unix chroot()
* function. It only saves the name supplied in the global
* AmigaRootDir. Everything else must be done by CheckAccess().
*/
extern int anonymous, guest;
char AmigaRootDir[MAXPATHLEN + 2] = "";
int
chroot (char *dir)
{
BPTR lock;
if (lock = Lock (dir, SHARED_LOCK))
{
NameFromLock (lock, AmigaRootDir, MAXPATHLEN);
UnLock (lock);
return 0;
}
return -1;
}
/*
* Checks if pathname "name1" is above
* "name" in directory structure.
*/
static BOOL
IsParent (char *name1, char *name2)
{
BOOL ret = 0;
BPTR l1;
if (l1 = Lock (name1, SHARED_LOCK))
{
BPTR l2;
if (l2 = Lock (name2, SHARED_LOCK))
{
switch (SameLock (l1, l2))
{
case LOCK_DIFFERENT:
break;
case LOCK_SAME:
ret = 2;
break;
case LOCK_SAME_VOLUME:
{
BPTR l;
while (l2)
{
l = l2;
l2 = ParentDir (l);
UnLock (l);
if (SameLock (l1, l2) == LOCK_SAME)
{
ret = 1;
break;
}
}
break;
}
}
UnLock (l2);
}
UnLock (l1);
}
return ret;
}
/* Compare two strings with pattern matching */
static BOOL
mymatch (char *pattern, char *string)
{
BOOL ret = FALSE;
char *parsedpattern;
long len = strlen (pattern) * 2 + 10;
long oldflags = DOSBase->dl_Root->rn_Flags;
DOSBase->dl_Root->rn_Flags |= RNF_WILDSTAR; /* turn on recognitions of star as wildcard */
if (parsedpattern = malloc (len))
{
if (ParsePattern (pattern, parsedpattern, len) != -1)
ret = MatchPattern (parsedpattern, string);
free (parsedpattern);
}
DOSBase->dl_Root->rn_Flags = oldflags; /* restore original flags */
return ret;
}
/* Checks if user is allowed to access file/directory.
* If create == TRUE check for parent of specified name
* (this is used if we want to check if user is allowed
* to access the directory into which a file should be
* created - so no "put <something> AmiTCP:db/passwd"
* hacks are possible).
*/
BOOL
CheckAccess (char *dir, BOOL create)
{
BPTR lock;
char name[MAXPATHLEN];
struct aclmember *entry = NULL;
strcpy (name, dir);
lock = Lock (name, SHARED_LOCK);
if (!lock && create)
{
*(FilePart (name)) = 0;
lock = Lock (name, SHARED_LOCK);
}
if (lock)
UnLock (lock);
else
/* If we could not access file/directory then return "OK"
* for now because access will be denied later by the
* command that called us.
*/
return TRUE;
/* first check if directory is on "deny" list */
while (getaclentry ("denydir", &entry) && ARG0 && ARG1)
{
if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
return FALSE;
}
/* now see if it is under root dir */
if (IsParent (AmigaRootDir, name))
return TRUE;
/* check if access is allowed even if dir is not under root */
else
{
entry = NULL;
while (getaclentry ("allowdir", &entry) && ARG0 && ARG1)
{
if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
return TRUE;
}
}
/* If directory is not on deny or allow list and not
* under root directory then we allow access for
* real users and don't allow access for guests.
*/
if (!anonymous && !guest)
return TRUE;
else
return FALSE;
}
/*
* Simulate Unix geteuid() call with MultiUser.
*/
int
amiga_geteuid (void)
{
if (muBase)
return ((muGetTaskOwner (FindTask (NULL)) & muMASK_UID) >> 16);
else
#undef geteuid
return (geteuid ());
}
/*
* Simulate Unix seteuid() call with MultiUser.
* You have to be logged in as root initially for this
* routine to work (after that it correctly keeps track
* of the user).
*/
int
amiga_seteuid (int u)
{
if (muBase)
{
ULONG tags[5];
int res = -1;
if (u == 0)
{
int uid;
uid = amiga_geteuid ();
/* Are we already root? */
if (uid == muROOT_UID)
return 0;
/* We can't set effective user ID to root
* if we are currently logged in as nobody
*/
if (uid == muNOBODY_UID)
return -1;
/* Now logout until we become either root or
* nobody. If we become nobody we fail.
*/
do
{
tags[0] = muT_Quiet;
tags[1] = TRUE;
tags[2] = TAG_END;
muLogoutA (tags);
uid = amiga_geteuid ();
}
while (uid != muROOT_UID && uid != muNOBODY_UID);
return ((uid == muROOT_UID) ? 0 : -1);
}
/* Check if we are maybe already logged in as that user. */
if (u == amiga_geteuid ())
return 0;
/* Ok, so we are trying to login as someone else.
* first make sure that we are root. */
if (amiga_seteuid (0) != -1)
{
struct muUserInfo *ui;
if (ui = muAllocUserInfo ())
{
ui->uid = u;
if (muGetUserInfo (ui, muKeyType_uid))
{
tags[0] = muT_UserID;
tags[1] = (ULONG) ui->UserID;
tags[2] = muT_NoLog;
tags[3] = TRUE;
tags[4] = TAG_END;
res = (muLoginA (tags) ? 0 : -1);
}
muFreeUserInfo (ui);
}
}
return res;
}
/* MultiUser is not installed so use dummy
* usergroup.library call.
*/
#undef seteuid
return (seteuid (u));
}
/*
* Simulate Unix seteuid() call with MultiUser.
* You have to be logged in as root initially for this
* routine to work (after that it correctly keeps track
* of the user).
*/
int
amiga_setegid (int g)
{
/* We can't set another group under
* MultiUser so we fail.
*/
if (muBase)
return -1;
/* MultiUser is not installed so use dummy
* usergroup.library call.
*/
#undef setegid
return (setegid (g));
}
/*
* Simulate Unix getpwnam() call with MultiUser.
*/
static struct passwd p;
char dummypas[] = "";
struct passwd *
amiga_getpwnam (char *name)
{
if (muBase)
{
struct muUserInfo *ui;
BOOL ok = FALSE;
if (ui = muAllocUserInfo ())
{
strcpy (ui->UserID, name);
if (muGetUserInfo (ui, muKeyType_UserID))
{
ok = TRUE;
p.pw_uid = ui->uid;
p.pw_gid = ui->gid;
if (p.pw_name)
free (p.pw_name);
if (p.pw_name = malloc (strlen (ui->UserID) + 1))
strcpy (p.pw_name, ui->UserID);
else
ok = FALSE;
p.pw_passwd = "";
if (p.pw_gecos)
free (p.pw_gecos);
if (p.pw_gecos = malloc (strlen (ui->UserName) + 1))
strcpy (p.pw_gecos, ui->UserName);
else
ok = FALSE;
if (p.pw_dir)
free (p.pw_dir);
if (p.pw_dir = malloc (strlen (ui->HomeDir) + 1))
strcpy (p.pw_dir, ui->HomeDir);
else
ok = FALSE;
if (p.pw_shell)
free (p.pw_shell);
if (p.pw_shell = malloc (strlen (ui->Shell) + 1))
strcpy (p.pw_shell, ui->Shell);
else
ok = FALSE;
}
muFreeUserInfo (ui);
}
if (!ok)
return (NULL);
return (&p);
}
#undef getpwnam
return (getpwnam (name));
}
/*
* Simulate Unix getgrnam() call with MultiUser.
*/
static struct group g;
struct group *
amiga_getgrnam (char *name)
{
if (muBase)
{
struct muGroupInfo *gi;
BOOL ok = FALSE;
if (gi = muAllocGroupInfo ())
{
strcpy (gi->GroupID, name);
if (muGetGroupInfo (gi, muKeyType_GroupID))
{
static char *dummy_memb = NULL;
ok = TRUE;
g.gr_gid = gi->gid;
if (g.gr_name)
free (g.gr_name);
if (g.gr_name = malloc (strlen (gi->GroupID) + 1))
strcpy (g.gr_name, gi->GroupID);
else
ok = FALSE;
g.gr_passwd = "";
g.gr_mem = &dummy_memb;
}
muFreeGroupInfo (gi);
}
if (!ok)
return (NULL);
return (&g);
}
#undef getgrnam
return (getgrnam (name));
}
/*
* Simulate Unix umask() call with MultiUser.
*/
const static BYTE abits[8] =
{
0, 0x2, 0x5, 0x7, 0x8, 0xA, 0xD, 0xF,
};
const static UBYTE ubits[16] =
{
0, 2, 1, 3, 2, 2, 3, 3,
4, 6, 5, 7, 6, 6, 7, 7,
};
ULONG
U2A_prot (mode_t mode)
{
return ((abits[mode & 7] << FIBB_OTR_DELETE) |
(abits[(mode >> 3) & 7] << FIBB_GRP_DELETE) |
(abits[(mode >> 6) & 7] ^ 0xf));
}
mode_t
A2U_prot (ULONG mode)
{
return ((ubits[(mode ^ 0xf) & 0xf] << 6) |
(ubits[((mode ^ 0xf) >> FIBB_GRP_DELETE) & 0xf] << 3) |
(ubits[((mode ^ 0xf) >> FIBB_OTR_DELETE) & 0xf]));
}
mode_t
amiga_umask (mode_t m)
{
if (muBase)
{
ULONG oldmask;
oldmask = muGetDefProtection (NULL);
muSetDefProtection (muT_DefProtection, U2A_prot (m), TAG_END);
return (A2U_prot (oldmask));
}
#undef umask
return (umask (m));
}
mode_t
amiga_getumask (void)
{
if (muBase)
return (A2U_prot (muGetDefProtection (NULL)));
#undef getumask
return (getumask ());
}
/* Use MultiUser function to set protection flags if
* MultiUser is installed, otherwise use original SetProtection()
* command.
*/
int
amiga_chmod (const char *path, int mode)
{
if (muBase)
{
if (!muSetProtection ((STRPTR) path, U2A_prot (mode)))
{
set_errno (IoErr ());
return -1;
}
else
return 0;
}
else
{
if (!SetProtection ((STRPTR) path, U2A_prot (mode)))
{
set_errno (IoErr ());
return -1;
}
else
return 0;
}
}
/* dummy stub function for compatibility with original source */
FILE *
ftpd_popen (char *program, char *type, int closestderr)
{
if (strpbrk (program, "`><|"))
return (NULL);
return (popen (program, type));
}
/* dummy stub function for compatibility with original source */
void
ftpd_pclose (FILE * iop)
{
pclose (iop);
}
/*
* This is a stub function which is called when
* the SIGINT signal arrives. It checks if maybe
* this SIGINT is a SIGALRM and executes the
* appropriate function.
*/
void (*intfunc) (int) = NULL;
void (*alrmfunc) (int) = NULL;
BOOL isalrm = FALSE;
void
amiga_sigalrm (int signum)
{
#undef signal
signal (SIGINT, amiga_sigalrm);
if (isalrm) /* Did we really get a SIGALRM? */
{
isalrm = FALSE;
(*alrmfunc) (SIGALRM); /* Yes, execute SIGALRM function */
}
else
(*intfunc) (SIGINT); /* No, it was a standard ctrl-c */
}
/*
* This is my implementation of the Unix alarm() function.
* Is kind of a hack, because when the time expires it sends
* a break signal (control-c) to itself, the break routine
* then notices that it was called from an alarm() and
* executes the proper code. A hack, but it works :-)
*/
struct Task *ThisTask;
struct MsgPort *TimerPort = NULL;
struct timerequest *TimerIO = NULL;
struct Interrupt *TimerInterrupt = NULL;
BOOL deviceopen = FALSE, alarmon = FALSE;
void __saveds __interrupt
IntFunc (void)
{
struct Message *msg;
if ((msg = GetMsg (TimerPort)) && alarmon)
{
isalrm = TRUE;
Signal (ThisTask, SIGBREAKF_CTRL_C);
}
}
void
cleanup_alarm (void)
{
if (TimerIO)
{
alarmon = FALSE;
if (!CheckIO (TimerIO))
{
AbortIO (TimerIO);
WaitIO (TimerIO);
}
}
if (deviceopen)
{
CloseDevice (TimerIO);
deviceopen = FALSE;
}
if (TimerIO)
{
DeleteExtIO (TimerIO);
TimerIO = NULL;
}
if (TimerPort)
{
FreeVec (TimerPort);
TimerPort = NULL;
}
if (TimerInterrupt)
{
FreeVec (TimerInterrupt);
TimerInterrupt = NULL;
}
}
int
alarm (int t)
{
if (t == 0)
{
alarmon = FALSE;
/* delete previous timer request */
if (TimerIO)
{
if (!CheckIO (TimerIO))
{
AbortIO (TimerIO);
WaitIO (TimerIO);
}
}
}
else
{
ThisTask = FindTask (NULL);
if (!TimerInterrupt)
{
if (TimerInterrupt = AllocVec (sizeof (struct Interrupt), MEMF_CLEAR))
{
TimerInterrupt->is_Node.ln_Type = NT_INTERRUPT;
TimerInterrupt->is_Code = &IntFunc;
}
}
if (TimerInterrupt && !TimerPort)
{
if (TimerPort = AllocVec (sizeof (struct MsgPort), MEMF_CLEAR))
{
TimerPort->mp_Node.ln_Type = NT_MSGPORT;
TimerPort->mp_Flags = PA_SOFTINT; /* cause a software interrupt when signal arrives */
TimerPort->mp_SoftInt = TimerInterrupt;
NewList (&(TimerPort->mp_MsgList));
}
}
if (TimerPort && !TimerIO)
TimerIO = (struct timerequest *) CreateExtIO (TimerPort, sizeof (struct timerequest));
if (TimerPort && TimerIO && !deviceopen)
{
deviceopen = (!OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerIO, 0));
if (deviceopen)
atexit (cleanup_alarm);
}
if (deviceopen)
{
alarmon = FALSE;
if (!CheckIO (TimerIO))
{
AbortIO (TimerIO);
WaitIO (TimerIO);
}
TimerIO->tr_node.io_Command = TR_ADDREQUEST;
TimerIO->tr_time.tv_secs = t;
TimerIO->tr_time.tv_micro = 0;
alarmon = TRUE;
BeginIO ((struct IORequest *) TimerIO);
}
else
cleanup_alarm ();
}
}
/*
* This is a new signal() function that also knows
* about SIGALRM (it installs SIGALRM as SIGINT with
* a special handler that knows about both SIGALRM and
* SIGINT).
*/
void
(*amiga_signal (int signum, void (*sigfunc) (int))) (int)
{
void (*oldfunc) (int) = NULL;
if (signum == SIGALRM || signum == SIGINT)
{
if (!intfunc)
intfunc = signal (SIGINT, amiga_sigalrm);
if (signum == SIGINT)
{
oldfunc = intfunc;
intfunc = sigfunc;
}
else
{
oldfunc = alrmfunc;
alrmfunc = sigfunc;
}
}
else
return (signal (signum, sigfunc));
return oldfunc;
}
#ifdef SETPROCTITLE
/* Sets name of currently running program. */
void
setproctitle (const char *fmt,...)
{
va_list args;
char *text;
if (text = malloc (BUFSIZ))
{
char *newfmt;
if (newfmt = malloc (strlen (fmt) + sizeof ("ftpd: ")))
{
sprintf (newfmt, "ftpd: %s", fmt);
va_start (args, fmt);
vsprintf (text, newfmt, args);
SetProgramName (text);
va_end (args);
free (newfmt);
}
else
SetProgramName ("ftpd");
free (text);
}
else
SetProgramName ("ftpd");
}
#endif