Monday, December 26, 2011

SMS emulator with original pads

I have always liked the SEGA consoles (and games) more than the Nintendo stuff. So I decided to install an emulator for my old SEGA Master System games and build an adapter to play the SMS games with the original gamepad on my old 650MHz Notebook. The reason that I play the games on my old notebook is simple: I have no new workstation or notebook with a parallel port anymore. Before you start make sure that your parallel port supports EPP:

# dmesg | grep parport
...
parport0: PC-style at 0x378, irq 7 [PCSPP,TRISTATE,EPP]
...

Then build an adapter like the following schematics:


The following image is the adapter I have build (opened):


If you have setup your adapter then remove the lp module first:

# rmmod lp

Next load the db9 module:

# modprobe db9 dev=0,2

Check the logs:

# dmesg
...
input: Multisystem joystick (2 fire) as /devices/virtual/input/input7

And check that the input device was created:

# ls /dev/input/js*
/dev/input/js0

Then do a simple check that the gamepad works. Execute cat on the js device and press any button on your gamepad. You should see some weird characters on your screen:

# cat /dev/input/js0
...

The parameters for the db9 module are easy: the first 0 is for the parallel port you want to use, in my case I use the first and only port on my notebook. If you want to use the second port then type 1 etc. The second digit defines the gamepad to use, here is a short list:

0 None
1 Multisystem 1-button joystick
2 Multisystem 2-button joystick
...

The SEGA Master System gamepads are Multisystem gamepads with 2 buttons, so 2 is the the appropiate choice here. Next you need an emulator for you roms. I like to use mednafen, it supports a lot of other consoles to. First get the source eg. from http://sourceforge.net/projects/mednafen/files/Mednafen/0.8.D.3/mednafen-0.8.D.3.tar.bz2/download. Then move the tar package to /usr/src and extract it:

# mv mednafen-0.8.D.3.tar.bz2 /usr/src
# cd /usr/src
# tar xf mednafen-0.8.D.3.tar.bz2

Then change into the new directory and configure the source:

# cd mednafen
# ./configure --prefix=/usr/games
...

Compile the sources and install the binaries:

# make
...
# make install
...

With the db9 driver loaded and mednafen installed you should be able to play a good old SEGA Master System rom:

$ /usr/games/bin/mednafen ~/custom_rom.sms

You can configure the first pad by pressing ALT+SHIFT+1 simultanously. Just follow the questions on the bottom of the screen.

Links:
Documentation how to set up an adapter and which gamepads are supported:
http://www.mjmwired.net/kernel/Documentation/input/joystick-parport.txt Print Friendly and PDF

Sunday, December 25, 2011

Creating an LDAP based address book

Imagine you have a small company with one manager, his secretary and a couple of workers. Each of these guys needs their own space to store some contacts, eg. the manager needs to store some manager contacts, the secretary needs to store some secretary contacts and workers need to store some contact about sales guys. At this point you need to create an organizational unit for your address book with more organizational units in it for all workers etc:

# vi addressbook.ldif
dn: ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: addressbook

dn: ou=manager,ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: manager

dn: ou=secretary,ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: secretary

dn: ou=worker1,ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: worker1

dn: ou=worker2,ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: worker2

Then add it to your LDAP:

# ldapadd -x -W -D 'cn=ldapadmin,dc=example,dc=com' -f addressbook.ldif
...

The above ldif file will create the address book ou with one manger, one secretary and two workers. Now you need to configure the ACL which is a little more tricky. Each manager, secretary and worker should only be able to read and write within their own address book. The manager should not be able to read the address book of one of his workers etc. Here is a sample how I solved it:

# cd /etc/openldap/
# vi acl.conf
...
access to dn.regex="^ou=([^,]+),ou=addressbook,dc=example,dc=com$"
  by dn.regex="^uid=$1,ou=users,dc=example,dc=com$$" write
  by * none

access to dn.children="ou=addressbook,dc=example,dc=com"
  by * write

access to dn.base="ou=addressbook,dc=example,dc=com"
  by * write
...

The ACL are read from the bottom to the top. First give write access to everybody to the complete address book. The second ACL dn.children is needed to create non existing contacts. With the first ACL you are only allowed to modify already existing contacts but not be able to create them. The third ACL defines that only the current authenticated user may write into his address book. Eg. the manager is logged in with uid manager stored in uid=manager,ou=users,dc=example,dc=com. Then he tries to change or add a contact. In this case he needs to authenticate to the LDAP server again and uses his uid=manager,ou=users,dc=example,dc=com again. The regex will check the login name and makes sure that only uid=manager,ou=users,dc=example,dc=com may write to ou=manager,ou=addressbook,dc=example,dc=com.
But sometimes you need some shared space that everybody can use. In this case you need some kind of an public address book too. The next ldif file will create such a address book under ou=addressbook,dc=example,dc=com:

# vi public.ldif
dn: ou=public,ou=addressbook,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: public

Then add it to your LDAP again:

# ldapadd -x -W -D 'cn=ldapadmin,dc=example,dc=com' -f public.ldif
...

But I don't want that everybody has write access to the public address book. Only the secretary shall be able to write into the public address book, all others (including the manager) shall have read access only. If they want to change or add a contact then they have to go over the secretary. In this case you need to change the ACL one more time:

# cd /etc/openldap/
# vi acl.conf
...
access to dn.base="ou=public,ou=addressbook,dc=example,dc=com"
  by dn.exact="uid=secretary,ou=users,dc=example,dc=com" write
  by * read

access to dn.regex="^ou=([^,]+),ou=addressbook,dc=example,dc=com$"
  by dn.regex="^uid=$1,ou=users,dc=example,dc=com$$" write
  by * none

access to dn.children="ou=addressbook,dc=example,dc=com"
  by * write

