Система контроля версий RCS на службе сисадмина Сергей Супрунов # ci -u MICRO # rcsdiff -u MICRO # co -l MICRO # ci -u MICRO root# rlog MICRO # rcsdiff -r1.1 -r1.2 MICRO # co -r1.1 MICRO # rcs -aserg MICRO $ rlog MICRO ----------------------------------------------------------------------------------------------------------------- Используйте преимущества файловой системы ZFS в Solaris Алексей Коробкин # zpool create zoopark c1t1d0 # zpool status zoopark # zpool create zerkalo3 mirror c1t1d0 c1t2d0 c1t3d0 # zpool status # zpool create veer raidz c1t1d0 c1t2d0 c1t3d0 c1t4d0 # zpool status veer # zpool create kombi raidz2 c1t1d0 c1t2d0 c1t3d0 c1t4d0 raidz2 c1t5d0 c1t6d0 c1t8d0 c1t9d0 # zpool status # zpool add kombi raidz2 c1t10d0 c1t11d0 c1t12d0 c1t15d0 # zpool status # zpool create -n lusterko mirror c1t1d0 c1t2d0 mirror c1t3d0 c1t4d0 mirror c1t5d0 c1t6d0 mirror c1t8d0 c1t9d0 spare c1t10d0 c1t11d0 # zpool create lusterko mirror c1t1d0 c1t2d0 mirror c1t3d0 c1t4d0 mirror c1t5d0 c1t6d0 mirror c1t8d0 c1t9d0 spare c1t10d0 c1t11d0 # zpool status # /usr/sbin/smcwebconsole start # useradd -P 'ZFS Storage Management', 'ZFS File System Management' zfsadmin # zpool import -D # zpool import -D -f rombik # zpool status # zpool status # zpool create zoo raidz c1t1d0 c1t2d0 c1t3d0 c1t4d0 # zfs list zoo # zfs create zoo/animals # zfs create zoo/fish # zfs list # zfs set compression=on zoo/fish # zfs get compression zoo/fish # zfs create zoo/fish/shark # zfs get compression zoo/fish/shark # zfs get quota zoo/fish # zfs set quota=5gb zoo/fish # zfs list -r zoo # zfs get all zoo/fish # zfs get -H used zoo/fish # zfs set mountpoint=/mnt/fish zoo/fish # zfs list -r zoo # zfs set mountpoint=legacy zoo/fish # zonecfg -z aquarium zonecfg:aquarium> add fs zonecfg:aquarium:fs> set type=zfs zonecfg:aquarium:fs> set special=zoo/fish zonecfg:aquarium:fs> set dir=/export/home/fish zonecfg:aquarium:fs> end # zonecfg -z aquarium zonecfg:aquarium> add dataset zonecfg:aquarium:dataset> set name=zoo/fish zonecfg:aquarium:dataset> end # zlogin aquarium # zpool list # zfs list -r # zfs create zoo/crocodile # zfs create zoo/fish/salmon # zfs list -r # zfs set sharenfs=on zoo/fish # share # touch /zoo/animals/snake # ls -v /zoo/animals/snake # chmod A+user:korobkin:read_data/write_data:allow snake # ls -v /zoo/animals/snake # ls -V /zoo/animals/snake ----------------------------------------------------------------------------------------------------------------- Устанавливаем eGroupware Сергей Яремчук $ cd /var/www $ sudo tar xjvf eGroupWare-1.2.106-2.tar.bz2 $ sudo tar xjvf eGroupWare-contrib-1.2.106-2.tar.bz2 $ sudo cat /etc/apache2/apache2.conf | grep User User www-data $ sudo chown -R www-data:www-data /var/www/egroupware $ sudo find egroupware -type d -exec chmod 550 {} \; $ sudo find egroupware -type f -exec chmod 440 {} \; $ sudo chmod -R 660 /var/www/egroupware/fudforum Order allow,deny Deny from all $ sudo apt-cache search php | grep mysql $ sudo apt-get install php5-mysql php5-mysqli php5-gd php5-imap $ sudo apt-get install pear $ sudo pear install Log $ sudo cp -v /tmp/header.inc.php /var/www/egroupware/ $ sudo chown -R www-data:www-data /var/www/egroupware/header.inc.php $ mysqladmin -u root -p create egroupware $ mysql -u root -p $ sudo mkdir /var/lib/egroupware/ $ sudo mkdir /var/lib/egroupware/default/ $ sudo mkdir /var/lib/egroupware/default/backup $ sudo mkdir /var/lib/egroupware/default/files $ sudo chown -R www-data:www-data /var/lib/egroupware ----------------------------------------------------------------------------------------------------------------- Корпоративный MAIL RELAY-сервис. E-mail + UNIX + Exchange Яков Коваленко FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl mydomain.ru smtp8:[XXX.XXX.XXX.XXX] mydomain.com smtp8:[XXX.XXX.XXX.XXX] To:mydomain.ru RELAY To:mydomain.com RELAY XXX.XXX.XXX.XXX RELAY POSSIBLE += $(shell test -f bitdomain && echo bitdomain.db) POSSIBLE += $(shell test -f uudomain && echo uudomain.db) POSSIBLE += $(shell test -f genericstable && echo genericstable.db) POSSIBLE += $(shell test -f userdb && echo userdb.db) CFFILES = sendmail.cf submit.cf all: ${CFFILES} ${POSSIBLE} virtusertable.db access.db ? domaintable.db mailertable.db userdb.db : userdb @makemap btree $@ < $< %.db : % @makemap hash $@ < $< %.cf : %.mc @if test -f /usr/share/sendmail-cf/m4/cf.m4; then \ mv -f $@ $@.bak; \ m4 $< > $@; \ fi; clean: rm -f *.db *~ perl -MCPAN -e shell install Net::Telnet #!/bin/sh SRC_DIR=/usr/local/src/sendmail mkdir -p ${SRC_DIR}/include cp `rpm -ql sendmail-devel | grep '\.h$’` ${SRC_DIR}/include/ mkdir -p ${SRC_DIR}/libmilter cp `rpm -ql sendmail-devel | grep '/lib’` ${SRC_DIR}/libmilter/ cd /root/.cpan/build/Sendmail-Milter-* perl Makefile.PL ${SRC_DIR}/ ${SRC_DIR}/ make make test make install INPUT_MAIL_FILTER(`mxcheck',`S=local:/var/run/mxcheck.socket') #!/usr/bin/perl # # Любой продукт можно бесконечно оптимизировать и развивать. # Скрипт должен послужить только отправной точкой. # Здесь описаны лишь основные моменты, но они работают. # Готовый продукт вы должны написать для себя сами. # # # Определяем переменные и модули # use Sendmail::Milter; use Net::Telnet (); use Socket; use AnyDBM_File; use strict; my ( $uncheck, $scriptname, $sendmail_cf, $error_code, $reply, $exchangeip, $debug, $time, $basedir, %validsbase, $validsbase, $TTL, $rcpt_to, $line, $smtp, $msg, $IP, $enh_error_code ); # # Директория, в которую кладется база # $basedir = "/etc/mail"; # # Название кэш-базы # $validsbase = "validmails"; # # Имя скрипта для поиска коннект-информации в sendmail.cf # $scriptname = "mxcheck"; # # Местоположение конфигурационного файла Sendmail # $sendmail_cf = "$basedir/sendmail.cf"; # # Адрес Exchange-сервера, у которого мы будем спрашивать существование адресов # $exchangeip = "10.1.0.10"; # # Адрес или подсеть, которая считается «своей», и почта от которой не проверяется # $uncheck = "10.1"; # # Режим отладки. Если поставить 1 – будет выдавать на STDOUT отладочные сообщения # $debug = 0; # # Время жизни адреса в кэш-базе. Секунды # $TTL = 86400; # # Определяем, какие SMTP-запросы нам нужно принять и обработать в скрипте. Здесь мы используем только # адрес получателя и информацию о подключении, хотя можно использовать и другие. Почитайте мануал, очень интересно my %mx_callbacks = ( 'connect' => \&connect_callback, 'envrcpt' => \&callback_rcptto, ); # # Инициализируем Milter # BEGIN: { @AnyDBM_File::ISA = qw(DB_File); my($conn) = Sendmail::Milter::auto_getconn("mxcheck", "$sendmail_cf"); print "Found connection info for milter: $conn\n"; if ($conn =~ /^local:(.+)$/) { my $unix_socket = $1; if (-e $unix_socket) { print "Attempting to unlink UNIX socket '$conn'\n"; if (unlink($unix_socket) == 0) { print "failed\n"; exit(); } print "successful\n"; } } if (not Sendmail::Milter::auto_setconn("$scriptname", "$sendmail_cf")) { print "Failed to detect connection information\n"; } elsif (not Sendmail::Milter::register("$scriptname", \%mx_callbacks, SMFI_CURR_ACTS)) { print "Failed to register callbacks for milter\n"; } else { print "Starting Sendmail::Milter$Sendmail::Milter::VERSION engine\n"; if (Sendmail::Milter::main()) { print "Successful exit from the Sendmail::Milter \n"; } else { print "Unsuccessful exit from the Sendmail::Milter \n"; } } } # # Получение информации о подключении # sub connect_callback { my $ctx = shift; my $hostname = shift; my $sockaddr_in = shift; my ($port, $iaddr); if ($debug == 1) { print "connect:\n"; print " + hostname: ‘$hostname’\n"; } # # Если к нам подключился сервер из доверенной подсети – никаких проверок # if (defined $sockaddr_in) { ($port, $iaddr) = sockaddr_in($sockaddr_in); $IP = inet_ntoa($iaddr); if ($IP =~ /^$uncheck/) { if ($debug == 1) { print "$IP in ALLOWED list.\n"; } return SMFIS_ACCEPT; } if ($debug == 1) { print " port: '$port'\n"; print " iaddr: '" . inet_ntoa($iaddr) . "'\n"; } } return SMFIS_CONTINUE; } # ## Проверка адреса в Exchange # sub callback_rcptto { # # Получаем информацию об адресате # my $time=time(); my $ctx = shift; my $rcpt_to = shift; $rcpt_to = lc($rcpt_to); $rcpt_to =~ s/\s*\<(.+?)\>\s*/$1/; my($href) = $ctx->getpriv(); $ctx->setpriv($href); # # Посмотрим, есть ли этот адрес в кэш-базе # unless (dbmopen(%validsbase,"$basedir/$validsbase",0600)) { return SMFIS_CONTINUE; if ($debug == 1) { print "Cannot open base \n"; } } if ($validsbase{$rcpt_to} ) { if ($debug == 1) { print "$rcpt_to FOUND in base \n"; } # # Похоже, что есть. Посмотрим TTL # $valid = ($time - $validsbase{$rcpt_to}); if ( $valid < $TTL) { if ($debug == 1) { print "$rcpt_to ALIVE TTL is ". ($valid - $TTL) ." time left - ". (($valid - $TTL) / 3600) ." hours \n"; } # # Есть и TTL не истек. Пропускаем # return SMFIS_CONTINUE; } else { delete $validsbase{$rcpt_to}; # # Есть, но TTL истек, удаляем из базы и продолжаем проверку # if ($debug == 1) { print "$rcpt_to DEAD. erasing \n"; } } } dbmclose(%validsbase); # # Если адрес не найден в кэш-базе или TTL истек – проверяем на Exchange # if ($debug == 1) { print "Go to exch \n"; } # # Запускаем подпрограмму проверки на Exchange # &check_exch($rcpt_to); $line =~ s/[\r\n]+$//; # # Возвращен ответ, начинающийся на 550, это означает, что нет такого адреса # if ($line =~ /^550/) { $error_code = '554'; $enh_error_code = '5.1.1'; $reply = 'Unroutable address'; $ctx->setreply($error_code, $enh_error_code, $reply); # # Пишем сообщение и отказываем в приеме # return SMFIS_REJECT; } # # Возвращен ответ, начинающийся на 250, это означает, что такой адрес есть # elsif ($line =~ /^250/) { $reply = $rcpt_to; $ctx->setreply('250', '2.1.5', $reply); # # Сохраняем его в кэш-базе на сутки # unless (dbmopen(%validsbase,"$basedir/$validsbase",0600)) { return SMFIS_CONTINUE; if ($debug == 1) { print "Cannot open basefile \n"; } } $validsbase{$rcpt_to} = $time; dbmclose(%validsbase); # # Принимаем почту # return SMFIS_CONTINUE; } # # Если ни то и ни другое – все равно принять, на всякий случай # else { return SMFIS_CONTINUE; } } # # Проверка на Exchange # sub check_exch { my($rcpt_to) = @_; if ($debug == 1) { print "connecting to $exchangeip as $rcpt_to \n"; } # # Устанавливаем Telnet-соединение с Exchange-сервером # $smtp = new Net::Telnet (Telnetmode => 0); $smtp->open(Host => $exchangeip, Port => 25, Errmode => "return"); if ($debug == 1) { print "Processing Telnet... please wait - $smtp \n"; } # # Обрабатываем возможные ошибки # $msg = $smtp->errmsg; if ($debug == 1) { print "Debug info - $msg \n"; } # # Если ошибка подключения – принимаем почту, на всякий случай # if ($msg) { if ($msg =~ /^problem/) { $line = 250; if ($debug == 1) { print "connecting to $exchangeip falled \n"; } return $line; exit; } else { $line = 250; if ($debug == 1) { print "Unknown error with Telnet session \n"; } return $line; exit; } } # # Получаем первое SMTP-сообщение от сервера # $line = $smtp->getline; if ($debug == 1) { print "$line \n"; } # # Отправляем HELO # $smtp->print("HELO mail.mydomain.ru"); $line = $smtp->getline; if ($debug == 1) { print "$line \n"; } # # Отправляем MAIL FROM:<> # $smtp->print("MAIL FROM:<>"); $line = $smtp->getline; if ($debug == 1) { print "$line \n"; } # # Отправляем RCPT TO с адресом получателя # $smtp->print("RCPT TO:<$rcpt_to>"); $line = $smtp->getline; if ($debug == 1) { print "$line \n"; } # # Отправляем QUIT # $smtp->print("QUIT"); # # Возвращаем результат – ответ сервера # return $line; } #!/bin/sh # Source function library. . /etc/rc.d/init.d/functions RETVAL=0 milter_path="/usr/local/milters/mxcheck" milter_name="mxcheck.pl" start() { # Start daemons. echo -n "Starting $milter_name: " $milter_path/$milter_name & sleep 2 RETVAL=$? echo return $RETVAL } stop() { # Stop daemons. echo -n "Shutdowning $milter_name: " killproc $milter_name RETVAL=$? echo PID=`ps axwu | grep $milter_name | grep perl | gawk '{print $2}'` if [ ! -z "${PID}" ]; then kill ${PID} 2>/dev/null sleep 1 fi return $RETVAL } # See how we were called case "$1" in start) start RETVAL=$? ;; stop) stop RETVAL=$? ;; restart) stop sleep 2 start RETVAL=$? ;; status) status $milter_name RETVAL=$? ;; *) echo "Usage: $0 { start | stop | restart | status }" exit 1 esac exit $RETVAL cd /etc/mail make /etc/init.d/sendmail restart /etc/init.d/mxcheck start ----------------------------------------------------------------------------------------------------------------- Большие гонки веб-серверов Сергей Супрунов # cd /usr/ports/www/<имя_веб-сервера> # make depends # make install PREFIX=/usr/local/<имя_веб-сервера> wwwtest# libexec/bozohttpd -b -c /var/cgi-bin -i 10.161.193.253 -I 80 -U www /var/www wwwtest# cd /var/www wwwtest# /usr/local/dfileserver/bin/dfileserver -port 80 & http stream tcp nowait root /usr/local/fnord/bin/fnord fnord /var/www wwwtest# sbin/gatling -n -u www -c /var/www & CGIhandler = /usr/bin/perl:cgi AddType application/x-httpd-cgi cgi server.document-root = "/var/www" cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl" ) /usr/local/mini_httpd/sbin/mini_httpd -D -c '**.cgi' wwwtest# cd /var/www wwwtest# /usr/local/mini_httpd/sbin/mini_httpd_wrapper & location / { root /var/www; index index.html index.htm; } AddType application/x-httpd-cgi cgi wwwtest# bin/shttpd -d /var/www -c cgi -p 80 -u www & Module modules/mod_env.so Module modules/mod_cgi.so ----------------------------------------------------------------------------------------------------------------- Решаем типичные проблемы безопасности домашних сетей Иван Максимов smbtree -N #!/usr/bin/perl -w # Путь к интерпретатору языка Perl print "Content-Type: text/html; charset=koi8-r\n\n"; # Сообщаем браузеру, что данный тип документа text/html # в кодировке koi8-r $tmp_f="/tmp/$$.txt"; # Создаем временный файл $smb=`smbtree -N 2>/dev/null | grep "[\\]" > $tmp_f`; # Выполним команду smbtree для создания дерева SMB-ресурсов # и командой grep отфильтруем содержимое вывода, # результат запишем во временный файл open (LIST,$tmp_f); while () { print $_; # Вывод содержимого временного файла print "

