Nutzungszeitbeschränkung unter Linux?

jsowieso

Lt. Junior Grade
Registriert
Okt. 2004
Beiträge
272
Hallo,
Gibt es unter Linux irgendwie die Möglichkeit Nutzern nur x Stunden am Tag ihre Konten nutzen zu lassen? So dass man nach der abgelaufenen Zeit automatisch abgemeldet wird und sich erst am nächsten Tag wieder anmelden kann?
Und gibt es die Möglichkeit lokalen Nutzern das Anmelden nur an bestimmten Tageszeiten zu gestatten, bspw von 8:00 bis 20:00Uhr? (Die Funktion gibt es doch jetzt in Vista, oder?)

Wenn es irgendwelche Anwendungen oder Skripte dazu gibt, lasst es mich bitte wissen. Auch wenn gerade ein Projekt dazu am starten ist.
 
Die Beschänkung auf bestimmte (Wochen)Tage oder Zeiten läßt sich über die Datei /etc/usertty steuern, eine Übersicht findest du bspw. hier. Diese Funktion gibt übrigens seit Uhrzeit in NT-basierten Systemen ;)

greetings, Keita
 
Vielen Dank, ich werde mir das mal durchlesen und ausprobieren. Das es sowas schon seit Ewigkeiten gibt hätte ich mir ja denken können, es ist nur auf den ersten Blick gut versteckt. ;-)
 
So, habe mir das mal durchgelesen, vermute auch das sowas funktioniert, habs aber noch nicht ausprobiert, da es mich nicht wirklich weiterbringt. Kann man denn diese Beschränkungen in KDE vornehmen, also das KDM einfach zu bestimmten Zeiten Nutzer sperrt. Wenn das ginge wäre mein Problem gelöst, denn an meinem Rechner meldet sich niemand über die Konsole an. Oder ist sowas erst in KDE4 geplant?
Ich bin gespannt auf eure Antworten.
 
mir ist weder bekannt, dass es mit kdm möglich ist, noch dass es für kde4 geplant ist.
wenn du das starten einer kde-session verhindern willst, ist es wohl am einfachsten in dem kde-startskript eine abfrage einzubaun. (das skript heißt startkde und befindet sich entweder in /usr/bin/startkde oder /opt/kde3/bin/startkde. wenn du es da nicht finden kannst, mittels "whereis startkde" nachschauen, wo es sich versteckt.)

wenn du jemanden aktiv auslogen willst, geht das so:
du schaust nach, ob folgende datei exisitert:
/tmp/ksocket-username/KSMserver__0 (das ist die datei für den ersten bildschirm, wenn du auch die anderen beachten willst: /tmp/ksocket-username/KSMserver__*)
wenn die datei existiert, läuft eine kde-session. auslogen geht dann so:
dcop --user username --all-sessions ksmserver ksmserver logout 0 0 0
(das doppelte auftreten von ksmserver ist beabsichtigt.)
sieht dann in einem skript so aus:
Code:
#!/bin/sh
if [ -f /tmp/ksocket-username/KSMserver__? ]; then
     dcop --user username --all-sessions ksmserver ksmserver logout 0 0 0
fi

das skript rufst du dann irgendwas im minutentakt auf. das sollte deine probleme lösen.

du könntest auch auf änderungen in dem passenden ksocket verzeichnis achten, aber dafür müsste man ein bisschen mehr code schreiben.

achja: das auslogen geht natürlich nur bei personen, bei denen du schreibrecht im ice des x-server hast. also als root bei allen, sonst nur wenn du passende rechte hast, also eigentlich nie.

nachtrag: das geht natürlich nur, wenn eine kde-session läuft. wenn also jemand auf den trichter kommt, dass er nur einen anderen wm nutzen muss, bringt das nichts mehr. das kannst du aber dadurch verhindern, dass du nur eine .desktop-datei für kde in dem xsessions verzeichnis (üblicherweise: /usr/share/xsessions) ablegst.

nachtrag2: ich hatte das "--all-sessions" vergessen. sonst könnte man das skript unterlaufen, in dem man mehr als eine session benutzt.
 
