Hpricot 0.8.1 on ruby 1.8.5

Installing latest Hpricot on ruby 1.8.5 fails due missing macro RARRAYPTR:

[root@silver ~]# gem install hpricot
Building native extensions.  This could take a while...
ERROR:  Error installing hpricot:
        ERROR: Failed to build gem native extension.
 
/usr/bin/ruby extconf.rb
checking for main() in -lc... yes
creating Makefile
 
make
gcc -I. -I. -I/usr/lib64/ruby/1.8/x86_64-linux -I.  -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -Wall -fno-strict-aliasing  -fPIC  -c hpricot_css.c
hpricot_css.rl: In function ‘hpricot_css’:
hpricot_css.rl:106: warning: implicit declaration of function ‘RSTRING_PTR’
hpricot_css.rl:106: warning: assignment makes pointer from integer without a cast
hpricot_css.rl:107: warning: implicit declaration of function ‘RSTRING_LEN’
hpricot_css.rl:82: warning: field precision should have type ‘int’, but argument 5 has type ‘long int’
hpricot_css.c:295: warning: comparison is always true due to limited range of data type
[...]
hpricot_css.c:3403: warning: comparison between pointer and integer
hpricot_css.c:3403: warning: ‘eof’ is used uninitialized in this function
hpricot_css.rl:92: warning: ‘aps’ may be used uninitialized in this function
gcc -I. -I. -I/usr/lib64/ruby/1.8/x86_64-linux -I.  -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -Wall -fno-strict-aliasing  -fPIC  -c hpricot_scan.c
hpricot_scan.rl: In function ‘our_rb_hash_lookup’:
hpricot_scan.rl:169: warning: implicit declaration of function ‘st_lookup’
hpricot_scan.rl: In function ‘make_hpricot_struct’:
hpricot_scan.rl:693: warning: implicit declaration of function ‘RARRAYPTR’
hpricot_scan.rl:693: error: subscripted value is neither array nor pointer
make: *** [hpricot_scan.o] Error 1
 
 
Gem files will remain installed in /usr/lib64/ruby/gems/1.8/gems/hpricot-0.8.1 for inspection.
Results logged to /usr/lib64/ruby/gems/1.8/gems/hpricot-0.8.1/ext/hpricot_scan/gem_make.out

Searching with google I’ve found this post that explains equivalence of the RARRAYPTR(v) is RARRAY(v)->ptr . We’ll need to define RARRAYPTR macro.

We’ll replace occurences of #include <ruby.h> with #include “ruby_macros.h” and create an include file ruby_macros.h with the following content:

#ifndef __RUBY_MACROS__
#define __RUBY_MACROS__
 
#include <ruby.h>
 
#ifndef RARRAYPTR
#  define RARRAYPTR(v) RARRAY(v)->ptr
#endif
#endif
[root@silver ~]# cd /usr/lib64/ruby/gems/1.8/gems/hpricot-0.8.1/ext/hpricot_scan 
[root@silver hpricot_scan]# sed -i 's,#include <ruby.h>,#include "ruby_macros.h",g' *.h *.c *.rl
[root@silver hpricot_scan]# touch ruby_macros.h
[root@silver hpricot_scan]# vi ruby_macros.h

The next step is to recreate the gem and install it:

[root@silver ~]# cd /usr/lib64/ruby/gems/1.8/gems/hpricot-0.8.1
[root@silver hpricot-0.8.1]# rake package
(in /usr/lib64/ruby/gems/1.8/gems/hpricot-0.8.1)
fatal: Not a git repository
rm -r ext/fast_xs/Makefile
rm -r ext/hpricot_scan/Makefile
rm -r .config
rm -r pkg
rm -r hpricot-0.8.1-mswin32
rm -r hpricot-0.8.1-jruby
Using ragel version: 6.3, location: /usr/bin/ragel
cd ext/hpricot_scan ; ragel hpricot_scan.rl -G2 -o hpricot_scan.c && ragel hpricot_css.rl -G2 -o hpricot_css.c
mkdir -p pkg
mkdir -p pkg/hpricot-0.8.1
rm -f pkg/hpricot-0.8.1/CHANGELOG
[...]
cd pkg
tar zcvf hpricot-0.8.1.tgz hpricot-0.8.1
hpricot-0.8.1/
hpricot-0.8.1/Rakefile
[...]
hpricot-0.8.1/ext/fast_xs/fast_xs.c
cd -
WARNING:  description and summary are identical
  Successfully built RubyGem
  Name: hpricot
  Version: 0.8.1
  File: hpricot-0.8.1.gem
