Samba

Temperary Exim4 SASL AUTH solution with LDAP-Samba-PAM/NSS + Courier authpam module

Recall to my previous Exim4 + Courier + SSL on Debian etch mini-HOWTO, Exim4 authentication should work fine without enable plain_courier_authdaemon and login_courier_authdaemon support. But case will become a bit more complicated when using LDAP-Samba-PAM/NSS setup: LDAP user will now not able to be authenticated. Why and what's up!?

Why not functioning?

By default Debian's Exim4 already coming with AUTH PLAIN and AUTH LOGIN setup with direct query on /etc/passwd or /etc/shadow as follow (Beware! This is completely not equal as authenticate with PAM!):

plain:
  driver = plaintext
  public_name = PLAIN
.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS
  client_send = "<; ${if !eq{$tls_cipher}{}\
                    {^${extract{1}{:}{PASSWDLINE}}\
                     ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}\
                   }fail}"
.else
  client_send = "<; ^${extract{1}{:}{PASSWDLINE}}\
                    ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}"
.endif

login:
  driver = plaintext
  public_name = LOGIN
.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS
  # Return empty string if not non-TLS AND looking up $host in passwd-file
  # yields a non-empty string; fail otherwise.
  client_send = "<; ${if and{\
                          {!eq{$tls_cipher}{}}\
                          {!eq{PASSWDLINE}{}}\
                         }\
                      {}fail}\
                 ; ${extract{1}{::}{PASSWDLINE}}\
                 ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}"
.else
  # Return empty string if looking up $host in passwd-file yields a
  # non-empty string; fail otherwise.
  client_send = "<; ${if !eq{PASSWDLINE}{}\
                      {}fail}\
                 ; ${extract{1}{::}{PASSWDLINE}}\
                 ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}"
.endif