Zuletzt bearbeitet:
Also ich wiederhole erst mal was ich verstanden habe:
Das Script sieht also in etwas so aus:
wenn [ es läuft eine Sitzung eines bestimmten Nutzers] {
dann, logge ihn aus }
Wie bekomme ich das nun aber hin, dass der Nutzer erst nach 1 Stunde (bspw) ausgeloggt wird? Es müsste doch noch ein Timer mitlaufen, oder gibt es da eine Variable, die anzeigt wie lange die K-Sitzung schon läuft? Müsste es doch eigentlich. Sprich ich müsste diese noch in die Bedingung reinschieben [ ... && $ktime <= 60 ]. Gibt es denn soetwas?

Und noch eine Frage zu deinem Vorschlag? Kostet das nicht noch irgendwie Leistung des Systems wenn er dieses Script ständig aufruft? Wäre es nicht besser 2 Scripte zu haben, eines das exakt nach der eingestellten Zeit, 60min, aufgerufen wird, eine Variable speichert, die für einen Tag gilt und dann die K-Sitzung runterfährt. Das 2te Script ist dann das startkde-Script welches überprüft ob die eben genannte Variable existiert und demnach die Sitzung runterfährt?

Und noch eine Frage: Für was steht das 0 0 0 hinter ... logout?
 
zuerst mein fehler: das skript gerade war natürlich nur geeignet um user daran zu hindern, zu einer bestimmten uhrzeit angemeldet zu sein. dazu hätte es dann einfach passend in die crontab eingetragen werden müssen.
Wie bekomme ich das nun aber hin, dass der Nutzer erst nach 1 Stunde (bspw) ausgeloggt wird? Es müsste doch noch ein Timer mitlaufen, oder gibt es da eine Variable, die anzeigt wie lange die K-Sitzung schon läuft? Müsste es doch eigentlich. Sprich ich müsste diese noch in die Bedingung reinschieben [ ... && $ktime <= 60 ]. Gibt es denn soetwas?
wie lange die kde-session schon läuft, kannst du über den erstellzeitpunkt von KSMsession_* rausbekommen. also bspw so:
Code:
#wenn eine session länger als 60min läuft, dann tu was
if ! [ -z `find /tmp/ksocket-username/KSMserver__? -cmin +60` ]; then
tu irgendwas
fi
das nützt aber nicht viel, da man das umgehen kann, daher würde ich dir empfehlen, dass ganze mittels eine lock-datei zu machen:
also:
Code:
if [ -f /tmp/ksocket-username/KSMserver__? ]; then
   if [ -f /tmp/kdelockdatei-username ]; then
      if ! [ -z `find /tmp/kdelockdatei-username -cmin +60` ]; then
        ausloggen
      fi
   else
     touch /tmp/kdelockdatei-username
   fi
fi

das ist natürlich nicht geeignet, wenn du ein zeitkonto hast. dann sieht es ein anders aus:
dazu ist es am einfachsten, du legst dir eine datei an, in der das restguthaben eingetragen ist.
bspw: /tmp/username.time
die füllst du jeden tag mittels bspw: echo 60 > /tmp/usename.time
auf.
das skript zur verarbeitung sieht dann so aus:
Code:
#nur wenn der nutzer überhaupt ein zeitkonto hat
if [ -f /tmp/username.time ] then
#nur wenn die person gerade kde nutzt, die zeit überprüfen
if [ -f /tmp/ksocket-username/KSMserver__? ]; then
 #zeit abgelaufen?
  if [ `cat /tmp/username.time` -eq 0 ]; then
    dcop --user username --all-sessions ksmserver ksmserver logout 0 0 0
  else
#wenn nicht. eine minute abziehen
    echo $((`cat /tmp/username.time`-1)) > /tmp/username.time
  fi
fi
fi
das skript rufst du jede minute auf. dann sollte das system, wenn die zeit abgelaufen ist, die person automatisch ausloggen.

zur performance: den einfluss kannst du vernachlässigen. die überprüfung, ob eine datei existiert kostet quasi keine leistung.

zu 0 0 0 hinter logout:
das legt ein paar parameter fest. also das sofort ausgelogt werden soll. das programme, die über sessionsverfügen, diese speichern soll. bei letzten bin ich mir gerade nicht sicher, was er macht...
 
Das sieht ja schon mal spitze aus. Wie bekomme ich das denn hin, dass sich das Script jede Minute aufruft? Dann kann ich gleich mal testen ob es funktioniert.
 