access to dn.base="ou=addressbook,dc=example,dc=com"
  by * write
...

The ACL are read from the bottom to the top. The first three ACL are the same as above. The fourth ACL will give write access to the secretarys account, all other have only read access. That's all and all to easy again. If you configure some application (like kaddressbook/kontact) against it make sure that the user uses his own uid and that the DN maps against the appropiate address book of the user.
If you have trouble with the ACL then run the slapd in foreground with debug level 128, eg:

# /usr/libexec/slapd -h ldap://192.168.1.73:389 -d 128
...
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
...

Then search/add/modify any contact to see what happens.
Print Friendly and PDF

Friday, December 23, 2011

LDAP for Solaris 10

With this article I want you to show how to set up OpenLDAP for Solaris 10. I have here a small Sun Fire V100 with 2GB running - perfect for playing around. Using Solaris as a LDAP client is a little bit strange first, but with the time you will enjoy it. Solaris comes with a tool called ldapclient to initiate a Solaris host as a LDAP client. There is a daemon called ldap_cachemgr which will be started when you initialize Solaris as a LDAP client and it runs all the time. The LDAP server has to provide at least on special profile for Solaris. To provide a profile for Solaris you have to add two extra schema files which don't come with OpenLDAP but can be easily downloaded. As mentioned, I'm going to show you how to setup OpenLDAP as a LDAP server for Solaris. The server itself will act as a client too. Before you can use OpenLDAP with Solaris you have to download Berkeley DB from http://www.oracle.com (just like nearly every DB these days). I am using nearly the same releases used in Slackware 13.37, they just work. Also the compile instructions are very similar and highly inspired by the Slackware build scripts. After you have downloaded the Berkeley DB, copy it to /usr/src and extract it:

# cd /usr/src
# gzip -dc db-4.4.20.tar.gz | tar xf -

Then go to the new directory and create a build directory where you can compile the source:

# cd /usr/src/db-4.4.20
# mkdir build && cd build

Export the following PATH variable to include most compiler tools in your path and compile the DB:

# export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/sfw/bin:/usr/sfw/sbin:/usr/ccs/bin
# ../dist/configure --prefix=/opt/db/4.4.20 --enable-shared --enable-rpc --enable-cxx --enable-compat185
...
# make && make install
...

The binaries and libraries are now available in /opt/db/4.4.20. Go to /opt/db and create a symbolic link from 4.4.20 to latest:

# cd /opt/db/
# ln -s 4.4.20 latest

So far so good, the DB is compiled. Next you need OpenLDAP it self. Download it and extract it:

# cd /usr/src
# wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.26.tgz
...
# gzip -dc openldap-2.4.26.tgz | tar xf -

Go to the new directory, export all variables and compile the source:

# cd openldap-2.4.26
# export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/sfw/bin:/usr/sfw/sbin:/usr/ccs/bin
# export CPPFLAGS="-I/opt/db/latest/include/"
# export LD_LIBRARY_PATH=/opt/db/4.4.20/lib:$LD_LIBRARY_PATH
# ./configure --prefix=/opt/openldap/2.4.26 --with-cyrus-sasl --with-tls --enable-crypt --with-threads --enable-debug --enable-syslog --enable-dynamic --enable-bdb --enable-local --enable-proctitle --disable-static --enable-shared --enable-slapd
...
# make
...
# make install
...

After the compile has finished, go to /opt/openldap and create a symbolic link to 2.4.26:

# cd /opt/openldap
# ln -s 2.4.26 latest

Next configure your LDAP. Go to the LDAP configuration file, make a backup of the original configuration file and create a new one:

# cd /opt/openldap/latest/etc/openldap
# mv slapd.conf slapd.conf.orig
# vi slapd.conf
# SCHEMES
include         /opt/openldap/latest/etc/openldap/schema/core.schema
include         /opt/openldap/latest/etc/openldap/schema/cosine.schema
include         /opt/openldap/latest/etc/openldap/schema/inetorgperson.schema
include         /opt/openldap/latest/etc/openldap/schema/nis.schema

# ACL
include         /opt/openldap/latest/etc/openldap/acl.conf

# DATABASE
database        bdb
directory       /var/lib/ldap/example.com

# GENERIC
pidfile         /var/run/slapd.pid
argsfile        /var/run/slapd.args
suffix          "dc=example,dc=com"
rootdn          "cn=ldapadmin,dc=example,dc=com"
rootpw          {SSHA}tJMqZ3lE22tS6ygBbexB9yiCT0ebfSXf
password-hash   {CRYPT}
loglevel        256
sizelimit       unlimited

The section SCHEMES will load some definitions for the informations you want to provide. There are various schemes available depending on the informations you want to provide in your environment. For a proper use with Solaris we need to expand them later.
The section ACL will load the access control list. You can put it directly into the configuration file or put in a seperate file. I like to store my ACL's in a seperate file:

# vi /opt/openldap/latest/etc/openldap/acl.conf
access to attrs=userPassword
    by dn.base="uid=proxy,dc=example,dc=com" read
    by self write
    by * auth

access to dn.base=""
    by * read

access to * by self write
    by * read

They are read from the bottom to the top, at first everybody gets read access to everything, but they are getting more granular when it's about passwords at the top. With my example DIT (later) I will create a simple security object as proxy user. This is needed to read the passwords for authentication under Solaris.
The section DATABASE defines the database and where it will be stored, in this case a simple BDB. When you start slapd (the OpenLDAP daemon) then you may notice a message like this in the logs:

# cat /var/log/ldap.log
...
bdb_db_open: warning - no DB_CONFIG file found in directory /var/lib/ldap/example.com: (2). Expect poor performance for suffix "dc=example,dc=com".
...

