home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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
-