am einfachsten ist, dass du es beim hochfahren von "init" im hintergrund starten lässt und es dann immer 60s schlafen lässte.
sieht dann so aus:
Code:
until ! [ -z "" ]; do
#schlaf eine minute
sleep 60s

#nur wenn der nutzer überhaupt ein zeitkonto hat
if [ -f /tmp/username.time ] then
#nur wenn die person gerade kde nutzt, die zeit überprüfen
if [ -f /tmp/ksocket-username/KSMserver__? ]; then
 #zeit abgelaufen?
  if [ `cat /tmp/username.time` -eq 0 ]; then
    dcop --user username --all-sessions ksmserver ksmserver logout 0 0 0
  else
#wenn nicht. eine minute abziehen
    echo $((`cat /tmp/username.time`-1)) > /tmp/username.time
  fi
fi
fi
done
in dem init-skript musst du dann noch einbauen, dass die zeit jeden tag zurück gesetzt wird.
ich weiß gerade nicht, ob ich mich verständlich ausdrücke. wenn nicht melde dich nochmal, insbesondere für das init-script.
 
Also, das habe ich soweit verstanden. Wenn Init das Aufrufen soll muss ich es demnach in das entsprechende Runlevel kopieren, sprich 5, vorher startet KDE ja nicht. Sollte das denn wirklich Init selbst machen oder, ich glaube mich zu erinnern, nicht lieber KInit (o.ä.)?

Zum Reseten der Datei nutze ich dann cron.daily.
Code:
#!/bin/bash
#/etc/cron.daily/timeset
cat 60 > /temp/username.time

Soweit so richtig?

und noch eine Frage zum Script: für was steht die erste Zeile? Also es ist eine Schleife, dass das Script alle 60sek neugestartet wird, aber was heißt ! [ -z "" ] ?
 
ich würde es in init aufrufen. aber bitte erst nach cron. du musst da aber noch einen skript drumherum schreiben, daher fragte ich nach. ich hab den skript hier fertig vorliegen, der ist aber was länger, daher habe ich bisher verzichtet ihn zu posten.
und noch eine Frage zum Script: für was steht die erste Zeile? Also es ist eine Schleife, dass das Script alle 60sek neugestartet wird, aber was heißt ! [ -z "" ] ?
das ist eine endlos schleife, daher musst du es im hintergrund starten.
zur genauen erklärung: [ -z "" ] testet, ob der string "" leer ist. das "!" invertiert die ausgabe.
 
Zuletzt bearbeitet: (true != false)
Ich verstehe deinen Satz, du musst aber noch ein Skript drumherum schreiben, nicht. Ich habe den Code aus Beitrag #9 nach /etc/init.d/rc5.d in eine Datei namens S14timerestrict kopiert. Dann habe ich alle usernames ersetzt und #!/bin/bash an den Anfang der Datei geschrieben. Ich habe erst einmal manuell eine Datei /tmp/usrname.time erstellt, mit dem probewert 2. Leider tut sich gar nichts. Wie kann ich feststellen, dass init das Skript (wenn es denn eins ist) überhaupt gestartet hat? ps -ax liefert es nicht.
 
du hast das skript so in dein init getan? nicht dein ernst, oder? da kann ich eigentlich nur froh sein, dass ich bei dbus den pfad nicht angeben hatte...
das skript geht in eine endlos schleife. das würde deinen rechner blockieren, wenn es tatsächlich gestartet worden wäre...

du musst da ein bisschen mehr skript drumherum schreiben. du musst nämlich auch noch verhindern, dass dein programm mehrfach gestartet wird. dafür legst du am einfachsten eine pid datei an und überprüfst, ob dein prozess noch an dieser pid ist.
das ganze startskript ist eigentlich nur eine "ausgeliehene" variante des dbus startskriptes aus debian.
Code:
! /bin/sh
### BEGIN INIT INFO
# Provides:          userzeit
# Required-Start:    $dbus
# Required-Stop:     $dbus
# Default-Start:     2 3 4 5
# Default-Stop:      S 0 1 6
### END INIT INFO
# -*- coding: utf-8 -*-
# Debian init.d script for D-BUS
# Copyright © 2003 Colin Walters <walters@debian.org>
# Copyright © 2005 Sjoerd Simons <sjoerd@debian.org>
set -e