You can get rid of this message when you create the DB_CONFIG file. Just copy the one found in the openldap package:

# mkdir -p /var/lib/ldap/example.com
# cp /opt/openldap/latest/var/openldap-data/DB_CONFIG.example /var/lib/ldap/example.com/DB_CONFIG

The last section is the GENERIC section. It holds some informations for the LDAP daemon (slapd) itself like the pidfile, the suffix (eg. your domain) etc. For the above defined pid file you have to create a directory:

# mkdir /var/run/slapd/

The sections above are not for real - I just like to use them to make the configuration file easy to understand.
Very important is the rootpw. The rootpw has to be generated by slappasswd:

# /opt/openldap/latest/sbin/slappasswd
New password:
Re-enter new password:
{SSHA}tJMqZ3lE22tS6ygBbexB9yiCT0ebfSXf

Put the complete generated string into the configuration file slapd.conf including the start of the string {SSHA}.
Before you start slapd you should configure syslog for logging. Add the following lines to your /etc/syslog.conf. Important note: the spaces between local4.* and /var/log/ldap.log aren't spaces - they have to be tabs! Otherwise your syslog daemon not log correct:

# vi /etc/syslog.conf
...
# LDAP
local4.debug <- tab -> ifdef(`LOGHOST', /var/log/ldap.log, @loghost)
...

slapd will log on local4, with the loglevel 256 defined you will be able to see most information about connections, filters etc. Finally create the logfile and restart the syslog daemon:

# touch /var/log/ldap.log
# chmod 644 /var/log/ldap.log
# chown root:sys /var/log/ldap.log
# svcadm restart svc:/system/system-log:default

Next download OpenDS. OpenDS is a Open Directory Service written in Java (you can use also OpenDS direclty as LDAP server). It contains a few additional schema files which we need before we can continue:

# cd /usr/src
# wget -c "http://java.net/downloads/opends/promoted-builds/2.2.1/OpenDS-2.2.1.zip"
...


Unzip the package:

# unzip OpenDS-2.2.1.zip
...


Create a new subdirectory in your schema directory for the solaris schema files:

# mkdir -p /opt/openldap/latest/etc/openldap/schema/solaris
And change into the directory that comes with OpenDS schema files:

# cd /usr/src/OpenDS-2.2.1/config/schema/

The shipped ldif files that comes with the OpenDS package are not ready for OpenLDAP. They have a little different layout which can be changed with grep, ggrep and sed to make the ldif files usable for OpenLDAP:

# grep -v "^#" 05-rfc4876.ldif | grep -v "dn: cn=schema" | grep -v "objectClass: top" | grep -v "objectClass: ldapSubentry" | grep -v "objectClass: subschema" | sed 's/attributeTypes:/attributeType/g' | sed 's/objectClasses:/objectClass/g' > /opt/openldap/latest/etc/openldap/schema/solaris/05-rfc4876.schema
# ggrep -A2 "1.3.6.1.1.1.1.30" 04-rfc2307bis.ldif | sed 's/attributeTypes:/attributeType/g' > /opt/openldap/latest/etc/openldap/schema/solaris/04-rfc2307bis.schema
# ggrep -A2 "1.3.6.1.1.1.2.15" 04-rfc2307bis.ldif | sed 's/objectClasses:/objectClass/g' >> /opt/openldap/latest/etc/openldap/schema/solaris/04-rfc2307bis.schema


Execute the complete above commands to turn the shipped ldif file into a schema file. Then add the new schema files to your slapd.conf:

# cd /opt/openldap/latest/etc/openldap
# vi slapd.conf
# SCHEMES
...
# SOLARIS
include         /opt/openldap/latest/etc/openldap/schema/solaris/05-rfc4876.schema
include         /opt/openldap/latest/etc/openldap/schema/solaris/04-rfc2307bis.schema


...

Exit vi and export the LD_LIBRARY_PATH variable and try to start slapd. Remember that you have to export LD_LIBRARY_PATH with the Berkeley DB libraries once before you can start slaps:

# export LD_LIBRARY_PATH=/opt/db/4.4.20/lib:$LD_LIBRARY_PATH
# /opt/openldap/latest/libexec/slapd -h ldap://192.168.1.75:389

You should see some information in ldap.log now:

# tail -f /var/log/ldap.log
Nov 13 18:54:14 bck01 slapd[13558]: [ID 100111 local4.debug] slapd starting
Nov 13 18:54:14 bck01 slapd[13557]: [ID 702911 local4.debug] @(#) $OpenLDAP: slapd 2.4.26 (Nov 13 2011 18:13:56) $
Nov 13 18:54:14 bck01   root@bck01:/usr/share/src/openldap-2.4.26/servers/slapd
Nov 13 18:54:14 bck01 slapd[13558]: [ID 468869 local4.debug] bdb_monitor_db_open: monitoring disabled; configure monitor database to enable
Nov 13 18:54:14 bck01 slapd[13558]: [ID 100111 local4.debug] slapd starting
...

Now you need to create a basic DIT (domain information tree) to store the users, passwords, groups and a simple profile:

# vi basic_dit.ldif
dn: dc=example,dc=com
o: example
dc: example
objectClass: dcObject
objectClass: organization
objectClass: nisDomainObject
nisDomain: example.com

dn: ou=profile,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: profile

dn: cn=default,ou=profile,dc=example,dc=com
objectClass: DUAConfigProfile
cn: default
defaultSearchBase: dc=example,dc=com
credentialLevel: anonymous
authenticationMethod: none
defaultSearchScope: sub
profileTTL: 300
searchTimeLimit: 60
defaultServerList: 192.168.1.75
serviceSearchDescriptor: passwd: ou=users,dc=example,dc=com?one
serviceSearchDescriptor: shadow: ou=users,dc=example,dc=com?one
serviceSearchDescriptor: group: ou=groups,dc=example,dc=com?one

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: groups

dn: cn=staff,ou=groups,dc=example,dc=com
gidNumber: 10
cn: staff
objectClass: posixGroup
objectClass: top

dn: ou=users,dc=example,dc=com
objectClass: organizationalUnit
objectClass: top
ou: users

dn: uid=sneill,ou=users,dc=example,dc=com
cn: Sam Neill
sn: Neill
givenName: Sam
uid: sneill
uidNumber: 1000
gidNumber: 10
homeDirectory: /home/sneill
loginShell: /bin/bash
gecos: Normal User
mail: sam.neill@example.com
shadowMax: 45
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword:

dn: uid=proxy,dc=example,dc=com
objectClass: account
objectClass: simpleSecurityObject
objectClass: top
userPassword:
uid: proxy

The basic dit above will add your domain (example.com), creates three organizational units (groups, users and profile) and creates a group (staff with gid 10), a user (sneill with uid 1000), a default profile and a proxy user. Now add the basic dit to your LDAP:

# /opt/openldap/latest/bin/ldapadd -x -W -D 'cn=ldapadmin,dc=example,dc=com' -h 192.168.1.75 -f basic_dit.ldif
Enter LDAP Password:
adding new entry "dc=example,dc=com"

adding new entry "ou=profile,dc=example,dc=com"

adding new entry "cn=default,ou=profile,dc=example,dc=com"

adding new entry "ou=groups,dc=example,dc=com"

adding new entry "cn=staff,ou=groups,dc=example,dc=com"

adding new entry "ou=users,dc=example,dc=com"

adding new entry "uid=sneill,ou=users,dc=example,dc=com"

adding new entry "uid=proxy,dc=example,dc=com"

When you did it so far then the LDAP server it self is running. Note that the password for the user sneill is not set yet, you can do this easily with ldappasswd:

# /opt/openldap/latest/bin/ldappasswd -x -W -D 'cn=ldapadmin,dc=example,dc=com' -h 192.168.1.75 -S 'uid=sneill,ou=users,dc=example,dc=com'
New password:
Re-enter new password:
Enter LDAP Password:

The first password you enter is for the user sneill, the second to verify the first password. The third password you have to enter is for the user ldapadmin to authenticate against the LDAP. Do the same for the proxy user:

# /opt/openldap/latest/bin/ldappasswd -x -W -D 'cn=ldapadmin,dc=example,dc=com' -h 192.168.1.75 -S 'uid=proxy,dc=example,dc=com'
New password:
Re-enter new password:
Enter LDAP Password:

Now set the domainname. The domainname has to be the same as the domainname in the nisDomain attribute from the above basic dit, in this case example.com. Keep in mind that the NIS domain name has nothing to do with your real domain name. In my case both are the same, but your real domain name could be example.com while the NIS domain name could be foobar:

# domainname example.com

And finally configure your system for LDAP:

# ldapclient -v manual -a credentialLevel=proxy -a authenticationMethod=simple -a proxyDN=uid=proxy,dc=example,dc=com -a proxyPassword=It'satrap! -a defaultServerList=192.168.1.75 -a defaultSearchBase=dc=example,dc=com -a serviceSearchDescriptor=passwd:ou=users,dc=example,dc=com?one -a serviceSearchDescriptor=group:ou=groups,dc=example,dc=com?one
...
restart: milestone/name-services:default... success
System successfully configured

Don't forget to set the right password for the proxy user in the ldapclient command option list. Now play a little bit with one of the Solaris native LDAP tools - ldaplist. With ldaplist you can list your dit right from your server without using the ldapsearch tool:

# ldaplist
dn: ou=profile,dc=example,dc=com

dn: ou=groups,dc=example,dc=com

dn: ou=users,dc=example,dc=com

dn: uid=proxy,dc=example,dc=com

# ldaplist -l
dn: ou=profile,dc=example,dc=com
        objectClass: organizationalUnit
        objectClass: top
        ou: profile

dn: ou=groups,dc=example,dc=com
        objectClass: organizationalUnit
        objectClass: top
        ou: groups

dn: ou=users,dc=example,dc=com
        objectClass: organizationalUnit
        objectClass: top
        ou: users

dn: uid=proxy,dc=example,dc=com
        objectClass: account
        objectClass: simpleSecurityObject
        objectClass: top
        uid: proxy
        userPassword: {CRYPT}O6raWkfPSufks

The next ldaplist command sample is important:

# ldaplist -vl passwd
+++ database=passwd
+++ filter=objectclass=posixaccount
+++ template for merging SSD filter=%s
dn: uid=sneill,ou=users,dc=example,dc=com
        cn: Sam Neill
        sn: Neill
        givenName: Sam
        uid: sneill
        uidNumber: 1000
        gidNumber: 10
        homeDirectory: /home/sneill
        loginShell: /bin/bash
        gecos: Normal User
        mail: sam.neill@example.com
        shadowMax: 45
        objectClass: top
        objectClass: person
        objectClass: organizationalPerson
        objectClass: inetOrgPerson
        objectClass: posixAccount
        objectClass: shadowAccount
        userPassword: {CRYPT}SM2kt6IBQlP9k

As long as you don't see the userPassword attribute in the above ldaplist command your users won't be able to authenticate to the system! I have seen a lot of threads, wikis etc struggling with this - I ran into the same issue and solved it by creating the proxy user and give him read rights to the userPassword attribute inside the ACL.
You can also use the native ldapsearch command instead of the compiled OpenLDAP ldapsearch command, but the syntax is a little bit different. Enclosed an example how to use the native ldapsearch and the OpenLDAP ldapsearch command:

# /bin/ldapsearch -v -h 192.168.1.75 -p 389 -D 'cn=ldapadmin,dc=example,dc=com' -w - -b 'dc=example,dc=com' -s base '(&(objectClass=nisDomainObject)(nisDomain=example.com))'
Enter bind password:
ldapsearch: started Sun Nov 20 19:47:06 2011

ldap_init( 192.168.1.75, 389 )
filter pattern: (&(objectClass=nisDomainObject)(nisDomain=example.com))
returning: ALL
filter is: (&(objectClass=nisDomainObject)(nisDomain=example.com))
version: 1
dn: dc=example,dc=com
dc: example
nisDomain: example.com
o: Example
objectClass: dcObject
objectClass: organization
objectClass: nisDomainObject
1 matches

# /opt/openldap/latest/bin/ldapsearch -h 192.168.1.75 -p 389 -x -W -D 'cn=ldapadmin,dc=example,dc=com' -b 'dc=example,dc=com' -s base '(&(objectClass=nisDomainObject)(nisDomain=example.com))'
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope baseObject
# filter: (&(objectClass=nisDomainObject)(nisDomain=example.com))
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
dc: example
nisDomain: example.com
o: Example
objectClass: dcObject
objectClass: organization
objectClass: nisDomainObject

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

Now test if everything works with getent and check for users and groups:

# getent passwd
...
sneill:x:1000:10:Normal User:/home/sneill:/bin/bash
# getent group
...
staff::10:

The group staff should appear twice - one from your file based group entry in /etc/group and one from your LDAP entry. Now create a home directory for sneill:

# mkdir -p /home/sneill
# chown -R sneill:staff /home/sneill

And try to su:

# su - sneill
$ id -a
uid=1000(sneill) gid=10(staff) groups=10(staff)
$ exit
logout

At this point your LDAP server is running and usable with Solaris. Everytime you want to add a user take the template from the basic dit above, add it to the dit, create a password and create a home directory. Try to login via ssh:

# ssh sneill@192.168.1.75

Every user can change now their password with the passwd command:

$ passwd -r ldap
passwd: Changing password for sneill
Enter existing login password:
New Password:
Re-enter new Password:
passwd: password successfully changed for sneill

The above method to initialize a Solaris host as a LDAP client has several disadvantages:

1. unneccassary long ldapclient command
2. a extra proxy user

Lets try to make it a little easier. First remove the proxy user from the LDAP ACL and give read permission to the userPassword attribute to everyone:

# cd /opt/openldap/latest/etc/openldap
# vi acl.conf
access to attrs=userPassword
    by self write
    by * read
    by * auth
...

This does not effect your security because the ldaplist command can be executed by any user. So every user can read your encrypted password. In this case it is OK to give read access to everyone. To activate the new ACL restart slapd:

# kill -15 `cat /var/run/slapd.pid`
# export LD_LIBRARY_PATH=/opt/db/4.4.20/lib:$LD_LIBRARY_PATH
# /opt/openldap/latest/libexec/slapd -h ldap://192.168.1.75:389

Next run a much simplier ldapclient command:

# ldapclient -v init 192.168.1.75
Arguments parsed:
        defaultServerList: 192.168.1.75
...
restart: milestone/name-services:default... success
System successfully configured

All information are already stored in the profile which is defined in the LDAP itself, no more options needed. This is much easier then initializing a Solaris host manually. You can savely remove the proxy user from your dit now:

# /opt/openldap/latest/bin/ldapdelete -x -W -D 'cn=ldapadmin,dc=example,dc=com' -h 192.168.1.75 'uid=proxy,dc=example,dc=com'
Enter LDAP Password:

And test that you can see the userPassword attribute when executing the ldaplist command:

# ldaplist -l passwd
dn: uid=sneill,ou=users,dc=example,dc=com
        cn: Sam Neill
        sn: Neill
        givenName: Sam
        uid: sneill
        uidNumber: 1000
        gidNumber: 10
        homeDirectory: /home/sneill
        loginShell: /bin/bash
        gecos: Normal User
        mail: sam.neill@example.com
        shadowMax: 45
        objectClass: top
        objectClass: person
        objectClass: organizationalPerson
        objectClass: inetOrgPerson
        objectClass: posixAccount
        objectClass: shadowAccount
        userPassword: {crypt}Skp/ZPmPGbkAw

Hope that this article cleared up a few things how to set up OpenLDAP for use with Solaris.

Links:
http://dsc.sun.com/solaris/articles/user_auth_solaris1.html
http://www.brandonhutchinson.com/wiki/Main_Page#LDAP
http://opends.java.net/

Update 11/30/2012: Replaced the two solaris schema files with ldif files from OpenDS Print Friendly and PDF

Sunday, December 18, 2011

SNES emulator with original pads

If you are a retro gamer like me then you know emulators. With emulators you can play variuos games of old consoles. Less known is the ability to connect the original gamepads to your computer. In most cases you need to build or buy an adapter. With this article I want you to show how to connect the original SNES gamepads to your parallel port on your PC and play games with them. I have build an adapter out of my old SNES console to keep the original gamepads intact. Before you think about building an adapter for yourself make sure that your parallel port supports EPP:

# dmesg | grep parport
[   12.133671] parport0: PC-style at 0x378 [PCSPP,TRISTATE,EPP]
...

If your parallel port supports EPP then you can continue building the adapter. The following image shows how to connect your SNES pads to your parallel port:
 


The 6 diodes on the pins 4-9 on your parallel port are connected at the end and then connected to pin 7 of every SNES pad you want to use. The other pins can be wired directly. For each gamepad you want to connect you need a seperate data line. With this layout you are able to use up to five SNES gamepads. I have only drawed a image with one connected gamepad to keep it clear. When you have created your own adapter then connect it to the parallel port of your pc. The next image is my adapter:




Then load the driver. First remove the lp driver if necessary:

# rmmod lp

Next load the gamecon driver:

# modprobe gamecon map=0,1,1,0,0,0

Check the logs:

# dmesg
...
input: SNES pad as /devices/virtual/input/input6
input: SNES pad as /devices/virtual/input/input7

And check if the input devices were created:

# ls /dev/input/js*
/dev/input/js0  /dev/input/js1

Then do a simple check if the gamepads work. Execute cat on one of the js devices and press any button on your gamepad. You should see some weird characters on your screen:

# cat /dev/input/js0
...

About the map parameter of the gamecon driver: the first 0 in the array defines which parallel port to use (0 = first parallel port, 1 = second parallel port). The five coming digits define which gamepad you want to use:

0 None
1 SNES pad
2 NES pad
...
9 SNES mouse

I use the first parallel port on my pc with two SNES gamepads.
Now you need an emulator to play the SNES games. I like to use xe. First get the xe binary. It is available precompile and should meet your needs:

# cd /usr/src/
# wget http://www.xe-emulator.com/files/xe-x86-32-bin.2.16.2.tar.bz2
...

Then extract the tar file and change into the new directory:

# tar xf xe-x86-32-bin.2.16.2.tar.bz2
# cd xe-x86

Then Link the binary and install it:

# make
# make install
xe successfully installed

The xe binary should be available under /usr/local/bin:

# ls -lah /usr/local/bin/xe
lrwxrwxrwx 1 root root 20 2011-12-17 23:20 /usr/local/bin/xe -> /usr/local/lib/xe/xe

Obviously it is not a binary, it is a symbolic link. But that should not matter. Start xe with a game:

$ xe custom_rom.smc

A simple gui will open and the game will start. Press CTRL+1 simultanously to activate gamepad 1 and CTRL+2 to activate gamepad 2. Have fun.

Links:
Documentation how to set up an adapter and which gamepads are supported:
http://www.mjmwired.net/kernel/Documentation/input/joystick-parport.txt Print Friendly and PDF

Friday, December 16, 2011

Streaming audio server with Icecast (OGG/MP3)

Creating your own internet radio station isn't very hard. There is a nice software called Icecast which can do it for you. Icecast was designed to stream any audio file if a appropiate streaming client is available. For OGG/Vorbis you can use ices and for MP3 icegenerator. Here is a small tutorial how to setup Icecast for streaming OGG/Vorbis and MP3. I am using Slackware Linux again.
This article contains the following topics:

Setting up the server: Icecast
Setting up the OGG/Vorbis streaming client: ices
Setting up the MP3 streaming client: icegenerator

Setting up the server: Icecast

First get the software:

# mkdir -p /usr/src/icecast
# cd /usr/src/icecast
# wget http://downloads.xiph.org/releases/icecast/icecast-2.3.2.tar.gz
...

Next extract the sources and change into the new driectory:

# tar xf icecast-2.3.2.tar.gz
# cd icecast-2.3.2

Then configure the sources:

# ./configure --prefix=/opt/icecast/2.3.2
...

And finally compile the sources and install the binaries:

# make
...
# make install
...

You should have now the icecast binary under /opt/icecast/2.3.2/latest/bin:

# ls /opt/icecast/2.3.2/bin/
icecast*

Now go into the icecast directory and link the 2.3.2 directory to latest:

# cd /opt/icecast
# ln -s 2.3.2 latest

Now configure icecast by editing the icecast.xml file. First move the orignal sample file to an alternate place:

# cd /opt/icecast/latest/etc
# mv icecast.xml icecast.xml.orig
# vi icecast.xml
<icecast>

  <!-- LIMITS -->
  <limits>
    <clients>10</clients>
    <sources>10</sources>
    <threadpool>5</threadpool>
    <queue-size>524288</queue-size>
    <client-timeout>30</client-timeout>
    <header-timeout>15</header-timeout>
    <source-timeout>10</source-timeout>
    <burst-on-connect>1</burst-on-connect>
    <burst-size>65535</burst-size>
  </limits>

  <!-- GENRIC -->
  <authentication>
    <source-password>Its'atrap!</source-password>
    <admin-user>icecast</admin-user>
    <admin-password>Its'anothertrap!</admin-password>
  </authentication>
  <hostname>dc01</hostname>
  <listen-socket>
    <port>8000</port>
  </listen-socket>
  <fileserve>1</fileserve>

  <!-- PATHES -->
  <paths>
    <basedir>/opt/icecast/latest/share/icecast</basedir>
    <webroot>/opt/icecast/latest/share/icecast/web</webroot>
    <adminroot>/opt/icecast/latest/share/icecast/admin</adminroot>
    <logdir>/var/log/icecast</logdir>
    <pidfile>/var/run/icecast/icecast.pid</pidfile>
    <alias source="/" dest="/status.xsl"/>
  </paths>

  <!-- LOG -->
  <logging>
    <accesslog>access.log</accesslog>
    <errorlog>error.log</errorlog>
    <playlistlog>playlist.log</playlistlog>
    <loglevel>1</loglevel>
    <logsize>10000</logsize>
    <logarchive>1</logarchive>
  </logging>

  <!-- SECURITY -->
  <security>
    <chroot>0</chroot>
    <changeowner>
      <user>icecast</user>
      <group>icecast</group>
    </changeowner>
  </security>

</icecast>

The above icecast.xml is very simple. The first section LIMITS defines how many radio stations you maximum want to provide (sources=10), how many clients may connect (clients=10) etc. The second section GENERIC defines a username, hostname (dc01), port (8000) for the server itself etc. The section PATHES defines the pathes to the webgui. Icecast has a small and simple webgui to see what is going on and this section defines where to find the web documents. The LOGGING section is of course for logging, where and what to log etc. The SECURITY section defines that the Icecast software itself should run under the user icecast and the group icecast.
Now we need three more things to do: create a user and a group called icecast as defined in the icecast.xml configuration file, create the place for the logs and a place for the pid file. First create the icecast user with the ID 200 and the group icecast with the ID 200:

# groupadd -g 200 icecast
# useradd -d /var/log/icecast -m -g icecast -s /bin/bash -u 200 icecast

With the -m option set the directory for the logs was automatically created and the second step can be spared. Only the directory for the pid file is now needed:

# mkdir -p /var/run/icecast
# chown -R icecast:icecast /var/run/icecast

Now give it a try and start the icecast server:

# /opt/icecast/latest/bin/icecast -c /opt/icecast/latest/etc/icecast.xml -b
Starting icecast2
Detaching from the console
Changed groupid to 200.
Changed userid to 200.

Your server is now running as your icecast user and logs will be produced under /var/log/icecast:

# ls /var/log/icecast/
access.log  error.log  playlist.log

Check that it is really running:

# pgrep -fl icecast
4434 /opt/icecast/latest/bin/icecast -c /opt/icecast/latest/etc/icecast.xml -b

Also the icecast server should be reachable via webgui under your given hostname and port, in my case http://dc01:8000/, when you have setup one or more stations they will show up here. The user for the administrative webgui is defined in the icecast.xml file above - icecast. The password in this case is It'sanothertrap!.

Setting up the OGG/Vorbis streaming client: ices

Before you can compile ices you need the libshout library. First download it:

# cd /usr/src/icecast
# wget http://downloads.us.xiph.org/releases/libshout/libshout-2.2.2.tar.gz
...

Then extract the tar file and change into the new directory:

# tar xf libshout-2.2.2.tar.gz
# cd libshout-2.2.2

Run the configure script:

# ./configure --prefix=/opt/icecast/latest
...

And compile the sources and install the library:

# make
...
# make install
...

Now download the ices client:

# cd /usr/src/icecast
# wget http://downloads.us.xiph.org/releases/ices/ices-2.0.1.tar.bz2
...

Extract the tar file and change into the new directory:

# tar xf ices-2.0.1.tar.bz2
# cd ices-2.0.1/

Before you run the configure script, export the PKG_CONFIG_PATH variable so ices will be able to include the libshout library:

# export PKG_CONFIG_PATH=/opt/icecast/latest/lib/pkgconfig:$PKG_CONFIG_PATH
# ./configure --prefix=/opt/icecast/latest
...

Now compile the sources and install the binaries:

# make
...
# make install
...

Check that the ices client is available:

# ls /opt/icecast/latest/bin/
icecast*  ices*

Finally configure the ices client and create your first OGG/Vorbis radio station:

# cd /opt/icecast/latest
# vi ices1.xml
<ices>

  <!-- GENERIC -->
  <background>1</background>
  <pidfile>/var/run/icecast/ices1.pid</pidfile>

  <!-- LOGGING -->
  <logpath>/var/log/icecast</logpath>
  <logfile>ices1.log</logfile>
  <logsize>2048</logsize>
  <loglevel>3</loglevel>
  <consolelog>0</consolelog>

  <!-- STREAM -->
  <stream>
    <metadata>
      <name>Testradio: One</name>
      <genre>Varios</genre>
      <description>Local Test Radio</description>
      <url>http://dc01:8000/</url>
    </metadata>
    <input>
      <param name="type">basic</param>
      <param name="file">/opt/icecast/latest/etc/playlist1.txt</param>
      <param name="random">1</param>
      <param name="once">0</param>
      <param name="restart-after-reread">1</param>
    </input>
    <instance>
      <hostname>dc01</hostname>
      <port>8000</port>
      <password>It'satrap!</password>
      <mount>/one.ogg</mount>
    </instance>
  </stream>

</ices>

The ices configuration file is as easy as the icecast configuration file. The section GENERIC defines to run ices in background and where the pid file can be found. The section LOGGING is all about logging, where and what to log. The STREAM section needs a little more attention. It defines the radio station itself like the name of the station, where the icecast server can be reached etc. The password is the source password from the icecast configuration file. If you don't set a password here everybody can connect to your icecast server and create a station. One more thing: the playlist. The playlist is a plain text file and contains all your songs you want to play. Every OGG/Vorbis file inside this file must have the full path, eg:

# cd /opt/latest/etc
# vi playlist1.txt
/export/music/artist/album/song1.ogg
/export/music/artist/album/song2.ogg
...

You can create this list easily with find:

# find /export/music -name "*.ogg" > /opt/icecast/latest/etc/playlist1.txt

With the ices configuration file and the playlist created, start up ices as user icecast:

# su - icecast -c "/opt/icecast/latest/bin/ices /opt/icecast/latest/etc/ices1.xml"

Now take a look into the log file:

# cat /var/log/icecast/ices1.log
[2011-12-16  12:17:05] INFO signals/signal_usr1_handler Metadata update requested
[2011-12-16  12:17:05] INFO playlist-basic/playlist_basic_get_next_filename Loading playlist from file "/opt/icecast/latest/etc/playlist1.txt"
[2011-12-16  12:17:05] INFO playlist-builtin/playlist_read Currently playing "/export/music/artist/album/song2.ogg"
[2011-12-16  12:17:05] INFO stream/ices_instance_stream Connected to server: dc01:8000/one.ogg
...

As you can see the first radio station is ready and available under http://dc01:8000/one.ogg. Now try to connect to your streaming server with an audio client and enjoy listening to your radio:

$ ogg123 http://dc01:8000/one.ogg
Audio Device:   Advanced Linux Sound Architecture (ALSA) output
Playing: http://dc01:8000/one.ogg
Ogg Vorbis stream: 2 channel, 44100 Hz
Album: album
Artist: artist
Description:
Genre:
Title: song2.ogg
...

For each radio station you want to provide you need to create a single ices configuration file with it's own playlist etc. Eg. you can create a seperate radio station for your Rock music and a seperate radio station for your Pop music.

Setting up the MP3 streaming client: icegenerator

To stream MP3 files you need a streaming client like icegenerator. Before you can compile icegenerator you have to install libshout first (if not done already):

# cd /usr/src/icecast
# wget http://downloads.us.xiph.org/releases/libshout/libshout-2.2.2.tar.gz
...

Then extract the tar file and change into the new directory:

# tar xf libshout-2.2.2.tar.gz
# cd libshout-2.2.2

Run the configure script:

# ./configure --prefix=/opt/icecast/latest
...

And compile the sources and install the library:

# make
...
# make install
...

To compile icegenerator downlod the source package from http://sourceforge.net/projects/icegenerator/ and store it in your src directory. Then go into the src directory and extract the source:

# cd /usr/src/icecast
# tar xfz icegenerator-0.5.5-pre2.tar.gz
# cd icegenerator-0.5.5-pre2

Now run the configure script (the --prefix option will be ignored, just run the configure script without the --prefix option):

# ./configure
...

And compile the sources and install the binaries:

# make
...
# make install
...

Check that icegenerator is available:

# ls -lah /usr/local/bin/ice*
-rwxr-xr-x 1 root root 55K 2011-12-16 12:41 /usr/local/bin/icegenerator*

Now configure icegeneratori and create your first MP3 radio station:

# cd /usr/local/etc
# vi icegen1.cfg
IP=192.168.1.73
PORT=8000
SERVER=2
MOUNT=/two.mp3
PASSWORD=It'satrap!
FORMAT=1
MP3PATH=m3u:/usr/local/etc/playlist2.m3u
LOOP=1
SHUFFLE=1
NAME=Testradio: Two
DESCRIPTION=Local Test Radio
GENRE=Varios
URL=http://dc01:8000/
LOG=2
LOGPATH=/var/log/icecast/icegen1.log
BITRATE=48000
SOURCE=icecast

The configuration file is a bit more complicated than the ices configuration file. At first you to define the IP and port for your Icecast server (in my case dc01, which is 192.168.1.73). The SERVER option is for the icy or http protocol, here it is http. MOUNT and PASSWORD are same as the OGG/Vorbis station, where to reach the station itself (http://dc01:8000/two.mp3) and how to authenticate. The FORMAT option is for either streaming MP3i (1) or OGG/Vorbis (0). LOOP and SHUFFLE for looping the playlist and randomized plaing. NAME, DESCRIPTION and GENRE will describe your radio. MP3PATH defines which files to stream, in this case all from a m3u compatible playlist (created later). URL tells where to reach the streaming server or any other address. This address will maybe displayed by your player. Specifiy LOG and LOGPATH for logging. The BITRATE defines the streaming quality and the last option SOURCE is the username for the icecast server.
Next create the playlist:

# vi /usr/local/etc/playlist2.m3u
/export/music/artist/album/song1.mp3
/export/music/artist/album/song2.mp3

Or just use find:

# find /export/music -name "*.mp3" > /usr/local/etc/playlist2.m3u

Now give it a try and start icegenerator. Remember that libshout is accessable under /opt/icecast/latest/lib, so you have to export the LD_LIBRARY_PATH variable first when you start icegenerator as user icecast:

# su - icecast -c "export LD_LIBRARY_PATH=/opt/icecast/latest/lib:$LD_LIBRARY_PATH; /usr/local/bin/icegenerator -f /usr/local/etc/icegen1.cfg"

Check that it is running:

# pgrep -fl icegen
31255 icegenerator -f /usr/local/etc/icegen1.cfg

And take a look at the log:

# cat /var/log/icecast/icegen1.log
Fri Dec 16 13:44:38 2011: Connected to stream server
Fri Dec 16 13:44:38 2011: Now playing song1.mp3
Fri Dec 16 13:48:41 2011: Wait for all child process to terminate...
...

And finally try playing it:

$ mplayer http://dc01:8000/two.mp3
MPlayer 20100218-4.4.3 (C) 2000-2010 MPlayer Team

Playing http://dc01:8000/two.mp3.
Resolving dc01 for AF_INET6...
Couldn't resolve name for AF_INET6: dc01
Resolving dc01 for AF_INET...
Connecting to server dc01[192.168.1.73]: 8000...
Name   : two
Website: http://dc01:8000/
Public : no
Bitrate: 48000kbit/s
Cache size set to 320 KBytes
Cache fill:  2.50% (8192 bytes)  
ICY Info: StreamTitle='song2';
Cache fill: 12.50% (40960 bytes)  
ICY Info: StreamTitle='song2';

Audio only file format detected.
==========================================================================
Opening audio decoder: [mp3lib] MPEG layer-2, layer-3
mpg123: Can't rewind stream by 725 bits!
AUDIO: 44100 Hz, 2 ch, s16le, 192.0 kbit/13.61% (ratio: 24000->176400)
Selected audio codec: [mp3] afm: mp3lib (mp3lib MPEG layer-2, layer-3)
==========================================================================
AO: [oss] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...

That's it again. A simple nice internet radio station to play around.

Links:
Icecast, libshout and ices:
http://www.icecast.org

icegenerator:
http://sourceforge.net/projects/icegenerator/

Description for icegenerator:
http://www.becrux.com/index.php?page=projects&name=icegenerator#Configuration
Print Friendly and PDF