As LDAP users information are now NOT stored within /etc/passwd and /etc/shadow, for sure that above setup will not function (because the PASSWDLINE don't contain such information).

Possible solutions

exim4-auth-001.pngexim4-auth-001.png

Some possible solutions:

  1. Direct authenticate with LDAP backend (reference: http://www.wlug.org.nz/EximSmtpAuth)
  2. Manual setup Exim4 with PAM authentication, as LDAP + PAM/NSS function correctly (reference: http://www.wlug.org.nz/EximSmtpAuth)
  3. Enable Exim4's plain_courier_authdaemon and login_courier_authdaemon support, as Courier's authpam module function correctly (which also means LDAP + PAM/NSS function correctly)

Each setup come with different PROS/CONS:

  1. Direct LDAP authentication: We can even store more information within LDAP, e.g. quota, vocation message, redirect, alias and so on, therefore enrich Exim4 functionality; BTW, this method is the most ideal but complicated in setup.
  2. Manual PAM authentication: A bit simple than above but only able to query authenticate information, and nothing else. There is no default Debian's reference setup, too.
  3. Authenticate though Courier: Most simple as Debian already handle most reference setup, what we only need to do is enable it.

Quick-and-dirty solution

Well... Long story short, as a quick and dirty solution, just enable Exim4's Courier authenticate section as below:

# Authenticate against courier authdaemon

# This is now the (working!) example from
# http://www.exim.org/eximwiki/FAQ/Policy_controls/Q0730
#
Possible pitfall: access rights on /var/run/courier/authdaemon/socket.
plain_courier_authdaemon:
  driver = plaintext
  public_name = PLAIN
  server_condition = \
    ${extract {ADDRESS} \
              {${readsocket{/var/run/courier/authdaemon/socket} \
              {AUTH ${strlen:exim\nlogin\n$auth2\n$auth3\n}\nexim\nlogin\n$auth2\n$auth3\n} }} \
              {yes} \
              fail}
  server_set_id = $auth2
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
  server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif

login_courier_authdaemon:
  driver = plaintext
  public_name = LOGIN
  server_prompts = Username:: : Password::
  server_condition = \
    ${extract {ADDRESS} \
              {${readsocket{/var/run/courier/authdaemon/socket} \
              {AUTH ${strlen:exim\nlogin\n$auth1\n$auth2\n}\nexim\nlogin\n$auth1\n$auth2\n} }} \
              {yes} \
              fail}
  server_set_id = $auth1
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
  server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif

And then ensure Courier is now authenticate with authpam:

authmodulelist="authpam"

Finally give access to Exim4 in order to query Courier authdaemon socket:

chmod 755 /var/run/courier/authdaemon

That's all :D


smbldap-populate hack with rfc2307bis.schema support

By default, smbldap_tools only support nis.schema and so not working with rfc2307bis.schema. By apply this patch your smbldap-populate can now install default schema with rfc2307bis.schema.

NOTE! This patch is far from complete: it only handle default schema populatation and hardcode with rfc2307bis.schema support. The ideal solution should be a clone to eGroupWare's implementation which can switch support between nis.schema and rfc2307bis.schema dynamically, and also add support for both group add/modify/delete actions.


eGroupWare + smbldap-tools integration with SQL hack

By default, smbldap-populate will add groups 'Domain User' with gidnumber 513, and 'Administrators' with gidnumber 544. This can map with eGroupWare's default groups 'Default' and 'Admins'. On the other hand, smbldap-populate will add default administrator account 'root' with uidnumber 0, where it is invalid for eGroupWare (eGroupWare count account id with AUTO_INCREMENT, where starting from 1 and so 0 is invalid). We need some tricks in order to integrate them:


Main difference between nis.schema and rfc2307bis.schema

I give some indeed study for eGroupWare + LDAP, compare its use between nis.schema and rfc2307bis.schema, slapcat and diff their result:

@@ -65,13 +65,15 @@ modifyTimestamp: 20090220182044Z
dn: cn=Default,ou=Group,dc=example,dc=com
objectClass: top
objectClass: posixGroup
+objectClass: groupOfNames
gidNumber: 1
cn: Default
-structuralObjectClass: posixGroup
+structuralObjectClass: groupOfNames
entryUUID: f627d08e-93c6-102d-9537-29575a5ac953
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20090220182056Z
memberUid: postmaster
memberUid: tester
+member: uid=postmaster,ou=People,dc=example,dc=com
+member: uid=tester,ou=People,dc=example,dc=com
entryCSN: 20090220182056.968007Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20090220182056Z

We can find that:

  1. Need to add the new objectClass: groupOfNames for each group.
  2. Need to replace all structuralObjectClass: posixGroup as structuralObjectClass: groupOfNames.
  3. Need to add required member attribute, e.g. member: uid=postmaster,ou=People,dc=example,dc=com.
  4. (HIDDEN RULE!) We need at least ONE member for each group!. eGroupWare web GUI will not allow group without any member, e.g. you can't create group without member, or delete the last member from a group.

So it is time to study how to patch smbldap-tools with rfc2307bis.schema support. May need some backtrace from eGroupWare logic, e.g. how to support both schema and dynamically switch the use of different syntax :D

Some code snippet from eGroupWare (/var/www/egroupware/phpgwapi/inc/class.accounts_ldap.inc.php):

                        // read the entry first, to check if the dn (account_lid) has changed
                        $sri = $is_group ? ldap_search($this->ds,$this->group_context,'gidnumber='.abs($data['account_id'])) :
                                ldap_search($this->ds,$this->user_context,'uidnumber='.$data['account_id']);
                        $old = ldap_get_entries($this->ds, $sri);

                        if (!$old['count'])
                        {
                                unset($old);
                        }
                        else
                        {
                                $old = $this->_ldap2array($old[0]);
                                foreach($old['objectclass'] as $n => $class)
                                {
                                        $old['objectclass'][$n] = strtolower($class);
                                }

                        $groupOfNames = in_array('groupofnames',$old ? $old['objectclass'] : $to_write['objectclass']);
                        if (!$old && $groupOfNames || $members)
                        {
                                $to_write = array_merge($to_write,$this->set_members($members,
                                        $data['account_id'],$groupOfNames,$dn));
                        }

        function set_members($members,$gid,$groupOfNames=null,$use_cn=null)
        {
                //echo "<p>accounts_ldap::set_members(".print_r($members,true).",$gid)</p>\n";
                if (!($cn = $use_cn) && !($cn = $this->id2name($gid))) return false;

                // do that group is a groupOfNames?
                if (is_null($groupOfNames)) $groupOfNames = $this->id2name($gid,'groupOfNames');

                $to_write = array('memberuid' => array());
                foreach((array)$members as $key => $member)
                {
                        if (is_numeric($member)) $member = $this->id2name($member);

                        if ($member)
                        {
                                $to_write['memberuid'][] = $member;
                                if ($groupOfNames) $to_write['member'][] = 'uid='.$member.','.$this->user_context;
                        }
                }
                if ($groupOfNames && !$to_write['member'])
                {
                        // hack as groupOfNames requires the member attribute
                        $to_write['member'][] = 'uid=dummy'.','.$this->user_context;
                }
                if ($use_cn) return $to_write;

                // set the member email addresses as forwards
                if ($this->id2name($gid,'account_email') &&     ($objectclass = $this->id2name($gid,'mailAllowed')))
                {
                        $forward = $this->group_mail_classes[$objectclass];

                        $to_write[$forward] = array();
                        foreach($members as $key => $member)
                        {
                                if (($email = $this->id2name($member,'account_email'))) $to_write[$forward][] = $email;
                        }
                }
                if (!ldap_modify($this->ds,'cn='.ldap::quote($cn).','.$this->group_context,$to_write))
                {
                        echo "ldap_modify(,'cn=$cn,$this->group_context',".print_r($to_write,true)."))\n";
                        return false;
                }
                return true;
        }


LDAP + Samba PDC + PAM/NSS on Debian Lenny HOWTO

Using LDAP is one of a good solution for single user database within networking hybrid system, e.g. integrate both user login for Windows and Linux, for email services, for web logon, and so on. This HOWTO will guide you though a basic system setup, including Samba PDC and PAM/NSS with LDAP on Debian Lenny. You can further more extend the use of LDAP to other system/platform with this setup.


Prevent '*Zone.Identifier*' files generate by WinXP SP3 and Samba3

My Samba is working fine before but some days ago, it keep on generating some '*Zone.Identifier*' files, e.g. DskPerf.zip:Zone.Identifier:$DATA, when copy file from WinXP SP3 to Samba. I can't delete them from both Windows and Linux, and I don't even understand why it come out suddently...

Finally, openSUSE forum give me a workable solution (http://forums.opensuse.org/network-internet/387779-samba-file-transfer-c...). Just add the following line to smb.conf:

vfs objects = streams_xattr

After restart Samba no more '*Zone.Identifier*' files will be generated :-)


Prevents clients from seeing the existence of files that cannot be read in Samba

When you share a disk resource with Samba directly (e.g. mount /dev/sda1 as /pub, then share /pub though Samba), you will always have a directory called as "lost+found" within the directory root.

BTW, since that is a system directory for fsck and belongs to root ONLY, you may hope to hide it from Samba so your client may not be confused. Moreover, you may also hope to hide those file/directory from Samba, if the user don't have enough privilege to access it. In this case, just add this line into your smb.conf, within global or target directory section (http://us4.samba.org/samba/docs/man/Samba-HOWTO-Collection/AccessControl...):

hide unreadable = Yes

Restart Samba and you will see the different :)


Samba也要utf8

今天買了一顆HD加到Server, 打算跑Samba Server來將我的mp3, animations等一些東西全放到這, 順便還可以養一下動物:p, Samba裝好後修改smb.conf在global section內加入下面三行, 讓Samba完全utf8 ^^

[global]
dos charset = UTF8
unix charset = UTF8
display charset = UTF8

再來用smbmount也都ok, 但中文就是一直會缺字, 我smbmount用的參數為iocharacter=utf8,codepage=cp950, 後來才發現原來codepage設錯了, cp950是big5的codepage number, 如果是utf8環境的話, 要用codepage=65001, 記下來以免下次忘了^=^

BTW, utf8的samba應該M$也看的到吧!!還沒試過, 不過2k/xp應該原本就是utf8了(因為日韓文看的到阿!), 詳細等有空再試吧!目前手邊沒M$的PC~XD

» http://ifgh.blogdns.net/blog/post/1/222


Syndicate content