![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Hallo Liste Kann mir mal bitte jemand die Blindenbinde entfernen und mich in die richtige Richtung schubsen (man cron, man crontab und google cron.daily haben mich nicht wirklich weitergebracht) Da mein Rechner nicht dauernd läuft, möchte ich dennoch regelmäßige Backups fahren. Bisher habe ich diese per crontab -e eingetragen. Funzt auch (siehe Logfile) - sind aber zuviele. 5 3,9,15,21 * * * /home/andreas/Daten/Script/Backup Es gibt aber doch auch die Möglichkeit Skripte einmal täglich auszuführen, egal wann der Rechner eingeschaltet wird. Ich möchte eigentlich nur ein Backup täglich haben. Hierzu habe ich mein Backupscript (welches in der crontab eingetragen perfekt funktioniert) nach /etc/cron.daily kopiert. andreas:/etc/cron.daily # ls -l -rwxr-xr-x 1 root root 990 2005-01-08 10:38 Backup Hier wird es aber definitiv nicht ausgeführt (siehe Logfile). Und cron.daily wird doch auch viertelstündlich geprüft, oder? andreas:/home/andreas # less /etc/crontab -*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1 Warum wird mein Script denn nicht ausgeführt? Danke für die Hilfe Andy grep Backup /var/log/messages Jun 3 03:05:00 andreas /USR/SBIN/CRON[2434]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 3 09:05:00 andreas /USR/SBIN/CRON[3141]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 3 15:05:00 andreas /USR/SBIN/CRON[2599]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 3 21:05:00 andreas /USR/SBIN/CRON[3661]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 4 03:05:00 andreas /USR/SBIN/CRON[4623]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 4 09:05:00 andreas /USR/SBIN/CRON[5606]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 4 15:05:00 andreas /USR/SBIN/CRON[6654]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 4 21:05:00 andreas /USR/SBIN/CRON[7543]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 5 03:05:00 andreas /USR/SBIN/CRON[8304]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 5 09:05:00 andreas /USR/SBIN/CRON[10332]: (andreas) CMD (/home/andreas/Daten/Script/Backup) Jun 5 15:05:00 andreas /USR/SBIN/CRON[11105]: (andreas) CMD (/home/andreas/Daten/Script/Backup)
![](https://seccdn.libravatar.org/avatar/318fce3ea1d3dd3d68d9f415a2612300.jpg?s=120&d=mm&r=g)
Am Sonntag, 5. Juni 2005 18:50 schrieb Andreas Schott:
Und cron.daily wird doch auch viertelstündlich geprüft, oder?
andreas:/home/andreas # less /etc/crontab
-*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
Füg da mal folgendes hinzu (meine Einstellung, kannst natürlich andere Zeiten verwenden): 59 * * * * root rm -f /var/spool/cron/lastrun/cron.hourly 14 0 * * * root rm -f /var/spool/cron/lastrun/cron.daily 29 1 * * 6 root rm -f /var/spool/cron/lastrun/cron.weekly 44 1 1 * * root rm -f /var/spool/cron/lastrun/cron.monthly Die waren bei mir auf dem Notebook nach der 9.3er Installation auch nicht drin, nach dem Einfügen lief wieder alles wie gewohnt (also es cron.daily läuft um 0:14 los wenn der Rechner läuft ansonsten wird periodisch geprüft, ob es länger als 24 Stunden her ist und dann starten die scripts). -- Machs gut | http://www.iivs.de/schwinde/buerger/tremmel/ | http://packman.links2linux.de/ Manfred | http://www.knightsoft-net.de
![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Hallo Manfred, hallo Liste Am Sonntag, 5. Juni 2005 19:34 schrieb Manfred Tremmel:
Am Sonntag, 5. Juni 2005 18:50 schrieb Andreas Schott:
Und cron.daily wird doch auch viertelstündlich geprüft, oder?
andreas:/home/andreas # less /etc/crontab
-*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
Füg da mal folgendes hinzu (meine Einstellung, kannst natürlich andere Zeiten verwenden):
59 * * * * root rm -f /var/spool/cron/lastrun/cron.hourly 14 0 * * * root rm -f /var/spool/cron/lastrun/cron.daily 29 1 * * 6 root rm -f /var/spool/cron/lastrun/cron.weekly 44 1 1 * * root rm -f /var/spool/cron/lastrun/cron.monthly
Die sind auch mit eingetragen. Sorry hatte nicht erwähnt, dass ich sie weggelassen hatte, da ich dachte, die sind für die Funktion nicht relevant. Hier wird doch nur die jeweilige Datei entfernt, oder?
Die waren bei mir auf dem Notebook nach der 9.3er Installation auch nicht drin,
Ich hab hier noch ne 9.0. Andy
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo Andy, hallo Leute, Am Sonntag, 5. Juni 2005 18:50 schrieb Andreas Schott:
Es gibt aber doch auch die Möglichkeit Skripte einmal täglich auszuführen, egal wann der Rechner eingeschaltet wird. Ich möchte eigentlich nur ein Backup täglich haben.
Hierzu habe ich mein Backupscript (welches in der crontab eingetragen perfekt funktioniert) nach /etc/cron.daily kopiert.
andreas:/etc/cron.daily # ls -l
-rwxr-xr-x 1 root root 990 2005-01-08 10:38 Backup
Passt.
Hier wird es aber definitiv nicht ausgeführt (siehe Logfile).
Bei cron.daily werden nicht die einzelnen Scripte geloggt, sondern nur den Aufruf von run-crons. Das greppen nach "Backup" kann also nicht funktionieren.
Und cron.daily wird doch auch viertelstündlich geprüft, oder?
andreas:/home/andreas # less /etc/crontab
-*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
Jepp.
Warum wird mein Script denn nicht ausgeführt?
Vielleicht wird es das ja schon - guck doch einfach mal nach, ob ein aktuelles Backup existiert ;-) Gruß Christian Boltz -- LINUX wird nie zum meistinstallierten System - so oft wie man Win98 neu installieren darf!
![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Hallo Christian, hallo Liste Am Sonntag, 5. Juni 2005 22:03 schrieb Christian Boltz:
Hallo Andy, hallo Leute,
Am Sonntag, 5. Juni 2005 18:50 schrieb Andreas Schott:
Es gibt aber doch auch die Möglichkeit Skripte einmal täglich auszuführen, egal wann der Rechner eingeschaltet wird. Ich möchte eigentlich nur ein Backup täglich haben.
Hierzu habe ich mein Backupscript (welches in der crontab eingetragen perfekt funktioniert) nach /etc/cron.daily kopiert.
andreas:/etc/cron.daily # ls -l
-rwxr-xr-x 1 root root 990 2005-01-08 10:38 Backup
Passt.
Prima. Ich hab das Backupscript jetzt nach cron.hourly gepackt um leichter kontrollieren zu können.
Hier wird es aber definitiv nicht ausgeführt (siehe Logfile).
Bei cron.daily werden nicht die einzelnen Scripte geloggt, sondern nur den Aufruf von run-crons. Das greppen nach "Backup" kann also nicht funktionieren.
Wusste ich nicht. Wird das nirgendwo geloggt?
Und cron.daily wird doch auch viertelstündlich geprüft, oder?
andreas:/home/andreas # less /etc/crontab
-*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
Jepp.
Prima
Warum wird mein Script denn nicht ausgeführt?
Vielleicht wird es das ja schon - guck doch einfach mal nach, ob ein aktuelles Backup existiert ;-)
Nein es existiert definitv kein Backup. Das sollte doch in dem Fall maximal 15 Minuten nach dem Booten des Rechners laufen, oder? Das booten ist nun schon fast zwei Stunden her grep cron /var/log/messages ergibt u.a. Jun 6 08:59:00 andreas /USR/SBIN/CRON[6409]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly) Jun 6 09:59:00 andreas /USR/SBIN/CRON[6951]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly) Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers. (Ich sichere mittels rsync) Den Key für den user andreas habe ich auf den Server geladen, damit das Teil ohne Passwortabfrage durchläuft. Aber den Key für root würde ich ungern dort ablegen. Ändere ich die Zugehörigkeit nach -rwxr-xr-x 1 andreas users 990 2005-01-08 10:38 Backup und starte es manuell, läuft es durch. Any hints? Andy
![](https://seccdn.libravatar.org/avatar/39f13fac7399d4bb3744a1a0390c8d94.jpg?s=120&d=mm&r=g)
Andreas Schott wrote: ...
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers.
Wo fragt es danach, wenn/falls es von cron gestartet wird? -- Viele Grüße ------------------------------------------------------------------------ Michael
![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Am Montag, 6. Juni 2005 11:48 schrieb Michael Behrens:
Andreas Schott wrote: ...
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers.
Wo fragt es danach, wenn/falls es von cron gestartet wird?
Ich starte es auf der Konsole und da kommt die Passwortabfrage. Ob es von cron gestartet wird, kann ich ja nicht sagen, weil ich nicht weiß, wo - wenn überhaupt - cron.hourly geloggt wird. Andy
![](https://seccdn.libravatar.org/avatar/318fce3ea1d3dd3d68d9f415a2612300.jpg?s=120&d=mm&r=g)
Am Montag, 6. Juni 2005 12:50 schrieb Andreas Schott:
Ich starte es auf der Konsole und da kommt die Passwortabfrage. Ob es von cron gestartet wird, kann ich ja nicht sagen, weil ich nicht weiß, wo - wenn überhaupt - cron.hourly geloggt wird.
Ich schreib in solchen fällen immer ein echo rein, das nen einfachen Text in eine Datei sowas wie 'echo "irgendwas > /tmp/irgendwas', schon hab ich die Kontrolle ob da was gestartet wird. Du hast schon berücksichtigt das ein per cron gestartetes Script keine bzw. eine sehr limitierte Environment hat, sprich alle Befehle mit Pfad anzugeben sind usw. -- Machs gut | http://www.iivs.de/schwinde/buerger/tremmel/ | http://packman.links2linux.de/ Manfred | http://www.knightsoft-net.de
![](https://seccdn.libravatar.org/avatar/551697df83d38ee75e41406e0b27735a.jpg?s=120&d=mm&r=g)
Andreas Schott, Montag, 6. Juni 2005 11:44:
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers.
Das wird wohl das Problem sein. Wie soll denn Dein Skript das Paßwort abfragen, wenn es keine Konsole hat? -- Antworten an lists@feile.net werden in /dev/null archiviert! Bitte ggf. lists... durch mail... ersetzen. Andreas Feile www.feile.net
![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Am Montag, 6. Juni 2005 18:40 schrieb Andreas Feile:
Andreas Schott, Montag, 6. Juni 2005 11:44:
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers.
Das wird wohl das Problem sein. Wie soll denn Dein Skript das Paßwort abfragen, wenn es keine Konsole hat?
Ja das ist schon klar. Werden in cron.hourly nur Scripte ausgeführt, die root gehören, oder kann cron.hourly auch Scripte ausführen, die einem User gehören? Andy
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo Andy, hallo Leute, Am Montag, 6. Juni 2005 19:54 schrieb Andreas Schott: [...]
Werden in cron.hourly nur Scripte ausgeführt, die root gehören, oder kann cron.hourly auch Scripte ausführen, die einem User gehören?
Ist die Frage (trotz meiner Verspätung - sorry!) noch offen? ;-) Wem die Dateien in /etc/cron.* gehören, ist eigentlich egal. Ausgeführt werden sie allerdings grundsätzlich mit root-Rechten. (Deshalb sollten sie sinnvollerweise auch root gehören ;-) Für normale User gibt es zwar die Möglichkeit, mit crontab -e eigene Cronjobs festzulegen, aber nur zu festen Zeiten - nichts im Stil von cron.daily usw. Da ich usercron.daily sowieso schon längst programmieren wollte - hier ist es: ----------------------------------------------------------------------- #!/bin/bash # usercron.daily # # Copyright (C)2005 by Christian Boltz - www.cboltz.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. me="${0//.*\/}" case "$me" in usercron.monthly) dirname=.cron.monthly ;; usercron.weekly) dirname=.cron.weekly ;; usercron.daily) dirname=.cron.daily ;; usercron.hourly) dirname=.cron.hourly ;; *) echo "unknown basename. Please name this script (or its symlink)" echo "usercron.monthly, usercron.weekly, usercron.daily or" echo "usercron.hourly." exit 1 esac # get list of users userlist="`cut -d: -f1 /etc/passwd`" # if /etc/cron.allow exists, allow only users in this file test -f /etc/cron.allow && userlist="`cat /etc/cron.allow`" for user in $userlist ; do # deny cronjobs for users in /etc/cron.deny grep "^[ ]*$user[ ]*$" /etc/cron.deny &>/dev/null && continue # ^^^ und ^^^ = Space Tab # get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`"; # test for .cron.* in homedir test -d "$homedir/$dirname" || continue # search and execute scripts in ~/cron.* ls -1 "$homedir/$dirname/" | while read file ; do test -x "$homedir/$dirname/$file" && { # log and execute logger -t "$me" "($user) CMD ($homedir/$dirname/$file)" su "$user" -c "$homedir/$dirname/$file" } done done ----------------------------------------------------------------------- Das Ganze speicherst Du als /etc/cron.daily/usercron.daily ab. Außerdem kannst Du in cron.hourly usw. Symlinks setzen. Wichtig: Da das Verhalten des Scripts auf seinem Namen basiert, muss es (bzw. der Symlink) wirklich usercron.daily, usercron.hourly usw. heißen. Die Benutzer können in ~/.cron.daily usw. Scripte anlegen, die dann mit entsprechenden User-Rechten ausgeführt werden. Achtung: Obiges Script habe ich eben in Rekordzeit getippt - es ist also nur minimal getestet. Die Behandlung von cron.deny und cron.allow [1] habe ich eingebaut, aber nicht getestet. Falls jemand Bugs oder mögliche Sicherheitslücken auffallen - bitte melden! Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2] Gruß Christian Boltz [1] Ist eigentlich irgendwo das Format dieser Dateien dokumentiert? Die Manpage ist leider nicht sonderlich auskunftsfreudig... [2] Man könnte die Ausgabe der "ls -1"-Schleife in eine Variable packen und (falls die Variable irgendwas enthält) eine Mail an $user@localhost versenden. Das einzubauen ist nicht sonderlich schwer, aber ich bin gerade zu müde dazu ;-) --
Der Testbug (#48) ist übrigens ein Duplikat von Bug #29 ;-) Shit. Machst du 'nen Bugreport? :-) [> Christian Boltz und Ratti in fontlinge-devel]
![](https://seccdn.libravatar.org/avatar/7b33cb1e776e35b87edb8ef09f0c888f.jpg?s=120&d=mm&r=g)
Hallo, Am Sun, 10 Jul 2005, Christian Boltz schrieb:
----------------------------------------------------------------------- #!/bin/bash
# usercron.daily # # Copyright (C)2005 by Christian Boltz - www.cboltz.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version.
me="${0//.*\/}"
Das ist ein "bashism", auf SuSE Linux legitim, da sowas ja AFAIR sogar in den bootscripten verwendet wird. Ansonsten: me="`basename \"$0\"`" (und zwar so und nicht anders gequoted!)
# get list of users userlist="`cut -d: -f1 /etc/passwd`"
# if /etc/cron.allow exists, allow only users in this file test -f /etc/cron.allow && userlist="`cat /etc/cron.allow`"
Wenn du (oben) schon Bashisms verwendest: && userlist="$(</etc/cron.allow)"
for user in $userlist ; do
Besser: getent passwd | cut -d':' -f1 | while read -r user; do oder wenn die user alle auch in der passwd stehen: cut -d':' -f1 /etc/passwd | while read -r user; do Bzw. mit dem Test mit cron.allow: ==== PASSWD='/etc/passwd' ALLOW='/etc/cron.allow' # [..] if test -f "$ALLOW" && test -r "$ALLOW"; then listusers='cat "$ALLOW"' else # listusers='cat "$PASSWD"' listusers='getent passwd' fi $listusers | cut -d ':' -f 1 | while read -r user; do ====
# deny cronjobs for users in /etc/cron.deny grep "^[ ]*$user[ ]*$" /etc/cron.deny &>/dev/null && continue # ^^^ und ^^^ = Space Tab
grep -q "^[[:space:]]*$user[[:space:]]*$" /etc/cron.deny && continue
# get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`";
Auch hier kann man 'getent' verwenden. "Einfacher" (naja, eher "effektiver" ;) ist aber: homedir="`awk -F ':' -v u=\"$user\" '$1 == u { print $6; }' /etc/passwd`"; bzw.: homedir="`getent passwd | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`"; Achso: da das script unter cron laufen soll, sollte wohl noch a) PATH zum script-Anfang ergaenzen / explizit setzen, oder b) alle Programme explizit mit Pfad aufrufen. Dazu also "suchen&ersetzen" von cat, cut, grep, awk, usw.... Naja, eigentlich sollten alle verwendeten Programme in /bin oder /usr/bin/ liegen, und die beiden Verzeichnisse sind in PATH eines cron-scriptes... Zumindest unter SuSE bzw. wohl auch den meisten (allen?) anderen GNU/Linux Systemen...
# test for .cron.* in homedir test -d "$homedir/$dirname" || continue
# search and execute scripts in ~/cron.* ls -1 "$homedir/$dirname/" | while read file ; do
Das '-1' ist ueberfluessig, schadet aber auch nicht. ls schreibt grundsaetzlich nur einspaltig, wenn stdout kein Terminal ist (sondern z.B. eine pipe). Das aber nur nebenbei ;)
test -x "$homedir/$dirname/$file" && {
Ich verwende, wenn ich Variablen zusammenfuege meistens ${} um auf der sicheren Seite zu sein, also 'test -x "${homedir}/${dirname}/${file}"' Sollte aber natuerlich auch so funktionieren ;)
# log and execute logger -t "$me" "($user) CMD ($homedir/$dirname/$file)" su "$user" -c "$homedir/$dirname/$file" } done done -----------------------------------------------------------------------
Die Benutzer können in ~/.cron.daily usw. Scripte anlegen, die dann mit entsprechenden User-Rechten ausgeführt werden.
Gute Idee jedenfalls ;)
Achtung: Obiges Script habe ich eben in Rekordzeit getippt - es ist also nur minimal getestet. Die Behandlung von cron.deny und cron.allow [1] habe ich eingebaut, aber nicht getestet.
Sieht ok aus, wenn in den beiden Datein jeweils einfach eine (zeilenweise) Liste von Usernamen steht.
Falls jemand Bugs oder mögliche Sicherheitslücken auffallen - bitte melden!
s.o. Eigentlich nicht. Sieht auch so sehr gut aus, ist anstaendig gequoted (wichtig!) usw. Aber ich musste halt trotzdem mal wieder meinen Senf dazu geben ;) Deine Version sieht jedenfalls schon "sauber" aus.
Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2]
Einfachst Variante, nur mit stderr als Mail: su "$user" -c "$homedir/$dirname/$file" 2>&1 >/dev/null | mail "$user" Man achte auf die Reihenfolge von '2>&1' und '>/dev/null'... Oder willst du evtl. Fehlermeldungen des scripts selber auch dem User zukommen lassen? -dnh -- Gib einem Hungrigen einen Fisch, und er ist fuer einen Tag satt. Zeig ihm, wie man angelt, und er poebelt Dich an, dass er besseres zu tun haette, als Schnuere ins Wasser haengen zu lassen. -- David Kastrup in de.comp.text.tex
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo David, hallo Leute, Am Sonntag, 10. Juli 2005 03:29 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb:
-------------------------------------------------------------------- --- #!/bin/bash
# usercron.daily # # Copyright (C)2005 by Christian Boltz - www.cboltz.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version.
me="${0//.*\/}"
Das ist ein "bashism", auf SuSE Linux legitim, da sowas ja AFAIR sogar in den bootscripten verwendet wird. Ansonsten:
Klar, deshalb ja auch #!/bin/bash ;-) Die SuSE-Bootscripte verwenden auch teilweise bash-spezifische Dinge - allerdings steht trotzdem meistens #!/bin/sh drin :-(
me="`basename \"$0\"`" (und zwar so und nicht anders gequoted!)
Klar.
# get list of users userlist="`cut -d: -f1 /etc/passwd`"
# if /etc/cron.allow exists, allow only users in this file test -f /etc/cron.allow && userlist="`cat /etc/cron.allow`"
Wenn du (oben) schon Bashisms verwendest:
&& userlist="$(</etc/cron.allow)"
Nett, kannte ich noch gar nicht.
for user in $userlist ; do
Besser:
getent passwd | cut -d':' -f1 | while read -r user; do
Stimmt eigentlich. Usernamen mit Leerzeichen sollten zwar "eigentlich"[tm] nicht vorkommen, aber man weiß ja nie ;-)
oder wenn die user alle auch in der passwd stehen:
cut -d':' -f1 /etc/passwd | while read -r user; do
Bzw. mit dem Test mit cron.allow:
==== PASSWD='/etc/passwd' ALLOW='/etc/cron.allow' # [..] if test -f "$ALLOW" && test -r "$ALLOW"; then listusers='cat "$ALLOW"' else # listusers='cat "$PASSWD"' listusers='getent passwd' fi
$listusers | cut -d ':' -f 1 | while read -r user; do ====
Schöne Lösung. Darf ich die übernehmen?
# deny cronjobs for users in /etc/cron.deny grep "^[ ]*$user[ ]*$" /etc/cron.deny &>/dev/null && continue # ^^^ und ^^^ = Space Tab
grep -q "^[[:space:]]*$user[[:space:]]*$" /etc/cron.deny && continue
Ist zumindest fürs Zitieren in Mails besser ;-)
# get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`";
Auch hier kann man 'getent' verwenden. "Einfacher" (naja, eher "effektiver" ;) ist aber:
homedir="`awk -F ':' -v u=\"$user\" '$1 == u { print $6; }' /etc/passwd`";
bzw.:
homedir="`getent passwd | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`";
Wenn schon awk, dann mit obiger Konstruktion mit $listusers - auch wenn das im Fall von /etc/cron.allow einen useless use of cat gibt ;-)
Achso: da das script unter cron laufen soll, sollte wohl noch
a) PATH zum script-Anfang ergaenzen / explizit setzen, oder b) alle Programme explizit mit Pfad aufrufen.
Eher a) ;-)
Dazu also "suchen&ersetzen" von cat, cut, grep, awk, usw.... Naja, eigentlich sollten alle verwendeten Programme in /bin oder /usr/bin/ liegen, und die beiden Verzeichnisse sind in PATH eines cron-scriptes... Zumindest unter SuSE bzw. wohl auch den meisten (allen?) anderen GNU/Linux Systemen...
Ich hoffe doch.
# test for .cron.* in homedir test -d "$homedir/$dirname" || continue
# search and execute scripts in ~/cron.* ls -1 "$homedir/$dirname/" | while read file ; do
Das '-1' ist ueberfluessig, schadet aber auch nicht. ls schreibt grundsaetzlich nur einspaltig, wenn stdout kein Terminal ist (sondern z.B. eine pipe). Das aber nur nebenbei ;)
test -x "$homedir/$dirname/$file" && {
Ich verwende, wenn ich Variablen zusammenfuege meistens ${} um auf der sicheren Seite zu sein, also 'test -x "${homedir}/${dirname}/${file}"' Sollte aber natuerlich auch so funktionieren ;)
Durch den / als einziges Zwischenzeichen habe ich keine Bedenken. Ansonsten ist Dein Einwand korrekt und bei mir auch nicht unüblich.
# log and execute logger -t "$me" "($user) CMD ($homedir/$dirname/$file)" su "$user" -c "$homedir/$dirname/$file" } done done -------------------------------------------------------------------- ---
Die Benutzer können in ~/.cron.daily usw. Scripte anlegen, die dann mit entsprechenden User-Rechten ausgeführt werden.
Gute Idee jedenfalls ;)
Achtung: Obiges Script habe ich eben in Rekordzeit getippt - es ist also nur minimal getestet. Die Behandlung von cron.deny und cron.allow [1] habe ich eingebaut, aber nicht getestet.
Sieht ok aus, wenn in den beiden Datein jeweils einfach eine (zeilenweise) Liste von Usernamen steht.
Hatte ich auch vermutet, aber mangels schriftlichem Beweis...
Falls jemand Bugs oder mögliche Sicherheitslücken auffallen - bitte melden!
s.o. Eigentlich nicht. Sieht auch so sehr gut aus, ist anstaendig gequoted (wichtig!) usw. Aber ich musste halt trotzdem mal wieder meinen Senf dazu geben ;) Deine Version sieht jedenfalls schon "sauber" aus.
Danke ;-)
Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2]
Einfachst Variante, nur mit stderr als Mail:
su "$user" -c "$homedir/$dirname/$file" 2>&1 >/dev/null | mail "$user"
Man achte auf die Reihenfolge von '2>&1' und '>/dev/null'...
Das Problem dabei: Wenn es keine Ausgabe gibt, erhält der User eine leere Mail - das will ich eigentlich vermeiden.
Oder willst du evtl. Fehlermeldungen des scripts selber auch dem User zukommen lassen?
Nö, das ist wieder eine Sache für root ;-) Gruß Christian Boltz -- "Wirklich praxisnah wären Münzen zu EUR 0,99." [Wolfgang Schwanke in de.etc.sprache.deutsch]
![](https://seccdn.libravatar.org/avatar/7b33cb1e776e35b87edb8ef09f0c888f.jpg?s=120&d=mm&r=g)
Hallo, Am Sun, 10 Jul 2005, Christian Boltz schrieb:
Am Sonntag, 10. Juli 2005 03:29 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb:
-------------------------------------------------------------------- --- #!/bin/bash
# usercron.daily # # Copyright (C)2005 by Christian Boltz - www.cboltz.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version.
me="${0//.*\/}"
Das ist ein "bashism", auf SuSE Linux legitim, da sowas ja AFAIR sogar in den bootscripten verwendet wird. Ansonsten:
Klar, deshalb ja auch #!/bin/bash ;-)
Die SuSE-Bootscripte verwenden auch teilweise bash-spezifische Dinge - allerdings steht trotzdem meistens #!/bin/sh drin :-(
Jep. Naja, SuSE legt eben auch /bin/sh -> bash an, und wer das aendert muss eben wissen was er tut. Schoen ist es aber nicht.
Wenn du (oben) schon Bashisms verwendest:
&& userlist="$(</etc/cron.allow)"
Nett, kannte ich noch gar nicht.
*g* [..]
Bzw. mit dem Test mit cron.allow:
==== PASSWD='/etc/passwd' ALLOW='/etc/cron.allow' # [..] if test -f "$ALLOW" && test -r "$ALLOW"; then listusers='cat "$ALLOW"' else # listusers='cat "$PASSWD"' listusers='getent passwd' fi
$listusers | cut -d ':' -f 1 | while read -r user; do ====
Schöne Lösung. Darf ich die übernehmen?
Was meinst du, warum ich die geschrieben habe? Klar darfst du!
# deny cronjobs for users in /etc/cron.deny grep "^[ ]*$user[ ]*$" /etc/cron.deny &>/dev/null && continue # ^^^ und ^^^ = Space Tab
grep -q "^[[:space:]]*$user[[:space:]]*$" /etc/cron.deny && continue
Ist zumindest fürs Zitieren in Mails besser ;-)
Jep :) Achso: das ein grep die Zeichenklassen kennt ist zwar POSIX und GNU (und BSD AFAIK) aber sonst (v.a. auf kommerziellen Unices) gibt's haeufiger noch greps die das nicht koennen. Das nur nebenbei, aber wir haben uns ja wohl eh schon auf bash und GNU grep und so festgelegt ;)
# get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`";
Auch hier kann man 'getent' verwenden. "Einfacher" (naja, eher "effektiver" ;) ist aber:
homedir="`awk -F ':' -v u=\"$user\" '$1 == u { print $6; }' /etc/passwd`";
bzw.:
homedir="`getent passwd | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`";
Wenn schon awk, dann mit obiger Konstruktion mit $listusers - auch wenn das im Fall von /etc/cron.allow einen useless use of cat gibt ;-)
Stimmt. BTW: gerade bei sowas ist das eben nicht "useless" weil man sonst das '| awk ...' zweimal in die if .. then .. else .. fi Klausel schreiben muss. Ok, aufgerufen wird dann awk nur einmal, ich find's aber so leserlicher (eben dass beide Male das gleiche gemacht wird).
Achso: da das script unter cron laufen soll, sollte wohl noch
a) PATH zum script-Anfang ergaenzen / explizit setzen, oder b) alle Programme explizit mit Pfad aufrufen.
Eher a) ;-)
*g* [..]
test -x "$homedir/$dirname/$file" && {
Ich verwende, wenn ich Variablen zusammenfuege meistens ${} um auf der sicheren Seite zu sein, also 'test -x "${homedir}/${dirname}/${file}"' Sollte aber natuerlich auch so funktionieren ;)
Durch den / als einziges Zwischenzeichen habe ich keine Bedenken. Ansonsten ist Dein Einwand korrekt und bei mir auch nicht unüblich.
Ich habe mir eben angewoehnt *grundsaetzlich* so zu scripten; so wie ich auch Variablen immer quote, es sei denn ich habe sie selbst gesetzt und darf nicht quoten (s.o. $listusers, da muesste man dann 'eval "$listusers"' verwenden). Ansonsten quote ich alles, auch wenn selbst gesetzt. Hat eben den Vorteil, dass ich nur dann nachdenken muss, wenn's mal nicht mit ${} oder '' oder "" klappt.
Achtung: Obiges Script habe ich eben in Rekordzeit getippt - es ist also nur minimal getestet. Die Behandlung von cron.deny und cron.allow [1] habe ich eingebaut, aber nicht getestet.
Sieht ok aus, wenn in den beiden Datein jeweils einfach eine (zeilenweise) Liste von Usernamen steht.
Hatte ich auch vermutet, aber mangels schriftlichem Beweis...
Hm. Laut man 1 crontab sind das /var/spool/cron/{allow,deny} und ich habe eine /var/cron/deny in meiner SuSE 6.2 und eine /var/spool/cron/deny in der 9.1. ==== SUSE 9.1: man 1p crontab ==== Users shall be permitted to use crontab if their names appear in the file /usr/lib/cron/cron.allow. If that file does not exist, the file /usr/lib/cron/cron.deny shall be checked to determine whether the user shall be denied access to crontab. If neither file exists, only a process with appropriate privileges shall be allowed to submit a job. If only cron.deny exists and is empty, global usage shall be permitted. The cron.allow and cron.deny files shall consist of one user name per line. ==== # rpm -qf `man -w 1p crontab` man-pages-1.66-38 # man -k crontab [gekuerzt] crontab (1p) - schedule periodic background work crontab (1) - maintain crontab files for individual users (V3) Ist zumindest mal ein Hinweis, dass wir nicht ganz falsch mit der Vermutung liegen ;) [..]
Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2]
Einfachst Variante, nur mit stderr als Mail:
su "$user" -c "$homedir/$dirname/$file" 2>&1 >/dev/null | mail "$user"
Man achte auf die Reihenfolge von '2>&1' und '>/dev/null'...
Das Problem dabei: Wenn es keine Ausgabe gibt, erhält der User eine leere Mail - das will ich eigentlich vermeiden.
Oder willst du evtl. Fehlermeldungen des scripts selber auch dem User zukommen lassen?
Nö, das ist wieder eine Sache für root ;-)
Achso, dann schreib selber logs und maile dem User ggfs. nur eine Meldung: ==== #!/bin/bash exec 1>/var/log/usercron.log exec 2>/var/log/usercron.err errexit() { err="$1"; shift; user="$1"; shift; if test -z "$err" || test -z "$user"; then echo "Invalid params for 'errexit()'" >&2 exit 22 ## EINVAL fi getent passwd "$user" >/dev/null || { echo "Unknown user for 'errexit()'" >&2 exit 2 ## das gibt auch getent zurueck } echo "$me: Error($err): $@" | mail -s "usercron Error" "$user" exit $err } user=... ## nur als Beispiel: trap "errexit 2 $user 'Command cancelled'" INT [..] machwas || errexit FEHLERCODE USERNAME "FEHLERMELDUNG MIT ODER" \ OHNE QUOTES ==== Wobei "FEHLERCODE" z.B. auch $? sein kann. Das nur so als Anregung ;) HTH, -dnh --
Genauso könntest Du einen Grafiker in den Farbraum schicken. Was mich daran erinnert, dass Maler zwar von Farb_tönen_, Musiker aber von Klang_farben_ reden. [Michael Fesser, Markus Kottenhahn in <darw/>]
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo David, hallo Leute, Am Montag, 11. Juli 2005 00:22 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb:
Am Sonntag, 10. Juli 2005 03:29 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb: [...] Bzw. mit dem Test mit cron.allow:
==== PASSWD='/etc/passwd' ALLOW='/etc/cron.allow' # [..] if test -f "$ALLOW" && test -r "$ALLOW"; then
Useless use of second test ;-) test -f "$ALLOW" -a -r "$ALLOW"
listusers='cat "$ALLOW"' else # listusers='cat "$PASSWD"' listusers='getent passwd' fi
BTW: Ich bin Experte im Vermeiden von if-Blöcken in Bash-Scripten ;-) listusers='getent passwd' test -f -a -r "$ALLOW" && listusers='cat "$ALLOW"'
$listusers | cut -d ':' -f 1 | while read -r user; do
Der "cut ..." gehört wohl noch zur Variable $listusers - /var/spool/cron/allow enthält ja _nur_ Usernamen. (nach einem kurzen Test) Soviel zur Theorie. In der Praxis bekomme ich eine "nette" Fehlermeldung - dann also doch hinter den $listusers-Aufruf :-/
====
Schöne Lösung. Darf ich die übernehmen?
Was meinst du, warum ich die geschrieben habe? Klar darfst du!
Eine Nachfrage kann nie schaden - weiß ich, ob Deine Mail unter GPL steht? ;-)
# deny cronjobs for users in /etc/cron.deny grep "^[ ]*$user[ ]*$" /etc/cron.deny &>/dev/null && continue # ^^^ und ^^^ = Space Tab
grep -q "^[[:space:]]*$user[[:space:]]*$" /etc/cron.deny && continue
Ist zumindest fürs Zitieren in Mails besser ;-)
Jep :) Achso: das ein grep die Zeichenklassen kennt ist zwar POSIX und GNU (und BSD AFAIK) aber sonst (v.a. auf kommerziellen Unices) gibt's haeufiger noch greps die das nicht koennen. Das nur nebenbei, aber wir haben uns ja wohl eh schon auf bash und GNU grep und so festgelegt ;)
Eben.
# get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`";
Auch hier kann man 'getent' verwenden. "Einfacher" (naja, eher "effektiver" ;) ist aber:
homedir="`awk -F ':' -v u=\"$user\" '$1 == u { print $6; }' /etc/passwd`";
/etc/passwort schließt aber nicht-/etc/passwd-User (z. B. LDAP, ...) aus, und das haben wir ja oben mit getent vermieden. Deshalb:
bzw.:
homedir="`getent passwd | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`";
... ist das wohl geschickter. Hmm, ob awk so viel schneller ist als grep | cut? Mal sehen... # time for i in `seq 1 1000` ; do echo "a:b:c d:e:f" | grep "^d:" | cut -d':' -f1; done >/dev/null real 0m2.879s user 0m1.087s sys 0m1.761s # time for i in `seq 1 1000` ; do echo "a:b:c d:e:f" | awk -F ':' '$1 == "d" { print $1; }' ; done >/dev/null real 0m1.674s user 0m0.609s sys 0m1.034s Tatsächlich - auch wenn der Unterschied in der Praxis mangels entsprechender Userzahl eher irrelevant sein dürfte ;-) Das Cachen von `getent passwd` in einer Variable müsste auch etwas bringen - echo "$cache" dürfte deutlich schneller sein als getent ;-) # time { for i in `seq 1 1000` ; do getent passwd ; done >/dev/null ; } real 0m1.474s user 0m0.612s sys 0m0.783s # time { cache=`getent passwd` ; for i in `seq 1 1000` ; do echo "$cache" ; done >/dev/null ; } real 0m0.193s user 0m0.151s sys 0m0.003s Bei NIS/LDAP/sonstwas-Usern dürfte der Unterschied nochmal deutlicher sein, also: Rein mit dem Cache ;-)
Achso: da das script unter cron laufen soll, sollte wohl noch
a) PATH zum script-Anfang ergaenzen / explizit setzen, oder b) alle Programme explizit mit Pfad aufrufen.
Eher a) ;-)
*g*
Da ich /bin und /usr/bin sogar im cron-Pfad vermute, habe ich erstmal auf ein explizites Setzen von $PATH verzichtet. Und eins meiner Scripte in ~/.cron.daily müsste mir demnächst `env` zwecks Kontrolle zumailen ;-)
[..]
test -x "$homedir/$dirname/$file" && {
Ich verwende, wenn ich Variablen zusammenfuege meistens ${} um auf der sicheren Seite zu sein, also 'test -x "${homedir}/${dirname}/${file}"' Sollte aber natuerlich auch so funktionieren ;)
Durch den / als einziges Zwischenzeichen habe ich keine Bedenken. Ansonsten ist Dein Einwand korrekt und bei mir auch nicht unüblich.
Ich habe mir eben angewoehnt *grundsaetzlich* so zu scripten; so wie ich auch Variablen immer quote,
Ich bin eben manchmal etwas tippfaul - aber nur, wenn ich genau weiß, was ich tue. [...]
Hat eben den Vorteil, dass ich nur dann nachdenken muss, wenn's mal nicht mit ${} oder '' oder "" klappt.
;-)
Achtung: Obiges Script habe ich eben in Rekordzeit getippt - es ist also nur minimal getestet. Die Behandlung von cron.deny und cron.allow [1] habe ich eingebaut, aber nicht getestet.
Sieht ok aus, wenn in den beiden Datein jeweils einfach eine (zeilenweise) Liste von Usernamen steht.
Hatte ich auch vermutet, aber mangels schriftlichem Beweis...
Hm. Laut man 1 crontab sind das /var/spool/cron/{allow,deny} und ich habe eine /var/cron/deny in meiner SuSE 6.2 und eine /var/spool/cron/deny in der 9.1.
==== SUSE 9.1: man 1p crontab ==== Users shall be permitted to use crontab if their names appear in the file /usr/lib/cron/cron.allow. If that file does not exist, the file /usr/lib/cron/cron.deny shall be checked to determine whether the user shall be denied access to crontab.
Das habe ich ja bereits so implementiert.
If neither file exists, only a process with appropriate privileges shall be allowed to submit a job.
Schöne Spezialität - naja, der Vollständigkeit halber baue ich das auch noch ein.
If only cron.deny exists and is empty, global usage shall be permitted.
Das regelt bereits grep.
The cron.allow and cron.deny files shall consist of one user name per line.
Prima, das Format ist also auch klar.
====
# rpm -qf `man -w 1p crontab` man-pages-1.66-38 # man -k crontab [gekuerzt] crontab (1p) - schedule periodic background work crontab (1) - maintain crontab files for individual users (V3)
Sowas fieses. man 1 crontab hatte ich ja schon gefunden, aber die 1p ist mir entwischt. crontab(1) und crontab(5) enthalten auch keinen Hinweis darauf. Bei mir (SuSE 9.3) heißen die Dateien übrigens /var/spool/cron/deny (bzw. .../allow) - zumindest deny habe ich "erfolglos" getestet.
Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2]
Einfachst Variante, nur mit stderr als Mail:
su "$user" -c "$homedir/$dirname/$file" 2>&1 >/dev/null | mail "$user"
Man achte auf die Reihenfolge von '2>&1' und '>/dev/null'...
Das Problem dabei: Wenn es keine Ausgabe gibt, erhält der User eine leere Mail - das will ich eigentlich vermeiden.
Oder willst du evtl. Fehlermeldungen des scripts selber auch dem User zukommen lassen?
Nö, das ist wieder eine Sache für root ;-)
Achso, dann schreib selber logs und maile dem User ggfs. nur eine Meldung:
==== #!/bin/bash
exec 1>/var/log/usercron.log exec 2>/var/log/usercron.err
Damit hätte ich die Ausgabe für alle User in einem gemeinsamen Log :-(
errexit() { err="$1"; shift; user="$1"; shift;
if test -z "$err" || test -z "$user"; then echo "Invalid params for 'errexit()'" >&2 exit 22 ## EINVAL fi
getent passwd "$user" >/dev/null || { echo "Unknown user for 'errexit()'" >&2 exit 2 ## das gibt auch getent zurueck }
Zumindest dieser Test dürfte eher überflüssig sein - außer durch einen flaschen Eintrag in cron.allow haben wir ja - siehe getent - garantiert gültige Usernamen. Auch wenn sich mal ein ungültiger einschleichen sollte, wäre das beim Mailversand nicht so schlimm - es geht eben ein Bounce an root - vielleicht merkt er dadurch ja den Fehler in cron.allow. Moment - nicht existente User bzw. leeres homedir sollte ich nach homedir=... abfangen, ansonsten wird nach /.cron.daily gesucht... [...]
Das nur so als Anregung ;)
Danke - aber ich hatte eher an ein paar Backticks rund um die "ls"-Schleife gedacht (gefolgt von test -n und so). Das würde dafür sorgen, dass jeder User die für ihn gedachten Meldungen sieht. Heute nicht mehr. So, hier noch der aktuelle Stand des Scripts: ----------------------------------------------------------------------- #!/bin/bash # usercron.daily # # Copyright (C)2005 by Christian Boltz - www.cboltz.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # check man 1p crontab for the correct ALLOW / DENY filenames ALLOW='/var/spool/cron/allow' DENY='/var/spool/cron/deny' PASSWD='/etc/passwd' me="${0//.*\/}" case "$me" in usercron.monthly) dirname=.cron.monthly ;; usercron.weekly) dirname=.cron.weekly ;; usercron.daily) dirname=.cron.daily ;; usercron.hourly) dirname=.cron.hourly ;; *) echo "unknown basename. Please name this script (or its symlink)" echo "usercron.monthly, usercron.weekly, usercron.daily or" echo "usercron.hourly." exit 1 esac # get list of users listusers='getent passwd' # default command # if /etc/cron.allow exists, allow only users in this file test -f "$ALLOW" -a -r "$ALLOW" && listusers='cat "$ALLOW"' # see man 1p crontab for the following behaviour again ;-) test -f "$ALLOW" -o -f "$DENY" && { logger -t "$me" "neither $ALLOW or $DENY exist - exiting" exit 0 } usercache="`getent passwd`" $listusers | cut -d ':' -f 1 | while read -r user ; do # deny cronjobs for users in /etc/cron.deny grep "^[[:space:]]*$user[[:space:]]*$" "$DENY" &>/dev/null && continue # get homedir for $user homedir="`echo \"$usercache\" | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`"; test -n "$homedir" || { # no homedir? bad. logger -t "$me" "ERROR: user $user has no homedir" continue } # test for .cron.* in homedir test -d "$homedir/$dirname" || continue # search and execute scripts in ~/cron.* ls -1 "$homedir/$dirname/" | while read file ; do test -x "$homedir/$dirname/$file" && { # log and execute logger -t "$me" "($user) CMD ($homedir/$dirname/$file)" su "$user" -c "$homedir/$dirname/$file" } done done ----------------------------------------------------------------------- Demnächst[tm] auch zu finden auf www.cboltz.de ;-) Gruß Christian Boltz --
Aber sorry, habe die Schnauze voll mit Linux.... Da gehört's eindeutig nicht hin. Nimm's lieber wieder raus. [> Juergen Jaeckel und Bernd Glueckert in suse-linux]
![](https://seccdn.libravatar.org/avatar/7b33cb1e776e35b87edb8ef09f0c888f.jpg?s=120&d=mm&r=g)
Hallo, Am Thu, 14 Jul 2005, Christian Boltz schrieb:
Am Montag, 11. Juli 2005 00:22 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb:
Am Sonntag, 10. Juli 2005 03:29 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb: [...] Bzw. mit dem Test mit cron.allow:
==== PASSWD='/etc/passwd' ALLOW='/etc/cron.allow' # [..] if test -f "$ALLOW" && test -r "$ALLOW"; then
Useless use of second test ;-)
Absicht.
test -f "$ALLOW" -a -r "$ALLOW"
Ist nicht portabel. Hab ich mir so angewoehnt. Aber das Script verwendet ja GNU bash / test, also ok.
listusers='cat "$ALLOW"' else # listusers='cat "$PASSWD"' listusers='getent passwd' fi
BTW: Ich bin Experte im Vermeiden von if-Blöcken in Bash-Scripten ;-)
*g* Mach ich auch gern, aber nicht zu oft.
listusers='getent passwd' test -f -a -r "$ALLOW" && listusers='cat "$ALLOW"'
Ok.
$listusers | cut -d ':' -f 1 | while read -r user; do
Der "cut ..." gehört wohl noch zur Variable $listusers - /var/spool/cron/allow enthält ja _nur_ Usernamen.
(nach einem kurzen Test)
Soviel zur Theorie. In der Praxis bekomme ich eine "nette" Fehlermeldung - dann also doch hinter den $listusers-Aufruf :-/
Genau. Grund: die Pipe wird in der Variablen nur ausgewertet, wenn du die Kommandozeile nochmal parsen laesst, also: listusers="foo | bar" $listusers ## => Fehler eval "$listusers" ## => OK Deswegen habe ich eben die etwas langsamere Version mit cat und cut entschieden und verzichte auf's eval. Hm. Andererseits sollte der Inhalt von $listusers ja immer ok sein, d.h. ein "eval" drauf waere ungefaehrlich. Du kannst also doch: ==== listusers='getent passwd | cut -d":" -f 1' test -f -a -r "$ALLOW" && listusers='cat "$ALLOW"' eval "$listusers" | while read -r user; do ... ==== verwenden.
Schöne Lösung. Darf ich die übernehmen?
Was meinst du, warum ich die geschrieben habe? Klar darfst du!
Eine Nachfrage kann nie schaden - weiß ich, ob Deine Mail unter GPL steht? ;-)
Du kannst davon ausgehen, dass hier alle scripte usw. von mir unter der GPL v2.0 (aber nicht unbedingt spaeterer Versionen) steht.
# get homedir for $user homedir="`grep \"^$user:\" /etc/passwd | cut -d: -f6`";
Auch hier kann man 'getent' verwenden. "Einfacher" (naja, eher "effektiver" ;) ist aber:
homedir="`awk -F ':' -v u=\"$user\" '$1 == u { print $6; }' /etc/passwd`";
/etc/passwort schließt aber nicht-/etc/passwd-User (z. B. LDAP, ...) aus, und das haben wir ja oben mit getent vermieden. Deshalb:
Jup. Ich wusste ja nicht, ob du den Vorschlag mit getent uebernimmst ;)
bzw.:
homedir="`getent passwd | awk -F ':' -v u=\"$user\" '$1 == u { print $6; }'`";
... ist das wohl geschickter.
Jep.
Hmm, ob awk so viel schneller ist als grep | cut? Mal sehen...
# time for i in `seq 1 1000` ; do echo "a:b:c d:e:f" | grep "^d:" | cut -d':' -f1; done >/dev/null
real 0m2.879s user 0m1.087s sys 0m1.761s
# time for i in `seq 1 1000` ; do echo "a:b:c d:e:f" | awk -F ':' '$1 == "d" { print $1; }' ; done >/dev/null
real 0m1.674s user 0m0.609s sys 0m1.034s
Tatsächlich - auch wenn der Unterschied in der Praxis mangels entsprechender Userzahl eher irrelevant sein dürfte ;-)
Jep. Faustregel: Wenn du was direkt mit awk machen kannst ist das fast immer schneller als zwei andere Prozesse wie grep/sed/cut etc.
Das Cachen von `getent passwd` in einer Variable müsste auch etwas bringen - echo "$cache" dürfte deutlich schneller sein als getent ;-)
# time { for i in `seq 1 1000` ; do getent passwd ; done >/dev/null ; }
real 0m1.474s user 0m0.612s sys 0m0.783s
# time { cache=`getent passwd` ; for i in `seq 1 1000` ; do echo "$cache" ; done >/dev/null ; }
real 0m0.193s user 0m0.151s sys 0m0.003s
Eben. Deswegen ist ein Benchmark oben auch noch etwas "defekt" wenn du die Daten auf einmal bekommen kannst, da du da v.a. die Startzeiten der Prozesse misst (zu sehen am hohen 'sys' Anteil). Und hier unten am minimalen 'sys' Anteil beim 'echo "$cache"'. Prozesse starten ist eben relativ "teuer".
Bei NIS/LDAP/sonstwas-Usern dürfte der Unterschied nochmal deutlicher sein, also: Rein mit dem Cache ;-)
ACK.
Achso: da das script unter cron laufen soll, sollte wohl noch
a) PATH zum script-Anfang ergaenzen / explizit setzen, oder b) alle Programme explizit mit Pfad aufrufen.
Eher a) ;-)
*g*
Da ich /bin und /usr/bin sogar im cron-Pfad vermute, habe ich erstmal auf ein explizites Setzen von $PATH verzichtet.
Und eins meiner Scripte in ~/.cron.daily müsste mir demnächst `env` zwecks Kontrolle zumailen ;-)
Ok ;)
Ich bin eben manchmal etwas tippfaul - aber nur, wenn ich genau weiß, was ich tue.
Ok. Interaktiv in der shell mach ich das auch eher so, das sieht dann aber eben auch nur meine ~/.bash_history...
# rpm -qf `man -w 1p crontab` man-pages-1.66-38 # man -k crontab [gekuerzt] crontab (1p) - schedule periodic background work crontab (1) - maintain crontab files for individual users (V3)
Sowas fieses. man 1 crontab hatte ich ja schon gefunden, aber die 1p ist mir entwischt. crontab(1) und crontab(5) enthalten auch keinen Hinweis darauf.
Bei mir (SuSE 9.3) heißen die Dateien übrigens /var/spool/cron/deny (bzw. .../allow) - zumindest deny habe ich "erfolglos" getestet.
*g* Wobei ich mir nicht so sicher bin, wo die 1p herkommt. Naja, zu passen scheint sie ja. Auf meiner 6.2 habe ich die 1p-manpage auch nicht. Hm. Ich schaetze mal, dass die 1p die POSIX Version dokumentiert, und der vixie-cron von SUSE 9.x scheint sich daran zu halten...
Eine noch offene Baustelle ist der Mailversand im Fehlerfall - die Mail geht nämlich grundsätzlich an root, nicht an den jeweiligen User. Falls jemand eine gute Idee hat, wie man dieses Problem elegant löst - immer her damit ;-) [2] [..] ==== #!/bin/bash
exec 1>/var/log/usercron.log exec 2>/var/log/usercron.err
Damit hätte ich die Ausgabe für alle User in einem gemeinsamen Log :-(
Ja. Davon hattest du aber ja auch nix gesagt.
errexit() { err="$1"; shift; user="$1"; shift;
if test -z "$err" || test -z "$user"; then echo "Invalid params for 'errexit()'" >&2 exit 22 ## EINVAL fi
getent passwd "$user" >/dev/null || { echo "Unknown user for 'errexit()'" >&2 exit 2 ## das gibt auch getent zurueck }
Zumindest dieser Test dürfte eher überflüssig sein - außer durch einen flaschen Eintrag in cron.allow haben wir ja - siehe getent - garantiert gültige Usernamen.
Stimmt wohl.
Moment - nicht existente User bzw. leeres homedir sollte ich nach homedir=... abfangen, ansonsten wird nach /.cron.daily gesucht...
Jep.
[...]
Das nur so als Anregung ;)
Danke - aber ich hatte eher an ein paar Backticks rund um die "ls"-Schleife gedacht (gefolgt von test -n und so). Das würde dafür sorgen, dass jeder User die für ihn gedachten Meldungen sieht.
Heute nicht mehr.
Hae? Sowas wie ich unten einfuege?
So, hier noch der aktuelle Stand des Scripts:
----------------------------------------------------------------------- #!/bin/bash [..] # search and execute scripts in ~/cron.* ls -1 "$homedir/$dirname/" | while read file ; do test -x "$homedir/$dirname/$file" && { # log and execute logger -t "$me" "($user) CMD ($homedir/$dirname/$file)" su "$user" -c "$homedir/$dirname/$file" } } 2>&1 | mail \ -s "[usercron] output of CMD ($homedir/$dirname/$file)" \ "$user"
done done -----------------------------------------------------------------------
Hm. Eigentlich reicht's das hinter's su .. zu packen... Oder gleich die ganze Schleife vermailen: { ls .. | while read file; do ..; done } 2>&1 | mail ... HTH & HAND, -dnh --
Why is the speed of light so slow? If the quantum police catch its starship speeding again, it'll be forced to walk the Planck. -- The Usenet Oracle
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo Andy, hallo Leute, Am Montag, 6. Juni 2005 11:44 schrieb Andreas Schott:
Am Sonntag, 5. Juni 2005 22:03 schrieb Christian Boltz:
Am Sonntag, 5. Juni 2005 18:50 schrieb Andreas Schott:
Es gibt aber doch auch die Möglichkeit Skripte einmal täglich auszuführen, egal wann der Rechner eingeschaltet wird. Ich möchte eigentlich nur ein Backup täglich haben.
Hierzu habe ich mein Backupscript (welches in der crontab eingetragen perfekt funktioniert) nach /etc/cron.daily kopiert.
andreas:/etc/cron.daily # ls -l
-rwxr-xr-x 1 root root 990 2005-01-08 10:38 Backup
Passt.
Prima. Ich hab das Backupscript jetzt nach cron.hourly gepackt um leichter kontrollieren zu können.
Hier wird es aber definitiv nicht ausgeführt (siehe Logfile).
Bei cron.daily werden nicht die einzelnen Scripte geloggt, sondern nur den Aufruf von run-crons. Das greppen nach "Backup" kann also nicht funktionieren.
Wusste ich nicht. Wird das nirgendwo geloggt?
Nicht direkt. Du kannst es aber erzwingen ;-) #!/bin/bash echo "cron.hourly laeuft gerade" | logger in /etc/cron.hourly/ als Script ablegen und ausführbar machen. [...]
Warum wird mein Script denn nicht ausgeführt?
Vielleicht wird es das ja schon - guck doch einfach mal nach, ob ein aktuelles Backup existiert ;-)
Nein es existiert definitv kein Backup. Das sollte doch in dem Fall maximal 15 Minuten nach dem Booten des Rechners laufen, oder?
Zusätzlich gelten noch die Zeitabstände (z. B. 24 Stunden bei cron.daily). Wenn das Script also vor kurzem schonmal gelaufen ist, macht es erstmal Urlaub ;-)
Das booten ist nun schon fast zwei Stunden her
grep cron /var/log/messages ergibt u.a. Jun 6 08:59:00 andreas /USR/SBIN/CRON[6409]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly) Jun 6 09:59:00 andreas /USR/SBIN/CRON[6951]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly)
Hmm, ich vermisse den Aufruf von /usr/lib/cron/run-crons in Deinem Log. Oder hast Du den hier unterschlagen? ;-) (Falls der Aufruf von run-crons die letzte Zeile Deiner crontab ist, hänge danach noch eine leere Zeile an. Cron besteht angeblich drauf.)
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers. (Ich sichere mittels rsync) Den Key für den user andreas habe ich auf den Server geladen, damit das Teil ohne Passwortabfrage durchläuft. Aber den Key für root würde ich ungern dort ablegen.
Heißt das, dass Dein Script eine Benutzereingabe braucht? Kein Wunder, dass es nicht geht - cron kann keine Passwörter tippen ;-) Falls Du eine einigermaßen[1] sichere Lösung suchst, würde ich einen SSH-Key mit Passphrase und einen ssh-agent im Hintergrund empfehlen. Mit dieser Methode ist der Key nur benutzbar, solange der Rechner an ist. Nach Stromausfall/Reboot/Diebstahl/... muss man erst wieder die Passphrase eintippen. Ich habe sowas zum Sichern eines Servers am Laufen, Details auf Nachfrage. (keychain ginge, ist aber für sowas deutlich oversized.) Gruß Christian Boltz [1] 100% sicher sind Automatismen nie. Der Trick besteht darin, bei möglichst wenig Unbequemlicheit möglichst viel Sicherheit zu bekommen ;-) -- Vielleicht habe ich ja Glück und fang mir eine tödliche Krankheit ein, dann kann ich das Rauchen wieder anfangen. [Ratti in fontlinge-devel]
![](https://seccdn.libravatar.org/avatar/80ee424cfb65480d7f2de25c9974125b.jpg?s=120&d=mm&r=g)
Hallo Christian, hallo Leute Am Montag, 6. Juni 2005 21:26 schrieb Christian Boltz: [..]
Zusätzlich gelten noch die Zeitabstände (z. B. 24 Stunden bei cron.daily). Wenn das Script also vor kurzem schonmal gelaufen ist, macht es erstmal Urlaub ;-)
Klar.
Das booten ist nun schon fast zwei Stunden her
grep cron /var/log/messages ergibt u.a. Jun 6 08:59:00 andreas /USR/SBIN/CRON[6409]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly) Jun 6 09:59:00 andreas /USR/SBIN/CRON[6951]: (root) CMD ( rm -f /var/spool/cron/lastrun/cron.hourly)
Hmm, ich vermisse den Aufruf von /usr/lib/cron/run-crons in Deinem Log. Oder hast Du den hier unterschlagen? ;-)
Frech unterschlagen, weil er aufgerufen wird.
(Falls der Aufruf von run-crons die letzte Zeile Deiner crontab ist, hänge danach noch eine leere Zeile an. Cron besteht angeblich drauf.)
Steht so drin
Rufe ich das Script manuell aus /etc/cron.hourly auf, so startet es und fragt nach dem Rootpasswort des Servers. (Ich sichere mittels rsync) Den Key für den user andreas habe ich auf den Server geladen, damit das Teil ohne Passwortabfrage durchläuft. Aber den Key für root würde ich ungern dort ablegen.
Heißt das, dass Dein Script eine Benutzereingabe braucht? Kein Wunder, dass es nicht geht - cron kann keine Passwörter tippen ;-)
Wie warum das denn nicht? Nein Scherz beiseite. Benutzereingaben werden nur erwartet, wenn root das Teil startet. Deshalb meine Überlegung es als User zu starten (da liegt der ssh-key schon auf dem Server) und cron müsste nicht tippen. Oder geht das mit cron.hourly nicht?
Falls Du eine einigermaßen[1] sichere Lösung suchst, würde ich einen SSH-Key mit Passphrase und einen ssh-agent im Hintergrund empfehlen. Mit dieser Methode ist der Key nur benutzbar, solange der Rechner an ist. Nach Stromausfall/Reboot/Diebstahl/... muss man erst wieder die Passphrase eintippen.
Ist das nicht ein wenig heikel an einem laufenden Rechner für root ohne Passwort per ssh Zugriff zu erlauben? Andy
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo Andy, hallo Leute, auch hier: Sorry für die Verzögerung ;-) Am Montag, 6. Juni 2005 22:24 schrieb Andreas Schott:
Am Montag, 6. Juni 2005 21:26 schrieb Christian Boltz: [...]
Heißt das, dass Dein Script eine Benutzereingabe braucht? Kein Wunder, dass es nicht geht - cron kann keine Passwörter tippen ;-)
Wie warum das denn nicht? Nein Scherz beiseite. Benutzereingaben werden nur erwartet, wenn root das Teil startet. Deshalb meine Überlegung es als User zu starten (da liegt der ssh-key schon auf dem Server) und cron müsste nicht tippen. Oder geht das mit cron.hourly nicht?
Siehe nebenan ;-)
Falls Du eine einigermaßen[1] sichere Lösung suchst, würde ich einen SSH-Key mit Passphrase und einen ssh-agent im Hintergrund empfehlen. Mit dieser Methode ist der Key nur benutzbar, solange der Rechner an ist. Nach Stromausfall/Reboot/Diebstahl/... muss man erst wieder die Passphrase eintippen.
Ist das nicht ein wenig heikel an einem laufenden Rechner für root ohne Passwort per ssh Zugriff zu erlauben?
Jein ;-) Grundsätzlich: Wenn dem Script auch User-Rechte reichen, ist das natürlich sicherer. (Aber auch User-Logins kann man mit untenstehenden Schritten besser absichern.) Falls root-Rechte nötig sind (z. B. für ein Backup des kompletten Systems), verwende ich folgende Lösung: - einen SSH-Key, der per Passphrase geschützt ist - ein kleines Startscript, das den ssh-agent startet - aber anstatt seine Ausgabe wie üblich mit eval auszuwerten, wird diese nach /root/irgendwas geschrieben - ein Freischalt-Script, das /root/irgendwas source't und dann ssh-add aufruft. Mit diesem Script muss nach jedem Reboot der Key freigeschaltet werden - der Key ist also zumindest nach einem Stromausfall (durch Diebstahl des Rechners, Booten mit Knoppix, ...) geschützt. - die Scripte, die den Key benötigen, sourcen ebenfalls /root/irgendwas - serverseitig ist der Key mit command=... limitiert - siehe dazu man 8 sshd - Stichwort "command=". Das passende Kommando kannst Du, soweit nicht bekannt [1], einfach mit ps aux ermitteln, während der entsprechende Befehl läuft. Der verbleibende Risikofaktor ist, dass jemand ins laufende System eindringt und dort root-Rechte ergattert - er kann dann auch den SSH-Key nutzen. Dank Limitierung auf einen einzelnen Befehl ist aber auch dieses Risiko überschaubar. Diese Lösung ist immer noch besser als jeden Tag nachts um 3 das Passwort einzugeben, damit das Backup laufen kann. Ein verschlafener Admin ist schließlich auch ein Sicherheitsrisiko ;-)) Gruß Christian Boltz, handverlesene sig ;-) PS: Scripte auf Anfrage [1] rsync (bzw. seine Parameter) wäre dafür ein Beispiel, da die Parameter auf Client und Server unterschiedlich sind. --
PS.: Don't drink as root! Das kann man gar nicht oft genug sagen: "uups, rm -rf * statt rm -rf *~ in /etc", das war eine Meisterleistung nachts um 3 mit 2.6 auf dem Turm ;-)) [Volker Müller und Thomas Bendler in suse-linux]
![](https://seccdn.libravatar.org/avatar/7b33cb1e776e35b87edb8ef09f0c888f.jpg?s=120&d=mm&r=g)
Hallo, Am Sun, 10 Jul 2005, Christian Boltz schrieb:
Der verbleibende Risikofaktor ist, dass jemand ins laufende System eindringt und dort root-Rechte ergattert - er kann dann auch den SSH-Key nutzen. Dank Limitierung auf einen einzelnen Befehl ist aber auch dieses Risiko überschaubar.
Bzw.: wenn der Eindringling schon root-Rechte hat ist eh alles andere Makulatur...
Diese Lösung ist immer noch besser als jeden Tag nachts um 3 das Passwort einzugeben, damit das Backup laufen kann. Ein verschlafener Admin ist schließlich auch ein Sicherheitsrisiko ;-))
ACK. -dnh -- Support bacteria - it's the only culture some people have!
![](https://seccdn.libravatar.org/avatar/b58101fb24c64d0ff1d0f918e61cedd2.jpg?s=120&d=mm&r=g)
Hallo David, hallo Leute, Am Sonntag, 10. Juli 2005 03:33 schrieb David Haller:
Am Sun, 10 Jul 2005, Christian Boltz schrieb:
Der verbleibende Risikofaktor ist, dass jemand ins laufende System eindringt und dort root-Rechte ergattert - er kann dann auch den SSH-Key nutzen. Dank Limitierung auf einen einzelnen Befehl ist aber auch dieses Risiko überschaubar.
Bzw.: wenn der Eindringling schon root-Rechte hat ist eh alles andere Makulatur...
"Immerhin" bekommt er nicht noch den zweiten Rechner gratis dazu ;-) command="/bin/bash" sollte man in diesem Zusammenhang natürlich vermeiden... Gruß Christian Boltz -- vi-Befehle sind sogar relativ einfach zu merken. Wenn man einmal weiß, was dw db de d) d( d} d{ dd d^ d$ d0 dG sowie cw und yw machen, dann weiß man auch, was cb ce c) c( c} c{ cc c^ c$ c0 cG sowie yb ye y) y( y} y{ yy y^ y$ y0 yG machen. [Bernd Bordesser in suse-linux]
participants (6)
-
Andreas Feile
-
Andreas Schott
-
Christian Boltz
-
David Haller
-
Manfred Tremmel
-
Michael Behrens