DAEMON=/usr/bin/userzeit.bash
PIDDIR=/var/run
PIDFILE=$PIDDIR/pid
DESC="userzeit"


test -x $DAEMON || exit 0


. /lib/lsb/init-functions

start_it_up()
{
  if [ ! -d $PIDDIR ]; then
    mkdir -p $PIDDIR
  fi
  if [ -e $PIDFILE ]; then
    PIDDIR=/proc/$(cat $PIDFILE)
    if [ -d ${PIDDIR} -a  "$(readlink -f ${PIDDIR}/exe)" = "${DAEMON}" ]; then
      log_success_msg "$DESC already started; not starting."
    else
      log_success_msg "Removing stale PID file $PIDFILE."
      rm -f $PIDFILE
    fi
  fi
  log_daemon_msg "Starting $DESC" "$NAME"
  start-stop-daemon --start --quiet --pidfile $PIDFILE \
    --exec $DAEMON -- --system $PARAMS
  log_end_msg $?
}

shut_it_down()
{   
  log_daemon_msg "Stopping $DESC" "$NAME"
  start-stop-daemon --stop --retry 60 --quiet --oknodo --pidfile $PIDFILE
  # We no longer include these arguments so that start-stop-daemon
  # can do its job even given that we may have been upgraded.
  # We rely on the pidfile being sanely managed
  # --exec $DAEMON -- --system $PARAMS
  log_end_msg $?
}

case "$1" in
  start)
    start_it_up
  ;;
  stop)
    shut_it_down
  ;;
  reload|force-reload)
    shut_it_down
    start_it_up
  ;;
  restart)
    shut_it_down
    start_it_up
  ;;
  *)
    echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart|force-reload}" >&2
    exit 1
  ;;
esac

exit 0
für die pid-datei ist es ein bisschen hässlich, dass die bash ohne weiteres ihre eigene pid liefern kann. sie kann aber die ihrer eltern zurückliefern. das skritp, das die eigene pid liefert sieht dann so aus (ich nehme das in zukunft getpid):
Code:
#!/bin/bash
echo $PPID
in skriptdatei schreibst du dann vor der eigentlichen schleife:
Code:
PIDDIR=/var/run
PIDFILE=$PIDDIR/pid
echo `getpid` > $PIDFILE

das sollte dann eigentlich alles sein. wenn du kein debian hast, kann es sein, dass du kein start-stop-daemon hast.

das ist alles ohne gewähr und nur ein bisschen getestet. ;-)
 
Zuletzt bearbeitet:
Also deine erste Datei kommt in /etc/init.d/? In alle Runlevel, und wie und wo muss ich es hinkopieren, damit init es bei init 0/1/6 beendet?
Den Inhalt von code2 kopiere ich nach /var/run/pid. Wo kommt die eigentliche Skriptdatei denn hin, oder ist das egal?
Ich nutzte OpenSuSE 10.2, da gibt es soweit ich weiß einen start-stop-daemon. Mein Problem ist nur dass ich nicht richtig weiß wie er funktioniert.
 
also die datei getpid und das eigentlich skript würde ich in /usr/local/bin ablegen.

die startup-datei kommt in /etc/init.d sieht aber bei suse ein bisschen anders aus. wieder kopiert von cups ;-)
Code:
#! /bin/sh
#
# Copyright (c) 1995-2001 SuSE GmbH Nuernberg, Germany.
# Copyright (c) 2002 SuSE Linux AG, Nuernberg, Germany.
#
# Author: Kurt Garloff <feedback@suse.de>, 2000
#	  Klaus Singvogel <feedback@suse.de>, 2002
##
#   and symbolic its link
#
#
# System startup script for the CUPS printer daemon
#
### BEGIN INIT INFO
# Provides:            userzeit
# Required-Start:      $cron
# Required-Stop:       
# Should-Start:       
# Should-Stop:        
# Default-Start:       2 3 5
# Default-Stop:        0 1 6
# Description:         start userzeit
### END INIT INFO

# Source SuSE config, only if exists with size greater zero

# Shell functions sourced from /etc/rc.status:
#      rc_check         check and set local and overall rc status
#      rc_status        check and set local and overall rc status
#      rc_status -v     ditto but be verbose in local rc status
#      rc_status -v -r  ditto and clear the local rc status
#      rc_failed        set local and overall rc status to failed
#      rc_failed <num>  set local and overall rc status to <num><num>
#      rc_reset         clear local rc status (overall remains)
#      rc_exit          exit appropriate to overall rc status