mv hpricot-0.8.1.gem pkg/hpricot-0.8.1.gem
[root@silver hpricot-0.8.1]# gem install pkg/hpricot-0.8.1.gem
Building native extensions.  This could take a while...
Successfully installed hpricot-0.8.1
1 gem installed
Installing ri documentation for hpricot-0.8.1...
Installing RDoc documentation for hpricot-0.8.1...
 
[root@silver hpricot_scan]# gem list -l | grep hpricot
hpricot (0.8.1, 0.7, 0.6.164, 0.6.161, 0.6)

Missing host to link to! Please provide :host parameter or set default_url_options[:host]

Problem:
Missing host to link to! Please provide :host parameter or set default_url_options[:host] when sending emails.

Solution:
You can pass host parameter to url functions, but it’s cleaner to configure it with a before_filter globally in your application_controller.rb:

  # application_controller.rb
  before_filter :mailer_set_url_options
 
  ...
 
  def mailer_set_url_options
    ActionMailer::Base.default_url_options[:host] = request.host_with_port
  end

Simple script to convert ERB files to Haml

A simple script to convert .erb files from current directory to .haml :

#!/usr/bin/ruby
 
Dir.glob("*.html.erb").each do |erbname|
  hamlname = erbname.gsub(".html.erb", ".html.haml")
  system "/usr/bin/html2haml #{erbname} #{hamlname}"
end

File uploads in import scripts

Simulating file uploads in your scripts or from console can be done really simple using Rail’s ActionController::TestUploadedFile from action_pack.

Example code:

require 'action_controller/test_process'
 
class ImportExternalData
 ...
  def import_data
    ...
    page.attachments << PageAttachment.new(
      :uploaded_data => fake_file_upload(filename, mime_type),
      :title => title,
      :description => description)
    ...
  end
 
 
protected
  def fake_file_upload(path, mime_type = nil, binary = false)
    ActionController::TestUploadedFile.new(
      path,
      mime_type,
      binary
    )
  end
end

Excerpt from ActionController::TestUploadedFile’s comments:

Essentially generates a modified Tempfile object similar to the object
you’d get from the standard library CGI module in a multipart
request. This means you can use an ActionController::TestUploadedFile
object in the params of a test request in order to simulate
a file upload.

4PSA SpamGuardian, Plesk 9 and syntax error near unexpected token ‘>>’

After Plesk upgrade we had to upgrade SpamGuardian too, but the scripts from the rpm contains syntax errors and the package can’t be installed:

[root@andromeda tmp]# rpm -Uvh --force 4psa-sguardian-psa9-3.5.0-090305.01.rhel5.i386.rpm
Preparing... ########################################### [100%]
1:4psa-sguardian-psa9 ########################################### [100%]
/var/tmp/rpm-tmp.42581: line 315: syntax error near unexpected token `>>'
/var/tmp/rpm-tmp.42581: line 315: ` echo >> >> /etc/sguardian/sguardian.conf'

The solution is to install the rpm without running PRE/POST install scripts:

[root@andromeda tmp]# rpm -Uvh --force --noscripts 4psa-sguardian-psa9-3.5.0-090305.01.rhel5.i386.rpm

Then we can extract scripts with mc (midnight commander), or rpm -qp –scripts and run them separately after correcting the syntax errors (comment lines containing “>> >>” string):

[root@andromeda scripts]# sh PREIN 
 
[...]
 
[root@andromeda scripts]# sh POSTIN 
===> Installing 4PSA Spam Guardian
 
===> Regenerating Mail files
==> Checking for: mailsrv_conf_init... ok
==> Checking for: mail_mailbox_restore... ok
==> Checking for: mailsrv_entities_dump... ok
==> Checking for: mail_auth_dump... ok
==> Checking for: mailman_lists_dump... ok
==> Checking for: mail_responder_restore... ok
==> Checking for: mail_drweb_restore... ok
==> Checking for: mail_kav_restore... not exsists
==> Checking for: mail_spf_restore... ok
==> Checking for: mail_dk_restore... ok
Success
 
[...]

Munpack - File size limit exceeded

We alreay know how to extract files from Plesk backup with mpack, but if you do receive “File size limit exceeded” error, it can be from the following reasons:

  • Your file system doesn’t have LFS (large file support) support
  • OS limits (limits on the system resources imposed by your administrator)
  • mpack is not compiled with LFS

Check that your filesystem supports files bigger than 2GB (create a test file with “dd” command).

[vitalie@silver ~]$ dd if=/dev/zero of=test.bin bs=1G count=3 # create 3GB file

Then check your file size limits with ulimit command:

[vitalie@silver ~]$ ulimit -a | grep '^file size'
file size               (blocks, -f) unlimited

You can adjust limits from /etc/security/limits.conf, read file comments on how to do it, or read this article:
http://www.cyberciti.biz/faq/file-size-limit-exceeded-error-under-linux-and-solution/

If none above limits you, then the problems comes from mpack, it doesn’t have suport for large files (>2GB).

The guys from the Plesk recommends to grep the backup file, to find begin and end of the file in archive:
http://kb.parallels.com/en/1757

This solutions is not appropriate for large backup files, we’ll just recompile mpack to support large files.

Grab mpack’s RPM source from the Dag’s repository
http://dag.wieers.com/rpm/packages/mpack/mpack-1.6-2.rf.src.rpm

install it:

[vitalie@silver ~]$ rpm -ivh mpack-1.6-2.rf.src.rpm
[...]

Then modify mpack.spec and add the following code after “%build”:

export CFLAGS="-D_FILE_OFFSET_BITS=64"

Then rebuild the package and install it:

[vitalie@silver ~] rpm -ba mpack.spec
[...]
[vitalie@silver ~] rpm -Uvh --force mpack-1.6-3.rf.i386.rpm
[...]

References:

This site may harm your computer

Today the website of one of the clients was blacklisted by Google by containing malicious software that downloads and installs without user’s consent. Google displayed “This site may harm your computer” under website in the results page.

Analyzing site’s sources we found obfuscated JavaScript code inserted near body, html tags in .html, .php, .tpl files and a .htaccess file with following content:

RewriteEngine On
RewriteCond %{HTTP_REFERER} .*google.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*aol.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*msn.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*yahoo.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*yandex.*$ [NC,OR]^M
RewriteCond %{HTTP_REFERER} .*rambler.*$ [NC,OR]^M
RewriteCond %{HTTP_REFERER} .*ya.*$ [NC]
RewriteRule .* http://real-antispyware.info/0/go.php?sid=2 [R,L]

Hmm, visitors from search engines were redirected to real-antispyware.info. This website is a scam that shows some JavaScript animation fulling the user with a message that his computer is infected and prompts him to download and install a fake AntiVirus.

Analyzing IP addresses from ftp logs we found connections from Russia and China that altered client’s website. Somehow they got user’s ftp password (it can be done in so many ways: weak password, traffic sniffing, virus, keylogger, trojan, …) and they altered website files.

You can use this simple Ruby script to analyze your ftp logs. By default it is configured for a Plesk server, and it will show suspicious lines (change IGNORE variables to fit your needs). You may need to install rubygems and geoip gem.

#!/usr/bin/ruby
 
require 'rubygems'
require 'geoip'
require 'zlib'
 
# hide logs from these countries
# Example: RO US
IGNORE_COUNTRIES = %w{RO US}
# free geoip database is not 100% accurate
# we may need to ignore a few ip addresses
IGNORE_IP = %w{127.0.0.1 127.0.0.2}
 
files = Dir.glob("/usr/local/psa/var/log/xferlog*")
geoip = GeoIP.new('/var/lib/GeoIP/GeoIP.dat')
 
def ip2country(geoip, ip)
  country = geoip.country(ip)[3]
end
 
ip_list = []
files.each do |filename|
  puts ""
  puts "Processing #{filename} ..."
 
  File.open(filename) do |f|
    input = f
    input = Zlib::GzipReader.new(f) if File.extname(filename) == ".gz"
 
    while line = input.gets do
      ip = line.split(/\s+/)[6]
 
      unless ip_list.include? ip
        country = ip2country(geoip, ip)
        unless IGNORE_COUNTRIES.include? country.upcase or IGNORE_IP.include? ip
          puts " [#{country} : #{ip}] => #{line}"
        end
        ip_list << ip
      end
   end
  end
end

Steps that needs to followed:

  1. Change FTP password
  2. Upload a clean copy from the backups of the website
  3. Submit the website in the Webmaster’s Tools for reconsideration
  4. Audit your company security: computers, firewalls, antiviruses, software, …

You may find useful diagnose tool from the Google (replace example.com with your domain):

http://www.google.com/safebrowsing/diagnostic?site=http://example.com

Plesk alternative port for relaying

SMTP stands for Simple Mail Transfer Protocol, it was designed a long time ago when the Internet was a peaceful place. Today we are facing new challenges, so there should be new solutions.

One of the problem is SPAM messages, spammers are keeping to bombard us everyday with junk mails. We did invented black/white list to protect us from them.

If your clients are connecting from an ip address that’s listed in RBL lists (it’s not uncommon for ISPs that are using dynamic ip addresses) they can’t send messages through your server if you are using RBLs.

