935 lines
24 KiB
C
935 lines
24 KiB
C
/*
|
||
** $Id: vboxgetty.c,v 1.10 1998/11/10 18:36:35 michael Exp $
|
||
**
|
||
** Copyright 1996-1998 Michael 'Ghandi' Herold <michael@abadonna.mayn.de>
|
||
*/
|
||
|
||
#ifdef HAVE_CONFIG_H
|
||
# include "../config.h"
|
||
#endif
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <getopt.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <signal.h>
|
||
#include <limits.h>
|
||
#include <errno.h>
|
||
#include <fnmatch.h>
|
||
#include <pwd.h>
|
||
#include <grp.h>
|
||
#include <sys/stat.h>
|
||
|
||
|
||
#include "log.h"
|
||
#include "tcl.h"
|
||
#include "modem.h"
|
||
#include "rc.h"
|
||
#include "vboxrc.h"
|
||
#include "voice.h"
|
||
#include "stringutils.h"
|
||
#include "tclscript.h"
|
||
#include "vboxgetty.h"
|
||
#include "control.h"
|
||
#include "lock.h"
|
||
#include "breaklist.h"
|
||
|
||
/** Variables ************************************************************/
|
||
|
||
static unsigned char *progbasename;
|
||
static unsigned char *isdnttyname;
|
||
|
||
unsigned char temppathname[PATH_MAX + 1];
|
||
unsigned char savettydname[NAME_MAX + 1];
|
||
|
||
/** Structures ***********************************************************/
|
||
|
||
static struct vboxrc rc_getty_c[] =
|
||
{
|
||
{ "init" , NULL },
|
||
{ "initnumber" , NULL },
|
||
{ "badinitsexit" , NULL },
|
||
{ "initpause" , NULL },
|
||
{ "commandtimeout", NULL },
|
||
{ "echotimeout" , NULL },
|
||
{ "ringtimeout" , NULL },
|
||
{ "alivetimeout" , NULL },
|
||
{ "spooldir" , NULL },
|
||
{ "toggledtrtime" , NULL },
|
||
{ NULL , NULL }
|
||
};
|
||
|
||
static struct option arguments[] =
|
||
{
|
||
{ "version" , no_argument , NULL, 'v' },
|
||
{ "help" , no_argument , NULL, 'h' },
|
||
{ "debug" , required_argument, NULL, 'x' },
|
||
{ "device" , required_argument, NULL, 'd' },
|
||
{ NULL , 0 , NULL, 0 }
|
||
};
|
||
|
||
struct vboxmodem vboxmodem;
|
||
|
||
/** Prototypes ***********************************************************/
|
||
|
||
static int vboxgettyrc_parse(unsigned char *);
|
||
static int userrc_parse(struct vboxuser *, unsigned char *);
|
||
static int process_incoming_call(void);
|
||
static int run_modem_init(void);
|
||
static void pid_create(unsigned char *);
|
||
static void pid_remove(unsigned char *);
|
||
static void show_usage(int, int);
|
||
|
||
/*************************************************************************
|
||
** The magic main... **
|
||
*************************************************************************/
|
||
|
||
void main(int argc, char **argv)
|
||
{
|
||
char *stop;
|
||
int opts;
|
||
char *debugstr;
|
||
int debuglvl;
|
||
int i;
|
||
int modemstate;
|
||
int modeminits;
|
||
|
||
breaklist_init();
|
||
|
||
progbasename = argv[0];
|
||
|
||
if ((stop = rindex(argv[0], '/'))) progbasename = ++stop;
|
||
|
||
/* Die Argumente des Programms einlesen und den Debuglevel */
|
||
/* setzen. */
|
||
|
||
debugstr = NULL;
|
||
isdnttyname = NULL;
|
||
|
||
while ((opts = getopt_long(argc, argv, "vhx:d:", arguments, (int *)0)) != EOF)
|
||
{
|
||
switch (opts)
|
||
{
|
||
case 'x':
|
||
debugstr = optarg;
|
||
break;
|
||
|
||
case 'd':
|
||
isdnttyname = optarg;
|
||
break;
|
||
|
||
case 'v':
|
||
show_usage(200, 0);
|
||
break;
|
||
|
||
case 'h':
|
||
default:
|
||
show_usage(200, 1);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (debugstr)
|
||
{
|
||
if (strcasecmp(debugstr, "FULL") != 0)
|
||
{
|
||
debuglvl = LOG_E;
|
||
|
||
for (i = 0; i < strlen(debugstr); i++)
|
||
{
|
||
switch (debugstr[i])
|
||
{
|
||
case 'W':
|
||
case 'w':
|
||
debuglvl |= LOG_W;
|
||
break;
|
||
|
||
case 'I':
|
||
debuglvl |= LOG_I;
|
||
break;
|
||
|
||
case 'A':
|
||
debuglvl |= LOG_A;
|
||
break;
|
||
|
||
case 'D':
|
||
debuglvl |= LOG_D;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else debuglvl = LOG_X;
|
||
|
||
log_set_debuglevel(debuglvl);
|
||
}
|
||
|
||
umask(xstrtoo(VBOX_ROOT_UMASK, 0));
|
||
|
||
/* Pfadangaben vom Devicenamen abschneiden und <20>berpr<70>fen ob */
|
||
/* das Device vom Benutzer gelesen und beschrieben werden */
|
||
/* kann (eigentlich nicht n<>tig, da nur unter Rootrechten ge- */
|
||
/* startet werden kann. */
|
||
|
||
if (isdnttyname)
|
||
{
|
||
if ((stop = rindex(isdnttyname, '/'))) isdnttyname = ++stop;
|
||
|
||
printstring(savettydname, "%s" , isdnttyname);
|
||
printstring(temppathname, "/dev/%s", isdnttyname);
|
||
|
||
if (access(temppathname, F_OK|R_OK|W_OK) != 0)
|
||
{
|
||
fprintf(stderr, "\n%s: error: \"%s\" doesn't exist or is not accessible!\n\n", progbasename, temppathname);
|
||
|
||
quit_program(100);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fprintf(stderr, "\n%s: error: isdn tty name is required!\n", progbasename);
|
||
|
||
show_usage(100, 1);
|
||
}
|
||
|
||
/* Pr<50>fen ob das Programm unter Rootrechten gestartet wurde. Die */
|
||
/* Rechte werden sp<73>ter auf die des jeweiligen Benutzers ge<67>n- */
|
||
/* dert, zum Start sind aber Rootrechte n<>tig. */
|
||
|
||
if (getuid() != 0)
|
||
{
|
||
fprintf(stderr, "\n%s: error: need root privilegs to start!\n\n", progbasename);
|
||
|
||
quit_program(100);
|
||
}
|
||
|
||
/* Jetzt wird der Log ge<67>ffnet. Der Name des aktuellen Devices */
|
||
/* wird an das Ende angeh<65>ngt. */
|
||
|
||
printstring(temppathname, "%s/vboxgetty-%s.log", LOGDIR, isdnttyname);
|
||
|
||
log_open(temppathname);
|
||
|
||
/* Tcl-Interpreter starten. F<>r die momentanen Funktionen wird */
|
||
/* Version 8 oder h<>her ben<65>tigt. */
|
||
|
||
if (scr_create_interpreter() == -1)
|
||
{
|
||
log_line(LOG_E, "Can't create/initialize the tcl interpreter!\n");
|
||
|
||
quit_program(100);
|
||
}
|
||
|
||
log_line(LOG_I, "Running vbox version %s (with tcl version %s).\n", VERSION, scr_tcl_version());
|
||
|
||
/* Konfiguration des getty's abarbeiten. Zuerst wird die globale, */
|
||
/* dann die des jeweiligen tty's eingelesen. */
|
||
|
||
if (vboxgettyrc_parse(isdnttyname) == -1)
|
||
{
|
||
log_line(LOG_E, "Unable to read/parse configuration!\n");
|
||
|
||
quit_program(100);
|
||
}
|
||
|
||
/* Modem Device <20>ffnen und die interne Initialisierung */
|
||
/* ausf<73>hren (nicht der normale Modeminit). */
|
||
|
||
printstring(temppathname, "/dev/%s", isdnttyname);
|
||
|
||
log_line(LOG_D, "Opening modem device \"%s\" (38400, CTS/RTS)...\n", temppathname);
|
||
|
||
if (vboxmodem_open(&vboxmodem, temppathname) == -1)
|
||
{
|
||
log_line(LOG_E, "Can't open/setup modem device (%s).\n", vboxmodem_error());
|
||
|
||
quit_program(100);
|
||
}
|
||
|
||
/* Lock- und PID-Datei f<>r den getty und das entsprechende */
|
||
/* Device erzeugen. */
|
||
|
||
printstring(temppathname, "%s/LCK..%s", LOCKDIR, isdnttyname);
|
||
|
||
if (lock_create(temppathname) == -1) quit_program(100);
|
||
|
||
printstring(temppathname, "%s/vboxgetty-%s.pid", PIDDIR, isdnttyname);
|
||
|
||
pid_create(temppathname);
|
||
|
||
/* Signalh<6C>ndler installieren. Alle m<>glichen Signale werden */
|
||
/* auf quit_program() umgelenkt. */
|
||
|
||
signal(SIGINT , quit_program);
|
||
signal(SIGTERM, quit_program);
|
||
signal(SIGHUP , quit_program);
|
||
|
||
/* Hauptloop: Der Loop wird nur verlassen, wenn w<>hrend der */
|
||
/* Abarbeitung ein Fehler aufgetreten ist. Das Programm be- */
|
||
/* endet sich danach! */
|
||
|
||
modemstate = VBOXMODEM_STAT_INIT;
|
||
modeminits = 0;
|
||
|
||
while (modemstate != VBOXMODEM_STAT_EXIT)
|
||
{
|
||
switch (modemstate)
|
||
{
|
||
case VBOXMODEM_STAT_INIT:
|
||
|
||
if (run_modem_init() == -1)
|
||
{
|
||
if ((i = (int)xstrtol(rc_get_entry(rc_getty_c, "badinitsexit"), 10)) > 0)
|
||
{
|
||
modeminits++;
|
||
|
||
if (modeminits >= i)
|
||
{
|
||
modemstate = VBOXMODEM_STAT_EXIT;
|
||
modeminits = 0;
|
||
|
||
log_line(LOG_E, "Exit program while bad init limit are reached.\n");
|
||
}
|
||
else log_line(LOG_W, "Bad initialization - Program will exist on %d trys!\n", (i - modeminits));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
modemstate = VBOXMODEM_STAT_WAIT;
|
||
modeminits = 0;
|
||
}
|
||
break;
|
||
|
||
case VBOXMODEM_STAT_WAIT:
|
||
|
||
modem_flush(&vboxmodem, 0);
|
||
|
||
if (modem_wait(&vboxmodem) == 0)
|
||
{
|
||
modemstate = VBOXMODEM_STAT_RING;
|
||
modeminits = 0;
|
||
}
|
||
else modemstate = VBOXMODEM_STAT_TEST;
|
||
|
||
break;
|
||
|
||
case VBOXMODEM_STAT_TEST:
|
||
|
||
log_line(LOG_D, "Checking if modem is still alive...\n");
|
||
|
||
if (modem_command(&vboxmodem, "AT", "OK") > 0)
|
||
{
|
||
modemstate = VBOXMODEM_STAT_WAIT;
|
||
modeminits = 0;
|
||
}
|
||
else modemstate = VBOXMODEM_STAT_INIT;
|
||
|
||
break;
|
||
|
||
case VBOXMODEM_STAT_RING:
|
||
|
||
modem_set_nocarrier(&vboxmodem, 0);
|
||
process_incoming_call();
|
||
modem_hangup(&vboxmodem);
|
||
|
||
if (set_process_permissions(0, 0, xstrtoo(VBOX_ROOT_UMASK, 0)) != 0)
|
||
modemstate = VBOXMODEM_STAT_EXIT;
|
||
else
|
||
modemstate = VBOXMODEM_STAT_INIT;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
log_line(LOG_E, "Unknown modem status %d!\n", modemstate);
|
||
|
||
modemstate = VBOXMODEM_STAT_INIT;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
quit_program(0);
|
||
}
|
||
|
||
|
||
/*************************************************************************
|
||
** quit_program(): Gibt alle belegten Resourcen frei und beendet das **
|
||
** Programm. **
|
||
*************************************************************************
|
||
** => rc R<>ckgabewert des Programms (1-99 ist reserviert). **
|
||
*************************************************************************/
|
||
|
||
void quit_program(int rc)
|
||
{
|
||
set_process_permissions(0, 0, xstrtoo(VBOX_ROOT_UMASK, 0));
|
||
|
||
modem_hangup(&vboxmodem);
|
||
|
||
log_line(LOG_D, "Closing modem device (%d)...\n", vboxmodem.fd);
|
||
|
||
if (vboxmodem_close(&vboxmodem) != 0)
|
||
{
|
||
log_line(LOG_E, "%s (%s)\n", vboxmodem_error(), strerror(errno));
|
||
}
|
||
|
||
if (isdnttyname)
|
||
{
|
||
printstring(temppathname, "%s/LCK..%s", LOCKDIR, isdnttyname);
|
||
|
||
lock_remove(temppathname);
|
||
|
||
printstring(temppathname, "%s/vboxgetty-%s.pid", PIDDIR, isdnttyname);
|
||
|
||
pid_remove(temppathname);
|
||
}
|
||
|
||
scr_remove_interpreter();
|
||
rc_free(rc_getty_c);
|
||
breaklist_clear();
|
||
log_close();
|
||
|
||
exit(rc);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** show_usage(): Zeigt Benutzermeldung/Version an und beendet dann das **
|
||
** Programm. **
|
||
*************************************************************************
|
||
** => rc R<>ckgabewert des Programms (1-99 ist reserviert). **
|
||
** => help 1 wenn die Benutzermeldung oder 0 wenn die Version **
|
||
** angezeigt werden soll. **
|
||
*************************************************************************/
|
||
|
||
static void show_usage(int rc, int help)
|
||
{
|
||
if (help)
|
||
{
|
||
fprintf(stdout, "\n");
|
||
fprintf(stdout, "Usage: %s [OPTION] [OPTION] [...]\n", progbasename);
|
||
fprintf(stdout, "\n");
|
||
fprintf(stdout, "--device TTY Name of the isdn tty to use (required).\n");
|
||
fprintf(stdout, "--debug CODE Sets debug level (default \"EWI\").\n");
|
||
fprintf(stdout, "--version Display version and exit.\n");
|
||
fprintf(stdout, "--help Display this help and exit.\n");
|
||
fprintf(stdout, "\n");
|
||
fprintf(stdout, "Debugging codes:\n");
|
||
fprintf(stdout, "\n");
|
||
fprintf(stdout, "E - Error messages\n");
|
||
fprintf(stdout, "W - Warnings\n");
|
||
fprintf(stdout, "I - Informations\n");
|
||
fprintf(stdout, "A - Action messages (main routines)\n");
|
||
fprintf(stdout, "D - Debugging messages (long output)\n");
|
||
fprintf(stdout, "FULL - Full debugging\n");
|
||
fprintf(stdout, "\n");
|
||
}
|
||
else fprintf(stdout, "%s version %s\n", progbasename, VERSION);
|
||
|
||
exit(rc);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** run_modem_init(): Startet das Tcl-Skript zum initislisieren des **
|
||
** Modems. **
|
||
*************************************************************************
|
||
** <= 0 wenn die Initialisierung geklappt hat, -1 bei **
|
||
** einem Fehler. **
|
||
*************************************************************************/
|
||
|
||
static int run_modem_init(void)
|
||
{
|
||
struct vbox_tcl_variable vars[] =
|
||
{
|
||
{ "vbxv_init" , rc_get_entry(rc_getty_c, "init" ) },
|
||
{ "vbxv_initnumber" , rc_get_entry(rc_getty_c, "initnumber") },
|
||
{ NULL , NULL }
|
||
};
|
||
|
||
log_line(LOG_D, "Initializing modem...\n");
|
||
|
||
if (scr_init_variables(vars) == 0)
|
||
{
|
||
if (scr_execute("initmodem.tcl", NULL) == 0) return(0);
|
||
}
|
||
|
||
log_line(LOG_E, "Can't initialize modem device!\n");
|
||
|
||
return(-1);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*************************************************************************
|
||
** process_incoming_call(): Bearbeitet einen eingehenden Anruf. **
|
||
*************************************************************************/
|
||
|
||
static int process_incoming_call(void)
|
||
{
|
||
struct vboxuser vboxuser;
|
||
struct vboxcall vboxcall;
|
||
unsigned char line[VBOXMODEM_BUFFER_SIZE + 1];
|
||
int haverings;
|
||
int waitrings;
|
||
int usersetup;
|
||
int ringsetup;
|
||
int inputisok;
|
||
unsigned char *stop;
|
||
unsigned char *todo;
|
||
|
||
memset(&vboxuser, 0, sizeof(vboxuser));
|
||
memset(&vboxcall, 0, sizeof(vboxcall));
|
||
|
||
haverings = 0;
|
||
waitrings = -1;
|
||
usersetup = 0;
|
||
ringsetup = 0;
|
||
|
||
while (modem_read(&vboxmodem, line, modemsetup.ringtimeout) == 0)
|
||
{
|
||
inputisok = 0;
|
||
|
||
/* Wenn der Benutzer der angerufenen Nummer ermittelt ist und */
|
||
/* dessen Konfigurations abgearbeitet wurde, wird <20>berpr<70>ft ob */
|
||
/* der Anruf angenommen werden soll. */
|
||
|
||
if ((usersetup) && (ringsetup))
|
||
{
|
||
if (waitrings >= 0)
|
||
{
|
||
todo = savettydname;
|
||
stop = ctrl_exists(vboxuser.home, "answer", todo);
|
||
|
||
if (!stop)
|
||
{
|
||
todo = NULL;
|
||
stop = ctrl_exists(vboxuser.home, "answer", todo);
|
||
}
|
||
|
||
if (stop)
|
||
{
|
||
log_line(LOG_D, "Control \"vboxctrl-answer\" detected: %s (%s)...\n", stop, ((char *)todo ? (char *)todo : "global"));
|
||
|
||
if ((strcasecmp(stop, "no") == 0) || (strcasecmp(stop, "hangup") == 0) || (strcasecmp(stop, "reject") == 0))
|
||
{
|
||
log_line(LOG_D, "Incoming call will be rejected...\n");
|
||
|
||
return(0);
|
||
}
|
||
|
||
if (strcasecmp(stop, "now") != 0)
|
||
{
|
||
vboxuser.space = 0;
|
||
waitrings = xstrtol(stop, waitrings);
|
||
}
|
||
else
|
||
{
|
||
vboxuser.space = 0;
|
||
waitrings = 1;
|
||
}
|
||
|
||
log_line(LOG_D, "Call will be answered after %d ring(s).\n", waitrings);
|
||
}
|
||
}
|
||
|
||
if (waitrings > 0)
|
||
{
|
||
if (haverings >= waitrings)
|
||
{
|
||
return(voice_init(&vboxuser, &vboxcall));
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Ring abarbeiten: Beim ersten Ring wird die angerufene */
|
||
/* Nummer gesichert, die durch ATS13.7=1 mit einem Slash */
|
||
/* an den Ringstring angeh<65>ngt ist. */
|
||
|
||
if (strncmp(line, "RING/", 5) == 0)
|
||
{
|
||
inputisok++;
|
||
haverings++;
|
||
|
||
if (!ringsetup)
|
||
{
|
||
xstrncpy(vboxuser.localphone, &line[5], VBOXUSER_NUMBER);
|
||
|
||
ringsetup = 1;
|
||
}
|
||
|
||
log_line(LOG_A, "%s #%03d (%s)...\n", line, haverings, ((char *)usersetup ? (char *)vboxcall.name : "not known"));
|
||
}
|
||
|
||
/* CallerID aus dem Modeminput kopieren. Wenn bereits die */
|
||
/* angerufene Nummer ermittelt wurde, wird einmalig die */
|
||
/* Konfigurationsdatei des Benutzers abgearbeitet. */
|
||
|
||
if (strncmp(line, "CALLER NUMBER: ", 15) == 0)
|
||
{
|
||
inputisok++;
|
||
|
||
if ((ringsetup) && (!usersetup))
|
||
{
|
||
xstrncpy(vboxuser.incomingid, &line[15], VBOXUSER_CALLID);
|
||
|
||
if (userrc_parse(&vboxuser, rc_get_entry(rc_getty_c, "spooldir")) == 0)
|
||
{
|
||
if ((vboxuser.uid != 0) && (vboxuser.gid != 0))
|
||
{
|
||
/* Nachdem "vboxgetty.user" abgearbeitet ist und */
|
||
/* ein Benutzer gefunden wurde, werden einige der */
|
||
/* Kontrolldateien gel<65>scht. */
|
||
|
||
ctrl_remove(vboxuser.home, "suspend", savettydname);
|
||
ctrl_remove(vboxuser.home, "suspend", NULL );
|
||
|
||
/* Die "effective Permissions" des Prozesses auf */
|
||
/* die des Benutzers setzen und dessen Konfigurat- */
|
||
/* ionsdatei abarbeiten. */
|
||
|
||
if (set_process_permissions(vboxuser.uid, vboxuser.gid, vboxuser.umask) == 0)
|
||
{
|
||
usersetup = 1;
|
||
waitrings = vboxrc_parse(&vboxcall, vboxuser.home, vboxuser.incomingid);
|
||
|
||
if (waitrings <= 0)
|
||
{
|
||
if (waitrings < 0)
|
||
log_line(LOG_W, "Incoming call will be ignored!\n");
|
||
else
|
||
log_line(LOG_D, "Incoming call will be ignored (user setup)!\n");
|
||
}
|
||
else log_line(LOG_D, "Call will be answered after %d ring(s).\n", waitrings);
|
||
}
|
||
else return(-1);
|
||
}
|
||
else log_line(LOG_W, "Useing uid/gid 0 is not allowed - call will be ignored!\n", vboxuser.incomingid);
|
||
}
|
||
else log_line(LOG_W, "Number \"%s\" not bound to a local user - call will be ignored!\n", vboxuser.localphone);
|
||
}
|
||
}
|
||
|
||
if (!inputisok)
|
||
{
|
||
log_line(LOG_D, "Got junk line \"");
|
||
log_code(LOG_D, line);
|
||
log_text(LOG_D, "\"...\n");
|
||
|
||
continue;
|
||
}
|
||
}
|
||
|
||
return(-1);
|
||
}
|
||
/*************************************************************************
|
||
** set_process_permissions(): Setzt die effektive uid/gid des Pro- **
|
||
** zesses und die umask. **
|
||
*************************************************************************/
|
||
|
||
int set_process_permissions(uid_t uid, gid_t gid, int mask)
|
||
{
|
||
struct passwd *pwd;
|
||
int groupsset;
|
||
|
||
log_line(LOG_D, "Setting effective permissions to %d.%d [%04o]...\n", uid, gid, mask);
|
||
|
||
errno = 0;
|
||
groupsset = 0;
|
||
|
||
/* Eintrag des zu setzenden Benutzers aus der passwd lesen. Mit */
|
||
/* initgroups() werden dann die realen Gruppen des Benutzers ein- */
|
||
/* gestellt. Ab Kernel 2.1.x scheint das nicht mehr von setgid() */
|
||
/* gemacht zu werden! */
|
||
|
||
if ((pwd = getpwuid(uid)))
|
||
{
|
||
if (uid != 0)
|
||
{
|
||
if (initgroups(pwd->pw_name, gid) == 0) groupsset = 1;
|
||
}
|
||
|
||
if (setegid(gid) == 0)
|
||
{
|
||
if (seteuid(uid) == 0)
|
||
{
|
||
if (mask != 0) umask(mask);
|
||
|
||
if ((uid == 0) || (!groupsset))
|
||
{
|
||
if (initgroups(pwd->pw_name, gid) == 0) groupsset = 1;
|
||
}
|
||
|
||
if (!groupsset)
|
||
{
|
||
log(LOG_E, "Can't run initgroups(\"%s\", %d) (%s).\n", pwd->pw_name, gid, strerror(errno));
|
||
|
||
return(-1);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
else log_line(LOG_E, "Can't set effective uid to %d (%s).\n", uid, strerror(errno));
|
||
}
|
||
else log_line(LOG_E, "Can't set effective gid to %d (%s).\n", gid, strerror(errno));
|
||
}
|
||
else log(LOG_E, "Can't get uid %d passwd entry (%s).", strerror(errno));
|
||
|
||
return(-1);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** pid_create(): Erzeugt die PID Datei f<>r den getty. **
|
||
*************************************************************************
|
||
** => name Name der Datei. **
|
||
*************************************************************************/
|
||
|
||
static void pid_create(unsigned char *name)
|
||
{
|
||
FILE *pptr;
|
||
|
||
log_line(LOG_D, "Creating \"%s\"...\n", name);
|
||
|
||
if ((pptr = fopen(name, "w")))
|
||
{
|
||
fprintf(pptr, "%d\n", getpid());
|
||
fclose(pptr);
|
||
}
|
||
}
|
||
|
||
/*************************************************************************
|
||
** pid_remove(): L<>scht die PID Datei des getty. **
|
||
*************************************************************************
|
||
** => name Name der Datei. **
|
||
*************************************************************************/
|
||
|
||
static void pid_remove(unsigned char *name)
|
||
{
|
||
log_line(LOG_D, "Removing \"%s\"...\n", name);
|
||
|
||
remove(name);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*************************************************************************
|
||
** vboxgettyrc_parse(): Reads the gettys ttyI setup. **
|
||
*************************************************************************
|
||
** => tty Name of the used ttyI. **
|
||
** **
|
||
** On success, 0 is returned. On error, -1 is returned. **
|
||
*************************************************************************/
|
||
|
||
static int vboxgettyrc_parse(unsigned char *tty)
|
||
{
|
||
unsigned char tempsectname[VBOX_MAX_RCLINE_SIZE + 1];
|
||
|
||
xstrncpy(temppathname, SYSCONFDIR , PATH_MAX);
|
||
xstrncat(temppathname, "/vboxgetty.conf", PATH_MAX);
|
||
|
||
/* First time, the global ttyI settings will be */
|
||
/* parsed. */
|
||
|
||
xstrncpy(tempsectname, "vboxgetty-tty", VBOX_MAX_RCLINE_SIZE);
|
||
|
||
if (rc_read(rc_getty_c, temppathname, tempsectname) == -1) return(-1);
|
||
|
||
/* Second, the settings for the used ttyI will be */
|
||
/* parsed. */
|
||
|
||
xstrncpy(tempsectname, "vboxgetty-", VBOX_MAX_RCLINE_SIZE);
|
||
xstrncat(tempsectname, tty , VBOX_MAX_RCLINE_SIZE);
|
||
|
||
if (rc_read(rc_getty_c, temppathname, tempsectname) == -1) return(-1);
|
||
|
||
/* After this, all unset variables will be filled with */
|
||
/* the defaults. */
|
||
|
||
log_line(LOG_D, "Filling unset configuration variables with defaults...\n");
|
||
|
||
if (!rc_set_empty(rc_getty_c, "init" , "ATZ&B512" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "badinitsexit" , "10" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "initpause" , "2500" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "commandtimeout" , "4" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "echotimeout" , "4" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "ringtimeout" , "6" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "alivetimeout" , "1800" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "toggledtrtime" , "400" )) return(-1);
|
||
if (!rc_set_empty(rc_getty_c, "spooldir" , "/var/spool/vbox")) return(-1);
|
||
|
||
modemsetup.echotimeout = xstrtol(rc_get_entry(rc_getty_c, "echotimeout" ), 4 );
|
||
modemsetup.commandtimeout = xstrtol(rc_get_entry(rc_getty_c, "commandtimeout"), 4 );
|
||
modemsetup.ringtimeout = xstrtol(rc_get_entry(rc_getty_c, "ringtimeout" ), 6 );
|
||
modemsetup.alivetimeout = xstrtol(rc_get_entry(rc_getty_c, "alivetimeout" ), 1800 );
|
||
modemsetup.toggle_dtr_time = xstrtol(rc_get_entry(rc_getty_c, "toggledtrtime" ), 400 );
|
||
|
||
if (!rc_get_entry(rc_getty_c, "initnumber"))
|
||
{
|
||
log_line(LOG_E, "Variable \"initnumber\" *must* be set!\n");
|
||
|
||
return(-1);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
/*************************************************************************
|
||
** userrc_parse(): Reads the getty user setup. **
|
||
*************************************************************************
|
||
** => vboxuser
|
||
** => home
|
||
*************************************************************************/
|
||
|
||
static int userrc_parse(struct vboxuser *vboxuser, unsigned char *home)
|
||
{
|
||
unsigned char tempsectname[VBOX_MAX_RCLINE_SIZE + 1];
|
||
struct passwd *pwdent;
|
||
struct group *grpent;
|
||
unsigned char *varusr;
|
||
unsigned char *vargrp;
|
||
unsigned char *varspc;
|
||
unsigned char *varmsk;
|
||
int havegroup;
|
||
|
||
static struct vboxrc rc_user_c[] =
|
||
{
|
||
{ "user" , NULL },
|
||
{ "group" , NULL },
|
||
{ "umask" , NULL },
|
||
{ "hdspace" , NULL },
|
||
{ NULL , NULL }
|
||
};
|
||
|
||
xstrncpy(temppathname, SYSCONFDIR , PATH_MAX);
|
||
xstrncat(temppathname, "/vboxgetty.conf", PATH_MAX);
|
||
|
||
xstrncpy(tempsectname, "vboxgetty-phone-" , VBOX_MAX_RCLINE_SIZE);
|
||
xstrncat(tempsectname, vboxuser->localphone, VBOX_MAX_RCLINE_SIZE);
|
||
|
||
if (rc_read(rc_user_c, temppathname, tempsectname) < 0) return(-1);
|
||
|
||
varusr = rc_get_entry(rc_user_c, "user" );
|
||
vargrp = rc_get_entry(rc_user_c, "group" );
|
||
varspc = rc_get_entry(rc_user_c, "hdspace");
|
||
varmsk = rc_get_entry(rc_user_c, "umask" );
|
||
|
||
vboxuser->uid = 0;
|
||
vboxuser->gid = 0;
|
||
vboxuser->space = 0;
|
||
vboxuser->umask = 0;
|
||
|
||
strcpy(vboxuser->home, "");
|
||
strcpy(vboxuser->name, "");
|
||
|
||
if ((!varusr) || (!*varusr))
|
||
{
|
||
log_line(LOG_E, "You *must* specify a user name or a user id!\n");
|
||
|
||
rc_free(rc_user_c);
|
||
|
||
return(-1);
|
||
}
|
||
|
||
if (*varusr == '#')
|
||
pwdent = getpwuid((uid_t)xstrtol(&varusr[1], 0));
|
||
else
|
||
pwdent = getpwnam(varusr);
|
||
|
||
if (!pwdent)
|
||
{
|
||
log_line(LOG_E, "Unable to locate \"%s\" in systems passwd list.\n", varusr);
|
||
|
||
rc_free(rc_user_c);
|
||
|
||
return(-1);
|
||
}
|
||
|
||
vboxuser->uid = pwdent->pw_uid;
|
||
vboxuser->gid = pwdent->pw_gid;
|
||
|
||
if ((strlen(home) + strlen(pwdent->pw_name) + 2) < (PATH_MAX - 100))
|
||
{
|
||
xstrncpy(vboxuser->name, pwdent->pw_name, VBOXUSER_USERNAME);
|
||
|
||
printstring(vboxuser->home, "%s/%s", home, pwdent->pw_name);
|
||
}
|
||
else
|
||
{
|
||
log_line(LOG_E, "Oops! Spool directory name and user name too long!\n");
|
||
|
||
rc_free(rc_user_c);
|
||
|
||
return(-1);
|
||
}
|
||
|
||
if ((vargrp) && (*vargrp))
|
||
{
|
||
havegroup = 0;
|
||
|
||
setgrent();
|
||
|
||
while ((grpent = getgrent()))
|
||
{
|
||
if (*vargrp == '#')
|
||
{
|
||
if (grpent->gr_gid == (gid_t)xstrtol(&vargrp[1], 0))
|
||
{
|
||
vboxuser->gid = grpent->gr_gid;
|
||
havegroup = 1;
|
||
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (strcmp(grpent->gr_name, vargrp) == 0)
|
||
{
|
||
vboxuser->gid = grpent->gr_gid;
|
||
havegroup = 1;
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
endgrent();
|
||
|
||
if (!havegroup)
|
||
{
|
||
log_line(LOG_E, "Unable to locate \"%s\" in systems group list.\n", vargrp);
|
||
|
||
rc_free(rc_user_c);
|
||
|
||
return(-1);
|
||
}
|
||
}
|
||
|
||
if (varspc) vboxuser->space = xstrtol(varspc, 0);
|
||
if (varmsk) vboxuser->umask = xstrtoo(varmsk, 0);
|
||
|
||
log_line(LOG_D, "User \"%s\" (%d.%d) [%04o] will be used...\n", vboxuser->name, vboxuser->uid, vboxuser->gid, vboxuser->umask);
|
||
|
||
rc_free(rc_user_c);
|
||
|
||
return(0);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|