USERZEIT_BIN=/usr/local/bin/userzeit

test -s /etc/rc.status && \
     . /etc/rc.status

test -x $USERZEIT_BIN || exit 5

# First reset status of this service
rc_reset

# Return values acc. to LSB for all commands but status:
# 0 - success
# 1 - generic or unspecified error
# 2 - invalid or excess argument(s)
# 3 - unimplemented feature (e.g. "reload")
# 4 - insufficient privilege
# 5 - program is not installed
# 6 - program is not configured
# 7 - program is not running
# 
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signalling is not supported) are
# considered a success.

# change umask to avoid problems in wrong file permission of /etc/printcap
# (SuSE buzilla #16567)

case "$1" in
    start)
	echo -n "Starting userzeit"
	## Start daemon with startproc(8). If this fails
	## the echo return value is set appropriate.

	# NOTE: startproc return 0, even if service is 
	# already running to match LSB spec.
	if [ "$PREVLEVEL" = "N" -a "$RUNLEVEL" = "5" ]; then
		/usr/bin/ionice -c 3 startproc -pid=/var/run/userzeit.pid $USERZEIT_BIN
	else
		startproc -pid=/var/run/userzeit.pid $USERZEIT_BIN
	fi

	# Remember status and be verbose
	rc_status -v
	;;
    stop)
	echo -n "Shutting down cupsd"
	## Stop daemon with killproc(8) and if this fails
	## set echo the echo return value.

	killproc -TERM -pid=/var/run/userzeit.pid  $USERZEIT_BIN

	# Remember status and be verbose
	rc_status -v
	;;
    try-restart)
	## Stop the service and if this succeeds (i.e. the 
	## service was running before), start it again.
	## Note: try-restart is not (yet) part of LSB (as of 0.7.5)
	$0 status >/dev/null &&  $0 restart

	# Remember status and be quiet
	rc_status
	;;
    restart)
	## Stop the service and regardless of whether it was
	## running or not, start it again.
	$0 stop
	$0 start

	# Remember status and be quiet
	rc_status
	;;
    force-reload)
    $0 restart

	;;
    reload)
    $0 restart
	;;
    status)
	echo -n "Checking for cupsd: "
	## Check status with checkproc(8), if process is running
	## checkproc will return with exit status 0.

	# Status has a slightly different for the status command:
	# 0 - service running
	# 1 - service dead, but /var/run/  pid  file exists
	# 2 - service dead, but /var/lock/ lock file exists
	# 3 - service not running

	# NOTE: checkproc returns LSB compliant status values.
	checkproc   -pid=/var/run/userzeit.pid  $USERZEIT_BIN
	rc_status -v
	;;
    probe)
	## Optional: Probe for the necessity of a reload,
	## give out the argument which is required for a reload.

	rc_failed 3
	;;
    *)
	echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
	exit 1
	;;
esac
rc_exit
installieren geht dann mittels :
$> insserv userzeit
das sollte dann auch automatisch den richtigen platz finden.
 
Erst mal Vielen Dank. Das Skript funktioniert jetzt.
Ich habe allerdings noch eine Frage: Kann ich den Nutzer irgendwie warnen, dass er gleich ausgeloggt wird. Wenn ich mit kdialog noch entsprechende Zeilen ergänze, bekommt der Nutzer keine Warnung, ich denke mal die wird an root gesendet, da Init ja mit Root-Rechten läuft. Wie bekomme ich es hin, dass dieser kdialog-Befehl an den entsprechenden Nutzer gesendet wird?

Edit
Also das Problem liegt darin, dass kdialog meldet: cannot connect to xserver? wieso kann es das denn nicht? Habe es auch schon mal mit sudo -u user und DISPLAY0=: probiert. Weder das eine, noch das andere lieferte Erfolg. Hat jemand eine Idee, was ich da machen kann?

Wer die vorgegangen Beiträge oben das nicht lesen will: Wie bekomme ich es hin das kdialog in einem init-Skript aufgerufen funktioniert (Fehlermeldung cannot connect to xserver)?
 
Zuletzt bearbeitet:
Zurück
Oben