Disabling RBLs checks it’s not an option, we’ll configure an alternative port for relaying on port 1025 for the clients listed in RBLs.

You can just copy your smtp_psa file and customize it:

cd /etc/xinetd.d/
cp smtp_psa smtp_alt_psa
vim smtp_alt_psa

You need to change service name from smtp to smtp-alt and remove rblsmptd command and it’s -r parameters, finally it should something like this:

# /etc/xinetd.d/smtp_alt_psa
service smtp-alt
{
        socket_type     = stream
        protocol        = tcp
        wait            = no
        disable         = no
        user            = root
        instances       = UNLIMITED
        server          = /var/qmail/bin/tcp-env
        server_args     = -Rt0 /var/qmail/bin/relaylock /var/qmail/bin/qmail-smtpd /var/qmail/bin/smtp_auth /var/qmail/bin/true /var/qmail/bin/cmd5checkpw /var/qmail/bin/true
}

Append the new service to /etc/services:

smtp-alt        1025/tcp        
smtp-alt        1025/udp

And restart the xinetd service:

[root@sirius xinetd.d]# /etc/init.d/xinetd restart
Stopping xinetd:                                           [  OK  ]
Starting xinetd:                                           [  OK  ]

Verify your configuration with telnet command:

[root@sirius xinetd.d]# telnet localhost 1025
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
220 sirius.example.net ESMTP
 
# Ctr+] and quit to exit telnet

Now, instruct your clients to change port in SMTP settings from 25 to 1025, they will be able to send mails through your server even you are using RBL lists.

Install FreeImage on CentOS/RHEL 5

FreeImage is not yet available as RPM on CentOS/RHEL, so we’ll create one.

Before installing required libraries by FreeImage, configure yum to use Dag’s repositories, see this post how it can be done.

Learn how to setup your account to build RPMS as non-privileged user:
http://www.cherpec.com/2009/01/build-rpms-as-simple-user/

[root@lynx ~] yum install libjpeg-devel libpng-devel libtiff-devel libmng-devel openexr-devel zlib-devel
 
[...]

Next, download the following files from FreeImage’s website and put them in your SOURCES directory:

And download freeimage.spec and place it in the SPECS directory.

Now, you are ready to build FreeImage, switch to SPECS directory and build FreeImage package:

[joe@lynx SPECS]$ rpmbuild -ba freeimage.spec
 
[...]
 
+ umask 022
+ cd /home/joe/rpmbuild/BUILD
+ cd FreeImage
+ DOCDIR=/home/joe/rpmbuild/tmp/freeimage-3.11.0-buildroot/usr/share/doc/freeimage-3.11.0
+ export DOCDIR
+ rm -rf /home/joe/rpmbuild/tmp/freeimage-3.11.0-buildroot/usr/share/doc/freeimage-3.11.0
+ /bin/mkdir -p /home/joe/rpmbuild/tmp/freeimage-3.11.0-buildroot/usr/share/doc/freeimage-3.11.0
+ cp -pr FreeImage3110.pdf /home/joe/rpmbuild/tmp/freeimage-3.11.0-buildroot/usr/share/doc/freeimage-3.11.0
+ exit 0
Provides: libfreeimage.so.3()(64bit)
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) libc.so.6(GLIBC_2.3)(64bit) libgcc_s.so.1()(64bit) libgcc_s.so.1(GCC_3.0)(64bit) libstdc++.so.6()(64bit) libstdc++.so.
Processing files: freeimage-debuginfo-3.11.0-1
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/joe/rpmbuild/tmp/freeimage-3.11.0-buildroot
Wrote: /home/joe/rpmbuild/SRPMS/freeimage-3.11.0-1.src.rpm
Wrote: /home/joe/rpmbuild/RPMS/x86_64/freeimage-3.11.0-1.x86_64.rpm
Wrote: /home/joe/rpmbuild/RPMS/x86_64/freeimage-debuginfo-3.11.0-1.x86_64.rpm

Build RPMs as simple user

It’s not recommended to build your RPMS as root. You can build them as simple user, to accomplish this, you need to create a file called .rpmmacros in your home directory (we’ll assume that your user name is joe and your home directory is /home/joe):

# ~/.rpmmacros
%_topdir /home/joe/rpmbuild
%_tmppath %{_topdir}/tmp

Then create required directories:

[joe@lynx ~]$ mkdir -p ~/rpmbuild/{BUILD,RPMS/{noarch,i386,i586,i686,x86_64},SOURCES,SPECS,SRPMS,tmp}

You are ready to build your RPMS as simple user.