"; } close (LIST); SMB scan #!/usr/bin/perl -w print "Content-Type: text/html; charset=koi8-r\n\n"; use CGI; # Используем cgi для получения данных с html-формы $f=new CGI; $tmp_f="/tmp/$$"; $fn = $f->param('Fl'); # Получаем путь к локальному файлу (указанный в форме) $fn=~ s/.*[\/\\](.*)/$1/; # Получаем имя файла, «отсекая» локальный путь (вида c:\xxx) $fl_h = $f->upload('Fl'); # Используя метод upload, получаем указатель на временный # файл, созданного CGI.pm open (FILE,">$tmp_f"); # Создаем пустой файл while (<$fl_h>) { print FILE; } close (FILE); $vir=`clamscan $tmp_f | grep $tmp_f`; # Проверка файла антивирусом Clam $vir=~s/^.*[\\\:]//; print "$fn $vir"; # Вывод результатов

# Uncomment this option to enable logging. # LogFile must be writable for the user running daemon. # A full path is required. # Default: disabled LogFile /tmp/clamd.log # Log time with each message. # Default: disabled LogTime #!/usr/bin/perl -w print "Content-Type: text/html; charset=koi8-r\n\n"; $searchword="FOUND"; # Переменная с ключевым словом open (LIST,"/tmp/clamd.log"); while () { if (/\Q$searchword/i) # Если в данной строке есть совпадения с ключевым словом, # то выводим эту строку на экран { print $_; } print "

"; } close (LIST); cat /tmp/clamd.log | grep FOUND Вирусная активность #!/usr/bin/perl –w print "Content-Type: text/html; charset=koi8-r\n\n"; $str = $ENV{'REMOTE_ADDR'}; # Записываем переменную среды окружения REMOTE_ADDR в переменную $str $tmp_f="/tmp/$$"; $scan=`nmap -sT $str > $tmp_f`; # Сканируем tcp порты удаленной машины, результат запишем во временный файл open (LIST,$tmp_f); while () { print $_; print "

"; } close (LIST); ----------------------------------------------------------------------------------------------------------------- Auditor Collection: проверяем безопасность вашей сети Андрей Бирюков auditor# dnswalk -r webserver.ru. ifconfig tun0 10.0.0.1 up insmod netlink_dev insmod ethertap mknod /dev/tun0 c 36 16 nstxcd zone.server.com nstxd zone.server.com 123.45.67.89 [root@user -> ~]$ traceroute 10.0.0.1 [root@user -> ~]$ arp [root@hacker -> ~]$ arpspoof -t 10.0.0.171 10.0.0.1 [root@user~]$ arp [root@user]$ traceroute 10.0.0.1 ----------------------------------------------------------------------------------------------------------------- Ruby – язык завтрашнего дня Владимир Овсянников %port install ruby # gem install vcard -y --remote # gem --help arr1 = Array.new arr2 = [] hash1 = Hash.new hash2 = {} 1.class.class obj.attr = 5 var = obj.attr class MyFirstClass # создаём класс с именем MyFirstClass attr_reader :first # заменится на def first; @first; end attr_writer :second # заменится на def first=(v); @first = v; end attr_accessor :tre # attr_reader + attr_writer def initialize(attrs) # конструктор @first = attrs[:first] @second = attrs[:second] @tre = attrs[:tre] @end_attr = attrs[:end] end def end=(oth) # метод end = будет приравнивать @end_attr половине аргумента @end_attr = oth/2.to_f # .to_f – принудительное приведение к Float end def end # метод end будет возвращать квадрат @end_attr @end_attr**2 # методы возвращают последнее вычисленное значение или аргумент return end end obj = MyFirstClass.new(:first=>'FIRST', :second=>2, :tre=>'ТРИ', :end=>5) obj.first # => FIRST obj.first = 'ПЕРВЫЙ' # => ОШИБКА: метод first=() не определён obj.second = 'ДВА' # => ДВА obj.second # => ОШИБКА: метод second() не определён obj.tre = obj.tre*3 # => ТРИТРИТРИ obj.end # => 25 obj.end = 11 # => 11 obj.end # => 30.25 File.open('/tmp/tempfile', 'w') do |tmp| tmp.write 'Bla-bla-bla' end for(i=0; arr[i]; i++){ printf("%d\n", arr[i]) } arr.each{|el| puts el} rez = [3,4,5,6,7,8,9,11,12,15,17,21,22,25,30].find_all{|el| (el%3).zero?} puts rez rez = [3,4,5,6,7,8,9,11,12,15,17,21,22,25,30].map{|el| el*2} rez = [3,4,5,6,7,8,9,11,12,15,17,21,22,25,30].partition{|el| el>12} a = [1,2,3,4,5,6,7,8,9,0] a[-3..-1] # => [8, 9, 0] str = 'String' str[1] # => 116 str[1].chr # => 't' print 5[0], 5[1], 5[2] # => 101 5.to_s(2) # => '101' 8.to_s(7) # => '11' 59.to_s(27) # => '25' 100.to_s(36) # => '2s' ----------------------------------------------------------------------------------------------------------------- Обзор Ruby on Rails Владимир Овсянников # gem install rails -y class User < ActiveRecord::Base validates_confirmation_of :password, :message=>'Пароли не совпадают' validates_length_of:password, :in=>4..10, :too_long=>'Пароль слишком длинный', :too_short=>'Пароль слишком короткий', :on=>:create end (10.weeks + 1.day – 4.minutes).ago [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].in_groups_of(3){|el| p el} => [1, 2, 3] => [4, 5, 6] => [7, 8, 9] => [10, nil, nil] rails <имя директории> -----------------------------------------------------------------------------------------------------------------