<?xml version="1.0" encoding="UTF-8"?>
<chapter id="configuration">
  <title>Setting up Netatalk</title>

  <sect1>
    <title>Setting up the AFP file server</title>

    <para>AFP<indexterm>
        <primary>AFP</primary>

        <secondary>Apple Filing Protocol</secondary>
      </indexterm> (the Apple Filing Protocol) is a protocol used on the Apple
    Macintosh for file services<indexterm>
        <primary>File Services</primary>

        <secondary>Netatalk's File Services</secondary>
      </indexterm>. The protocol has evolved over the years. The final
    revision of the protocol, AFP 3.4, was introduced with OS X Lion<indexterm>
        <primary>Lion</primary>

        <secondary>Mac OS X 10.7</secondary>
      </indexterm> (10.7).</para>

    <para>Netatalk's <command>afpd</command> daemon offers AFP fileservices to
    Apple clients. The configuration is managed through the
    <filename>afp.conf</filename> file which uses an ini style configuration
    syntax.</para>

    <para>Support for <link linkend="spotlight">Spotlight</link><indexterm>
        <primary>Spotlight</primary>
      </indexterm> was added in Netatalk 3.1.</para>

    <para>Mac OS X 10.5 (Leopard) introduced support for Time Machine backups
    over AFP. Two new functions ensure that backups are written to disk, not
    just in the server's cache. Different host operating systems honor this
    cache flushing differently. To make a volume a Time Machine target, use
    the volume option "<option>time machine = yes</option>".</para>

    <para>Starting with Netatalk 2.1 UNIX symlinks<indexterm>
        <primary>symlink</primary>

        <secondary>UNIX symlink</secondary>
      </indexterm> can be used on the server. Semantics are the same as for
    e.g. NFS, i.e. they are not resolved on the server side but instead it's
    completely up to the client to resolve them, resulting in links that point
    somewhere inside the clients filesystem view.</para>

    <sect2>
      <title>afp.conf</title>

      <para><filename>afp.conf</filename> is the configuration file used by
      afpd to determine the behaviour and configuration of the AFP file server
      and the AFP volume that it provides.</para>

      <para>The <filename>afp.conf</filename> is divided into several
      sections:<variablelist>
          <varlistentry>
            <term>[Global]</term>

            <listitem>
              <para>The global section defines general server options</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>[Homes]</term>

            <listitem>
              <para>The homes section defines user home volumes</para>
            </listitem>
          </varlistentry>
        </variablelist>Any section not called <option>Global</option> or
      <option>Homes</option> is interpreted as an AFP volume.</para>

      <para>For sharing user homes by defining a <option>Homes</option>
      section you must specify the option <option>basedir regex</option> which
      can be a simple string with the path to the parent directory of all user
      homes or a regular expression.</para>

      <para>Example:</para>

      <para><programlisting>[Homes]
basedir regex = /home
</programlisting></para>

      <para>Now any user logging into the AFP server will have a user volume
      available whose path is <filename>/home/NAME</filename>.</para>

      <para>A more complex setup would be a server with a large amount of user
      homes which are split across e.g. two different
      filesystems:<itemizedlist>
          <listitem>
            <para>/RAID1/homes</para>
          </listitem>

          <listitem>
            <para>/RAID2/morehomes</para>
          </listitem>
        </itemizedlist>The following configuration is
      required:<programlisting>[Homes]
basedir regex = /RAID./.*homes
</programlisting></para>

      <para>If <option>basedir regex</option> contains a symlink, set the
      canonicalized absolute path. When <filename>/home</filename> links to
      <filename>/usr/home</filename>: <programlisting>[Homes]
basedir regex = /usr/home</programlisting></para>

      <para>For a more detailed explanation of the available options, please
      refer to the <citerefentry>
          <refentrytitle>afp.conf</refentrytitle>

          <manvolnum>5</manvolnum>
        </citerefentry> man page.</para>
    </sect2>
  </sect1>

  <sect1 id="CNID-backends">
    <title>CNID<indexterm>
        <primary>CNID</primary>

        <secondary>Catalog Node ID</secondary>
      </indexterm> backends<indexterm>
        <primary>Backend</primary>

        <secondary>CNID backend</secondary>
      </indexterm></title>

    <para>Unlike other protocols like SMB or NFS, the AFP protocol mostly
    refers to files and directories by ID and not by a path (the IDs are also
    called CNID, which stand for Catalog Node ID). A typical AFP request uses
    a directory ID<indexterm>
        <primary>DID</primary>

        <secondary>Directory ID</secondary>
      </indexterm> and a filename, something like <phrase>"server, please open
    the file named 'Test' in the directory with id 167"</phrase>. For example
    "Aliases" on the Mac basically work by ID (with a fallback to the absolute
    path in more recent AFP clients. But this applies only to Finder, not to
    applications).</para>

    <para>Every file in an AFP volume has to have a unique file ID<indexterm>
        <primary>FID</primary>

        <secondary>File ID</secondary>
      </indexterm>, IDs must, according to the specs, never be reused, and IDs
    are 32 bit numbers (Directory IDs use the same ID pool). So, after ~4
    billion files/folders have been written to an AFP volume, the ID pool is
    depleted and no new file can be written to the volume. No whining please
    :-)</para>

    <para>Netatalk needs to map IDs to files and folders in the host
    filesystem. To achieve this, several different CNID backends<indexterm>
        <primary>CNID backend</primary>
      </indexterm> are available and can be selected with the <option>cnid
    scheme</option><indexterm>
        <primary>cnidscheme</primary>

        <secondary>specifying a CNID backend</secondary>
      </indexterm> option in the <citerefentry>
        <refentrytitle>afp.conf</refentrytitle>

        <manvolnum>5</manvolnum>
      </citerefentry> configuration file. A CNID backend is basically a
    database storing ID &lt;-&gt; name mappings.</para>

    <para>The CNID databases are by default located in
    <filename>$prefix/var/netatalk/CNID</filename>. You can change the
    location by configuring <command>-Dwith-statedir-path=PATH</command> at
    compile time.</para>

    <para>There is a command line utility called <command>dbd</command>
    available which can be used to verify, repair and rebuild the CNID
    database.</para>

    <note>
      <para>There are some CNID related things you should keep in mind when
      working with netatalk:</para>

      <itemizedlist>
        <listitem>
          <para>Don't nest volumes<indexterm>
              <primary>Nested volumes</primary>
            </indexterm> unless "<option>vol dbnest = yes</option>" is
          set.</para>
        </listitem>

        <listitem>
          <para>CNID backends are databases, so they turn afpd into a file
          server/database mix.</para>
        </listitem>

        <listitem>
          <para>If there's no more space on the filesystem left, the database
          will get corrupted. You can work around this by using the
          <option>vol dbpath</option> option and put the database files into
          another location.</para>
        </listitem>

        <listitem>
          <para>Be careful with CNID databases for volumes that are mounted
          via NFS. That is a pretty audacious decision to make anyway, but
          putting a database there as well is really asking for trouble, i.e.
          database corruption. Use the <option>vol dbpath</option> directive
          to put the databases onto a local disk if you must use NFS<indexterm>
              <primary>NFS</primary>

              <secondary>Network File System</secondary>
            </indexterm> mounted volumes.</para>
        </listitem>
      </itemizedlist>
    </note>

    <sect2>
      <title>dbd<indexterm>
          <primary>DBD</primary>

          <secondary>"dbd" CNID backend</secondary>
        </indexterm></title>

      <para>The "Database Daemon" backend is built on Berkeley DB. Access to
      the CNID database is restricted to the cnid_dbd daemon process. afpd
      processes communicate with the daemon for database reads and updates.
      The probability for database corruption is practically zero.</para>

      <para>This is the default backend since Netatalk 2.1.</para>
    </sect2>

    <sect2>
      <title>last<indexterm>
          <primary>Last</primary>

          <secondary>"last" CNID backend</secondary>
        </indexterm></title>

      <para>The last backend is an in-memory tdb database. It is not
      persistent, with IDs valid only for the current session. Starting with
      netatalk 3.0, it operates in <emphasis>read only mode</emphasis>. This
      backend is useful e.g. for mounting CD-ROMs, or for automated
      testing.</para>

      <para>This is basically equivalent to how <command>afpd</command> stored
      CNID data in netatalk 1.5 and earlier.</para>
    </sect2>

    <sect2>
      <title>mysql<indexterm>
          <primary>MySQL</primary>

          <secondary>"mysql" CNID backend</secondary>
        </indexterm></title>

      <para>CNID backend using a MySQL server. The MySQL server has to be
      provisioned by the system administrator.</para>
    </sect2>
  </sect1>

  <sect1 id="charsets">
    <title>Charsets<indexterm>
        <primary>Charset</primary>

        <secondary>character set</secondary>
      </indexterm>/Unicode<indexterm>
        <primary>Unicode</primary>
      </indexterm></title>

    <sect2>
      <title>Why Unicode?</title>

      <para>Internally, computers don't know anything about characters and
      texts, they only know numbers. Therefore, each letter is assigned a
      number. A character set, often referred to as
      <emphasis>charset</emphasis> or <emphasis>codepage</emphasis><indexterm>
          <primary>Codepage</primary>
        </indexterm>, defines the mappings between numbers and letters.</para>

      <para>If two or more computer systems need to communicate with each
      other, the have to use the same character set. In the 1960s the
      ASCII<indexterm>
          <primary>ASCII</primary>

          <secondary>American Standard Code for Information
          Interchange</secondary>
        </indexterm> (American Standard Code for Information Interchange)
      character set was defined by the American Standards Association. The
      original form of ASCII represented 128 characters, more than enough to
      cover the English alphabet and numerals. Up to date, ASCII has been the
      normative character scheme used by computers.</para>

      <para>Later versions defined 256 characters to produce a more
      international fluency and to include some slightly esoteric graphical
      characters. Using this mode of encoding each character takes exactly one
      byte. Obviously, 256 characters still wasn't enough to map all the
      characters used in the various languages into one character set.</para>

      <para>As a result localized character sets were defined later, e.g the
      ISO-8859 character sets. Most operating system vendors introduced their
      own characters sets to satisfy their needs, e.g. IBM defined the
      <emphasis>codepage 437 (DOSLatinUS)</emphasis>, Apple introduced the
      <emphasis>MacRoman</emphasis><indexterm>
          <primary>MacRoman</primary>

          <secondary>MacRoman charset</secondary>
        </indexterm> codepage and so on. The characters that were assigned
      number larger than 127 were referred to as <emphasis>extended</emphasis>
      characters. These character sets conflict with another, as they use the
      same number for different characters, or vice versa.</para>

      <para>Almost all of those characters sets defined 256 characters, where
      the first 128 (0-127) character mappings are identical to ASCII. As a
      result, communication between systems using different codepages was
      effectively limited to the ASCII charset.</para>

      <para>To solve this problem new, larger character sets were defined. To
      make room for more character mappings, these character sets use at least
      2 bytes to store a character. They are therefore referred to as
      <emphasis>multibyte</emphasis> character sets.</para>

      <para>One standardized multibyte charset encoding scheme is known as
      <ulink url="http://www.unicode.org/">Unicode</ulink>. A big advantage of
      using a multibyte charset is that you only need one. There is no need to
      make sure two computers use the same charset when they are
      communicating.</para>
    </sect2>

    <sect2>
      <title>Character sets used by Apple</title>

      <para>In the past, Apple clients used single-byte charsets to
      communicate over the network. Over the years Apple defined a number of
      codepages, western users will most likely be using the
      <emphasis>MacRoman</emphasis> codepage.</para>

      <para>Codepages defined by Apple include:</para>

      <itemizedlist>
        <listitem>
          <para>MacArabic, MacFarsi</para>
        </listitem>

        <listitem>
          <para>MacCentralEurope</para>
        </listitem>

        <listitem>
          <para>MacChineseSimple</para>
        </listitem>

        <listitem>
          <para>MacChineseTraditional</para>
        </listitem>

        <listitem>
          <para>MacCroatian</para>
        </listitem>

        <listitem>
          <para>MacCyrillic</para>
        </listitem>

        <listitem>
          <para>MacDevanagari</para>
        </listitem>

        <listitem>
          <para>MacGreek</para>
        </listitem>

        <listitem>
          <para>MacHebrew</para>
        </listitem>

        <listitem>
          <para>MacIcelandic</para>
        </listitem>

        <listitem>
          <para>MacJapanese</para>
        </listitem>

        <listitem>
          <para>MacKorean</para>
        </listitem>

        <listitem>
          <para>MacRoman</para>
        </listitem>

        <listitem>
          <para>MacRomanian</para>
        </listitem>

        <listitem>
          <para>MacThai</para>
        </listitem>

        <listitem>
          <para>MacTurkish</para>
        </listitem>
      </itemizedlist>

      <para>Starting with Mac OS X and AFP3, <ulink
      url="http://www.utf-8.com/">UTF-8</ulink> is used. UTF-8 encodes Unicode
      characters in an ASCII compatible way, each Unicode character is encoded
      into 1-6 ASCII characters. UTF-8 is therefore not really a charset
      itself, it's an encoding of the Unicode charset.</para>

      <para>To complicate things, Unicode defines several <emphasis> <ulink
      url="http://www.unicode.org/reports/tr15/index.html">normalization</ulink>
      </emphasis> forms. While <ulink
      url="http://www.samba.org">samba</ulink><indexterm>
          <primary>Samba</primary>
        </indexterm> uses <emphasis>precomposed</emphasis><indexterm>
          <primary>Precomposed</primary>

          <secondary>Precomposed Unicode normalization</secondary>
        </indexterm> Unicode, which most UNIX tools prefer as well, Apple
      decided to use the <emphasis>decomposed</emphasis><indexterm>
          <primary>Decomposed</primary>

          <secondary>Decomposed Unicode normalization</secondary>
        </indexterm> normalization.</para>

      <para>For example lets take the German character '<keycode>ä</keycode>'.
      Using the precomposed normalization, Unicode maps this character to
      0xE4. In decomposed normalization, 'ä' is actually mapped to two
      characters, 0x61 and 0x308. 0x61 is the mapping for an 'a', 0x308 is the
      mapping for a <emphasis>COMBINING DIAERESIS</emphasis>.</para>

      <para>Netatalk refers to precomposed UTF-8 as
      <emphasis>UTF8</emphasis><indexterm>
          <primary>UTF8</primary>

          <secondary>Netatalk's precomposed UTF-8 encoding</secondary>
        </indexterm> and to decomposed UTF-8 as
      <emphasis>UTF8-MAC</emphasis><indexterm>
          <primary>UTF8-MAC</primary>

          <secondary>Netatalk's decomposed UTF-8 encoding</secondary>
        </indexterm>.</para>
    </sect2>

    <sect2>
      <title>afpd and character sets</title>

      <para>To support new AFP 3.x and older AFP 2.x clients at the same time,
      afpd needs to be able to convert between the various charsets used. AFP
      3.x clients always use UTF8-MAC, while AFP 2.x clients use one of the
      Apple codepages.</para>

      <para>At the time of writing, netatalk supports the following Apple
      codepages:</para>

      <itemizedlist>
        <listitem>
          <para>MAC_CENTRALEUROPE</para>
        </listitem>

        <listitem>
          <para>MAC_CHINESE_SIMP</para>
        </listitem>

        <listitem>
          <para>MAC_CHINESE_TRAD</para>
        </listitem>

        <listitem>
          <para>MAC_CYRILLIC</para>
        </listitem>

        <listitem>
          <para>MAC_GREEK</para>
        </listitem>

        <listitem>
          <para>MAC_HEBREW</para>
        </listitem>

        <listitem>
          <para>MAC_JAPANESE</para>
        </listitem>

        <listitem>
          <para>MAC_KOREAN</para>
        </listitem>

        <listitem>
          <para>MAC_ROMAN</para>
        </listitem>

        <listitem>
          <para>MAC_TURKISH</para>
        </listitem>
      </itemizedlist>

      <para>afpd handles three different character set options:</para>

      <variablelist>
        <varlistentry>
          <term>unix charset<indexterm>
              <primary>unix charset</primary>

              <secondary>afpd's unix charset setting</secondary>
            </indexterm></term>

          <listitem>
            <para>This is the codepage used internally by your operating
            system. If not specified, it defaults to <option>UTF8</option>. If
            <option>LOCALE</option> is specified and your system support UNIX
            locales, afpd tries to detect the codepage. afpd uses this
            codepage to read its configuration files, so you can use extended
            characters for volume names, login messages, etc. See
            <citerefentry>
                <refentrytitle>afp.conf</refentrytitle>

                <manvolnum>5</manvolnum>
              </citerefentry>.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>mac charset<indexterm>
              <primary>mac charset</primary>

              <secondary>afpd's mac charset setting</secondary>
            </indexterm></term>

          <listitem>
            <para>As already mentioned, older Mac OS clients (up to AFP 2.2)
            use codepages to communicate with afpd. However, there is no
            support for negotiating the codepage used by the client in the AFP
            protocol. If not specified otherwise, afpd assumes the
            <emphasis>MacRoman</emphasis> codepage is used. In case your
            clients use another codepage, e.g.
            <emphasis>MacCyrillic</emphasis>, you'll <emphasis
            role="bold">have</emphasis> to explicitly configure this. See
            <citerefentry>
                <refentrytitle>afp.conf</refentrytitle>

                <manvolnum>5</manvolnum>
              </citerefentry>.</para>
          </listitem>
        </varlistentry>

        <varlistentry>
          <term>vol charset<indexterm>
              <primary>vol charset</primary>

              <secondary>afpd's vol charset setting</secondary>
            </indexterm></term>

          <listitem>
            <para>This defines the charset afpd should use for filenames on
            disk. By default, it is the same as <option>unix charset</option>.
            If you have <ulink
            url="http://www.gnu.org/software/libiconv/">iconv</ulink><indexterm>
                <primary>Iconv</primary>

                <secondary>iconv encoding conversion engine</secondary>
              </indexterm> installed, you can use any iconv provided charset
            as well.</para>

            <para>afpd needs a way to preserve extended Macintosh characters,
            or characters illegal in UNIX filenames, when saving files on a
            UNIX filesystem. Earlier versions used the the so called CAP
            encoding<indexterm>
                <primary>CAP encoding</primary>

                <secondary>CAP style character encoding</secondary>
              </indexterm>. An extended character (&gt;0x7F) would be
            converted to a :xx hex sequence, e.g. the Apple Logo (MacRoman:
            0xF0) was saved as :f0. Some special characters will be converted
            as to :xx notation as well. '/' will be encoded to :2f, if
            <option>usedots</option> was not specified, a leading dot '.' will
            be encoded as :2e.</para>

            <para>Even though this version now uses <option>UTF8</option> as
            the default encoding for filenames, '/' will be converted to ':'.
            For western users another useful setting could be <option>vol
            charset = ISO-8859-15</option>.</para>

            <para>If a character cannot be converted from the <option>mac
            charset</option> to the selected <option>vol charset</option>,
            you'll receive a -50 error on the mac. <emphasis>Note</emphasis>:
            Whenever you can, please stick with the default UTF8 volume
            format. See <citerefentry>
                <refentrytitle>afp.conf</refentrytitle>

                <manvolnum>5</manvolnum>
              </citerefentry>.</para>
          </listitem>
        </varlistentry>
      </variablelist>
    </sect2>
  </sect1>

  <sect1 id="authentication">
    <title>Authentication<indexterm>
        <primary>Authentication</primary>

        <secondary>between AFP client and server</secondary>
      </indexterm></title>

    <sect2>
      <title>AFP authentication basics</title>

      <para>Apple chose a flexible model called "User Authentication
      Modules"<indexterm>
          <primary>UAM</primary>

          <secondary>User Authentication Module</secondary>
        </indexterm> (UAMs) for authentication purposes between AFP client and
      server. An AFP client initially connecting to an AFP server will ask for
      the list of UAMs which the server provides, and will choose the one with
      strongest encryption that the client supports.</para>

      <para>Several UAMs have been developed by Apple over the time, some by
      3rd-party developers.</para>
    </sect2>

    <sect2>
      <title>UAMs supported by Netatalk</title>

      <para>Netatalk supports the following ones by default:</para>

      <itemizedlist>
        <listitem>
          <para>"No User Authent"<indexterm>
              <primary>No User Authent</primary>

              <secondary>"No User Authent" UAM (guest access)</secondary>
            </indexterm> UAM (guest access without authentication)</para>
        </listitem>

        <listitem>
          <para>"Cleartxt Passwrd"<indexterm>
              <primary>Cleartxt Passwrd</primary>

              <secondary>"Cleartxt Passwrd" UAM</secondary>
            </indexterm> UAM (no password encryption)</para>
        </listitem>

        <listitem>
          <para>"Randnum exchange"<indexterm>
              <primary>Randnum exchange</primary>

              <secondary>"Randnum exchange" UAM</secondary>
            </indexterm>/"2-Way Randnum exchange"<indexterm>
              <primary>2-Way Randnum exchange</primary>

              <secondary>"2-Way Randnum exchange" UAM</secondary>
            </indexterm> UAMs (weak password encryption, separate password
          storage)</para>
        </listitem>

        <listitem>
          <para>"DHCAST128"<indexterm>
              <primary>DHCAST128</primary>

              <secondary>"DHCAST128" UAM</secondary>
            </indexterm> UAM (a.k.a. DHX; stronger password encryption)</para>
        </listitem>

        <listitem>
          <para>"DHX2"<indexterm>
              <primary>DHX2</primary>

              <secondary>"DHX2" UAM</secondary>
            </indexterm> UAM (successor of DHCAST128)</para>
        </listitem>
      </itemizedlist>

      <para>There exist other optional UAMs as well:</para>

      <itemizedlist>
        <listitem>
          <para>"Client Krb v2"<indexterm>
              <primary>Client Krb v2</primary>

              <secondary>"Client Krb v2" UAM (Kerberos V)</secondary>
            </indexterm> UAM (Kerberos V, suitable for "Single Sign On"
          Scenarios with macOS clients – see below)</para>
        </listitem>
      </itemizedlist>

      <para>You can configure which UAMs should be activated by defining
      "<option>uam list</option>" in <option>Global</option> section.
      <command>afpd</command> will log which UAMs it's using and if problems
      occur while activating them in either <filename>netatalk.log</filename>
      or syslog at startup time. <citerefentry>
          <refentrytitle>asip-status</refentrytitle>

          <manvolnum>1</manvolnum>
        </citerefentry> can be used to query the available UAMs of AFP servers
      as well.</para>

      <para>Having a specific UAM available at the server does not
      automatically mean that a client can use it. Client-side support is also
      necessary. For older Macintoshes running Classic Mac OS, DHCAST128
      support exists since AppleShare client 3.8.x.</para>

      <para>On macOS, there exist some client-side techniques to make the
      AFP-client more verbose, so one can have a look at what's happening
      while negotiating the UAMs to use. Compare with this <ulink
      url="https://web.archive.org/web/20080312054723/http://article.gmane.org/gmane.network.netatalk.devel/7383/">hint</ulink>.</para>
    </sect2>

    <sect2>
      <title>Which UAMs to activate?</title>

      <para>It depends primarily on your needs and on the kind of macOS
      clients you have to support. If your network consists of exclusively
      macOS (Mac OS X) clients, DHX2 is sufficient, and provides the strongest
      encryption.</para>

      <itemizedlist>
        <listitem>
          <para>Unless you really have to supply guest access to your server's
          volumes ensure that you disable "No User Authent" since it might
          lead accidentally to unauthorized access. In case you must enable
          guest access take care that you enforce this on a per volume base
          using the access controls.</para>

          <para>Note: "No User Authent" is required to use Apple II NetBoot
          services (<citerefentry>
              <refentrytitle>a2boot</refentrytitle>

              <manvolnum>8</manvolnum>
            </citerefentry>) to boot an Apple //e over AFP.</para>
        </listitem>

        <listitem>
          <para>The "ClearTxt Passwrd" UAM is as bad as it sounds since
          passwords go unencrypted over the wire. Try to avoid it at both the
          server's side as well as on the client's.</para>

          <para>Note: If you want to provide Mac OS 8/9 clients with
          NetBoot-services then you need uams_cleartext.so since the
          AFP-client integrated into the Mac's firmware can only deal with
          this basic form of authentication.</para>
        </listitem>

        <listitem>
          <para>Since "Randnum exchange"/"2-Way Randnum exchange" uses only 56
          bit DES for encryption it should be avoided as well. Another
          disadvantage is the fact that the passwords have to be stored in
          cleartext on the server and that it doesn't integrate into both PAM
          scenarios or classic /etc/shadow (you have to administrate passwords
          separately by using the <citerefentry>
              <refentrytitle>afppasswd</refentrytitle>

              <manvolnum>1</manvolnum>
            </citerefentry> utility, in order for clients to use these
          UAMs)</para>

          <para>However, this is the strongest form of authentication that can
          be used with Macintosh System Software 7.1 or earlier.</para>
        </listitem>

        <listitem>
          <para>"DHCAST128" ("DHX") or "DHX2" should be the sweet spot for
          most people since it combines stronger encryption with PAM
          integration.</para>
        </listitem>

        <listitem>
          <para>Using the Kerberos V<indexterm>
              <primary>Kerberos V</primary>

              <secondary>"Client Krb v2" UAM</secondary>
            </indexterm> ("Client Krb v2") UAM, it's possible to implement
          real single sign on scenarios using Kerberos tickets. The password
          is not sent over the network. Instead, the user password is used to
          decrypt a service ticket for the AppleShare server. The service
          ticket contains an encryption key for the client and some encrypted
          data (which only the AppleShare server can decrypt). The encrypted
          portion of the service ticket is sent to the server and used to
          authenticate the user. Because of the way that the afpd service
          principal detection is implemented, this authentication method is
          vulnerable to man-in-the-middle attacks.</para>
        </listitem>
      </itemizedlist>

      <para>For a more detailed overview over the technical implications of
      the different UAMs, please have a look at Apple's <ulink
      url="http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/AFP/AFPSecurity/AFPSecurity.html#//apple_ref/doc/uid/TP40000854-CH232-SW1">File
      Server Security</ulink> pages.</para>
    </sect2>

    <sect2>
      <title>Using different authentication sources with specific UAMs</title>

      <para>Some UAMs provide the ability to use different authentication
      "backends", namely <filename>uams_cleartext.so</filename>,
      <filename>uams_dhx.so</filename> and <filename>uams_dhx2.so</filename>.
      They can use either classic UNIX passwords from
      <filename>/etc/passwd</filename> (<filename>/etc/shadow</filename>) or
      PAM if the system supports that. <filename>uams_cleartext.so</filename>
      can be symlinked to either <filename>uams_passwd.so</filename> or
      <filename>uams_pam.so</filename>, <filename>uams_dhx.so</filename> to
      <filename>uams_dhx_passwd.so</filename> or
      <filename>uams_dhx_pam.so</filename> and
      <filename>uams_dhx2.so</filename> to
      <filename>uams_dhx2_passwd.so</filename> or
      <filename>uams_dhx2_pam.so</filename>.</para>

      <para>So, if it looks like this in Netatalk's UAMs folder (per default
      <filename>/etc/netatalk/uams/</filename>):<programlisting>uams_clrtxt.so -&gt; uams_pam.so
uams_dhx.so -&gt; uams_dhx_pam.so
uams_dhx2.so -&gt; uams_dhx2_pam.so</programlisting> then you're using PAM,
      otherwise classic UNIX passwords. The main advantage of using PAM is
      that one can integrate Netatalk in centralized authentication scenarios,
      e.g. via LDAP, NIS and the like. Please always keep in mind that the
      protection of your user's login credentials in such scenarios also
      depends on the strength of encryption that the UAM in question supplies.
      So think about eliminating weak UAMs like "ClearTxt Passwrd" and
      "Randnum exchange" completely from your network.</para>
    </sect2>

    <sect2>
      <title>Netatalk UAM overview table</title>

      <para>A small overview of the most common used UAMs.</para>

      <table orient="land">
        <title>Netatalk UAM overview</title>

        <tgroup align="center" cols="7">
          <colspec colname="col1" colnum="1" colwidth="0.5*"/>

          <colspec colname="uam_guest" colnum="2" colwidth="1*"/>

          <colspec colname="uam_clrtxt" colnum="3" colwidth="1*"/>

          <colspec colname="uam_randnum" colnum="4" colwidth="1*"/>

          <colspec colname="uam_dhx" colnum="5" colwidth="1*"/>

          <colspec colname="uam_dhx2" colnum="6" colwidth="1*"/>

          <colspec colname="uam_gss" colnum="7" colwidth="1*"/>

          <tbody>
            <row>
              <entry align="center" rotate="0" valign="middle">UAM</entry>

              <entry>No User Authent<indexterm>
                  <primary>uams_guest.so</primary>

                  <secondary>"No User Authent" UAM (guest access)</secondary>
                </indexterm></entry>

              <entry>Cleartxt Passwrd<indexterm>
                  <primary>uams_cleartxt.so</primary>

                  <secondary>"Cleartxt Passwrd" UAM</secondary>
                </indexterm></entry>

              <entry>(2-Way) Randnum exchange<indexterm>
                  <primary>uams_randnum.so</primary>

                  <secondary>"(2-Way) Randnum exchange" UAM</secondary>
                </indexterm></entry>

              <entry>DHCAST128<indexterm>
                  <primary>uams_dhx.so</primary>

                  <secondary>"DHCAST128" UAM</secondary>
                </indexterm></entry>

              <entry>DHX2<indexterm>
                  <primary>uams_dhx2.so</primary>

                  <secondary>"DHX2" UAM</secondary>
                </indexterm></entry>

              <entry>Client Krb v2<indexterm>
                  <primary>uams_gss.so</primary>

                  <secondary>"Client Krb v2" UAM (Kerberos V)</secondary>
                </indexterm></entry>
            </row>

            <row>
              <entry align="center" rotate="0" valign="middle">Password
              length</entry>

              <entry>guest access</entry>

              <entry>max. 8 characters</entry>

              <entry>max. 8 characters</entry>

              <entry>max. 64 characters</entry>

              <entry>max. 256 characters</entry>

              <entry>Kerberos tickets</entry>
            </row>

            <row>
              <entry align="center" rotate="0" valign="middle">Client
              support</entry>

              <entry>built-in into all Mac OS versions</entry>

              <entry>built-in in all Mac OS versions except 10.0. Has to be
              activated explicitly in later Mac OS X versions</entry>

              <entry>built-in into almost all Mac OS versions</entry>

              <entry>built-in since AppleShare client 3.8.4, available as a
              plug-in for 3.8.3, integrated in macOS's AFP client</entry>

              <entry>built-in since Mac OS X 10.2</entry>

              <entry>built-in since Mac OS X 10.2</entry>
            </row>

            <row>
              <entry align="center" rotate="0"
              valign="middle">Encryption</entry>

              <entry>Enables guest access without authentication between
              client and server.</entry>

              <entry>Password will be sent in cleartext over the wire. Just as
              bad as it sounds, therefore avoid at all if possible (note:
              providing NetBoot services requires the ClearTxt UAM)</entry>

              <entry>8-byte random numbers are sent over the wire, comparable
              with DES, 56 bits. Vulnerable to offline dictionary attack.
              Requires passwords in clear on the server.</entry>

              <entry>Password will be encrypted with 128 bit SSL, user will be
              authenticated against the server but not vice versa. Therefore
              weak against man-in-the-middle attacks.</entry>

              <entry>Password will be encrypted using libgcrypt with CAST 128
              in CBC mode. User will be authenticated against the server but
              not vice versa. Therefore weak against man-in-the-middle
              attacks.</entry>

              <entry>Password is not sent over the network. Due to the service
              principal detection method, this authentication method is
              vulnerable to man-in-the-middle attacks.</entry>
            </row>

            <row>
              <entry align="center" rotate="0" valign="middle">Server
              support</entry>

              <entry align="center" valign="middle">uams_guest.so</entry>

              <entry align="center" valign="middle">uams_cleartxt.so</entry>

              <entry align="center" valign="middle">uams_randnum.so</entry>

              <entry align="center" valign="middle">uams_dhx.so</entry>

              <entry align="center" valign="middle">uams_dhx2.so</entry>

              <entry align="center" valign="middle">uams_gss.so</entry>
            </row>

            <row>
              <entry align="center" rotate="0" valign="middle">Password
              storage method</entry>

              <entry align="center" valign="middle">None</entry>

              <entry align="center" valign="middle">Either /etc/passwd
              (/etc/shadow) or PAM</entry>

              <entry align="center" valign="middle">Passwords stored in clear
              text in a separate text file</entry>

              <entry align="center" valign="middle">Either /etc/passwd
              (/etc/shadow) or PAM</entry>

              <entry align="center" valign="middle">Either /etc/passwd
              (/etc/shadow) or PAM</entry>

              <entry align="center" valign="middle">At the Kerberos Key
              Distribution Center*</entry>
            </row>
          </tbody>
        </tgroup>
      </table>

      <para>* Have a look at this <ulink
      url="https://web.archive.org/web/20070705043002/http://cryptnet.net/fdp/admin/kerby-infra/en/kerby-infra.html">Kerberos
      overview</ulink></para>
    </sect2>

    <sect2 id="sshtunnel">
      <title>SSH tunneling</title>

      <para>Tunneling and VPNs usually have nothing to do with AFP
      authentication and UAMs. But since Apple introduced an option called
      "Allow Secure Connections Using SSH" and many people tend to confuse the
      two, we'll cover this here.</para>

      <sect3 id="manualsshtunnel">
        <title>Manually tunneling an AFP session</title>

        <para>This works since the first AFP servers that spoke "AFP over TCP"
        appeared in networks. One simply tunnels the remote server's AFP port
        to a local port different than 548 and connects locally to this port
        afterwards. On macOS this can be done by</para>

        <programlisting>ssh -l $USER $SERVER -L 10548:127.0.0.1:548 sleep 3000</programlisting>

        <para>After establishing the tunnel one will use
        <filename>"afp://127.0.0.1:10548"</filename> in the "Connect to
        server" dialog. All AFP traffic including the initial connection
        attempts will be sent encrypted over the wire since the local AFP
        client will connect to the Mac's local port 10548 which will be
        forwarded to the remote server's AFP port (we used the default 548)
        over SSH.</para>

        <para>This sort of tunnel is an ideal solution if you must access an
        AFP server through the Internet without having the ability or desire
        to use a "real" VPN. Note that you can let <command>ssh</command>
        compress the data by using its "-C" switch and that the tunnel
        endpoints can be different from both AFP client and server (compare
        with the SSH documentation for details).</para>
      </sect3>

      <sect3 id="autosshtunnel">
        <title>Automatically establishing a tunneled AFP connection</title>

        <para>From Mac OS X 10.2 to 10.4, Apple added an "Allow Secure
        Connections Using SSH" checkbox to the "Connect to Server" dialog. The
        idea behind this was: When the server signals that it can be contacted
        by SSH then macOS's AFP client tries to establish the tunnel and
        automagically send all AFP traffic through it.</para>

        <para>But it took until the release of Mac OS X 10.3 that this feature
        worked the first time... partly. In case, the SSH tunnel could not be
        established and the AFP client <emphasis
        role="strong">silently</emphasis> fell back to an unencrypted AFP
        connection attempt.</para>

        <para>Netatalk's afpd will report that it is capable of handling SSH
        tunneled AFP requests, when both "<option>advertise ssh</option>" and
        "<option>fqdn</option>" options are set in the <option>Global</option>
        section (double check with <citerefentry>
            <refentrytitle>asip-status</refentrytitle>

            <manvolnum>1</manvolnum>
          </citerefentry> after you restarted afpd when you made changes to
        the settings). But there are a couple of reasons why you don't want to
        use this option at all:</para>

        <itemizedlist>
          <listitem>
            <para>Most users who need such a feature are probably already
            familiar with using a VPN; it might be easier for the user to
            employ the same VPN software in order to connect to the network on
            which the AFP server is running, and then to access the AFP server
            as normal.</para>

            <para>That being said, for the simple case of connecting to one
            specific AFP server, a direct SSH connection is likely to perform
            better than a general-purpose VPN; contrary to popular belief,
            tunneling via SSH does <emphasis role="strong">not</emphasis>
            result in what's called "TCP-over-TCP meltdown", because the AFP
            data that are being tunneled do not encapsulate TCP data.</para>
          </listitem>

          <listitem>
            <para>Since this SSH kludge isn't a normal UAM that integrates
            directly into the AFP authentication mechanisms but instead uses a
            single flag signalling clients whether they can <emphasis
            role="strong">try</emphasis> to establish a tunnel or not, it
            makes life harder to see what's happening when things go
            wrong.</para>
          </listitem>

          <listitem>
            <para>You cannot control which machines are logged on by Netatalk
            tools like a <command>macusers</command> since all connection
            attempts seem to be made from localhost.</para>
          </listitem>

          <listitem>
            <para>Indeed, to ensure that all AFP sessions are encrypted via
            SSH, you need to limit afpd to connections that originate only
            from localhost (e.g., by using Wietse Venema's TCP Wrappers, or by
            using suitable firewall or packet-filtering facilities,
            etc.).</para>

            <para>Otherwise, when you're using Mac OS X 10.2 through 10.3.3,
            you get the opposite of what you'd expect: potentially unencrypted
            AFP communications (including login credentials) being sent across
            the network without a single notification that establishing the
            tunnel failed. Apple fixed that with Mac OS X 10.3.4.</para>
          </listitem>

          <listitem>
            <para>Encrypting all AFP sessions via SSH can lead to a
            significantly higher load on the computer that is running the AFP
            server, because that computer must also handle encryption; if the
            user is connecting through a trusted network, then such encryption
            might be an unnecessary overhead.</para>
          </listitem>
        </itemizedlist>
      </sect3>
    </sect2>
  </sect1>

  <sect1 id="acls">
    <title>ACL Support<indexterm>
        <primary>ACLs</primary>
      </indexterm></title>

    <para>ACL support for AFP is implemented for ZFS ACLs on Solaris and
    derived platforms and for POSIX 1e ACLs on Linux.</para>

    <sect2>
      <title>Configuration</title>

      <para>For a basic mode of operation there's nothing to configure.
      Netatalk reads ACLs on the fly and calculates effective permissions
      which are then send to the AFP client via the so called
      UARights<indexterm>
          <primary>UARights</primary>
        </indexterm> permission bits. On a Mac, the Finder uses these bits to
      adjust permission in Finder windows. Example: a folder whose UNIX mode
      is read-only and an ACL giving the user write access, will display the
      effective read-write permission. Without the permission mapping the
      Finder would display a read-only icon and the user wouldn't be able to
      write to the folder.</para>

      <para>By default, the effective permission of the authenticated user are
      only mapped to the mentioned UARights<indexterm>
          <primary>UARights</primary>
        </indexterm>permission structure, not the UNIX mode. You can adjust
      this behaviour with the configuration option <link
      linkend="map_acls">map acls</link>.</para>

      <para>However, neither in Finder "Get Info" windows nor in the Terminal
      will you be able to see the ACLs, because of how ACLs in macOS are
      designed. If you want to be able to display ACLs on the client, things
      get more involved as you must then setup both client and server to be
      part on a authentication domain (directory service, e.g. LDAP,
      OpenDirectory). The reason is, that in macOS ACLs are bound to UUIDs,
      not just uid's or gid's. Therefore afpd must be able to map every
      filesystem uid and gid to a UUID so that it can return the server side
      ACLs which are bound to UNIX uid and gid mapped to macOS UUIDs.</para>

      <para>Netatalk can query a directory server using LDAP queries. Either
      the directory server already provides an UUID attribute for user and
      groups (Active Directory, Open Directory) or you reuse an unused
      attribute (or add a new one) to you directory server (e.g.
      OpenLDAP).</para>

      <para>In detail:</para>

      <orderedlist>
        <listitem>
          <para>For Solaris/ZFS: ZFS Volumes</para>

          <para>You should configure a ZFS ACL know for any volume you want to
          use with Netatalk:</para>

          <screen>aclinherit = passthrough
aclmode = passthrough</screen>

          <para>For an explanation of what this knob does and how to apply it,
          check your hosts ZFS documentation (e.g. man zfs).</para>
        </listitem>

        <listitem>
          <para>Authentication Domain</para>

          <para>Your server and the clients must be part of a security
          association where identity data is coming from a common source. ACLs
          in Darwin are based on UUIDs and so is the ACL specification in AFP
          3.2. Therefore your source of identity data has to provide an
          attribute for every user and group where a UUID is stored as a ASCII
          string. In other words:</para>

          <itemizedlist>
            <listitem>
              <para>you need an Open Directory Server or an LDAP server where
              you store UUIDs in some attribute</para>
            </listitem>

            <listitem>
              <para>your clients must be configured to use this server</para>
            </listitem>

            <listitem>
              <para>your server should be configured to use this server via
              nsswitch and PAM</para>
            </listitem>

            <listitem>
              <para>configure Netatalk via the special <link
              linkend="acl_options">LDAP options for ACLs</link> in <link
              linkend="afp.conf.5">afp.conf</link> so that Netatalk is able to
              retrieve the UUID for users and groups via LDAP search
              queries</para>
            </listitem>
          </itemizedlist>
        </listitem>
      </orderedlist>
    </sect2>

    <sect2>
      <title>macOS ACLs</title>

      <para>With Access Control Lists (ACLs), macOS offers a powerful
      extension of the traditional UNIX permissions model. An ACL is an
      ordered list of Access Control Entries (ACEs) explicitly granting or
      denying a set of permissions to a given user or group.</para>

      <para>Unlike UNIX permissions, which are bound to user or group IDs,
      ACLs are tied to UUIDs. For this reason accessing an object's ACL
      requires server and client to use a common directory service which
      translates between UUIDs and user/group IDs.</para>

      <para>ACLs and UNIX permissions interact in a rather simple way. As ACLs
      are optional UNIX permissions act as a default mechanism for access
      control. Changing an objects's UNIX permissions will leave its ACL
      intact and modifying an ACL will never change the object's UNIX
      permissions. While doing access checks, macOS first examines an object's
      ACL evaluating ACEs in order until all requested rights have been
      granted, a requested right has been explicitly denied by an ACE or the
      end of the list has been reached. In case there is no ACL or the
      permissions granted by the ACL are not sufficient to fulfill the
      request, macOS next evaluates the object's UNIX permissions. Therefore
      ACLs always have precedence over UNIX permissions.</para>
    </sect2>

    <sect2>
      <title>ZFS ACLs</title>

      <para>ZFS ACLs closely match macOS ACLs. Both offer mostly identical
      fine grained permissions and inheritance settings.</para>
    </sect2>

    <sect2>
      <title>POSIX ACLs</title>

      <sect3>
        <title>Overview</title>

        <para>Compared to macOS or NFSv4 ACLs, POSIX ACLs represent a
        different, less versatile approach to overcome the limitations of the
        traditional UNIX permissions. Implementations are based on the
        withdrawn POSIX 1003.1e standard.</para>

        <para>The standard defines two types of ACLs. Files and directories
        can have access ACLs which are consulted for access checks.
        Directories can also have default ACLs irrelevant to access checks.
        When a new object is created inside a directory with a default ACL,
        the default ACL is applied to the new object as its access ACL.
        Subdirectories inherit default ACLs from their parent. There are no
        further mechanisms of inheritance control.</para>

        <para>Architectural differences between POSIX ACLs and macOS ACLs
        especially involve:</para>

        <para><itemizedlist>
            <listitem>
              <para>No fine-granular permissions model. Like UNIX permissions
              POSIX ACLs only differentiate between read, write and execute
              permissions.</para>
            </listitem>

            <listitem>
              <para>Entries within an ACL are unordered.</para>
            </listitem>

            <listitem>
              <para>POSIX ACLs can only grant rights. There is no way to
              explicitly deny rights by an entry.</para>
            </listitem>

            <listitem>
              <para>UNIX permissions are integrated into an ACL as special
              entries.</para>
            </listitem>
          </itemizedlist></para>

        <para>POSIX 1003.1e defines 6 different types of ACL entries. The
        first three types are used to integrate standard UNIX permissions.
        They form a minimal ACL, their presence is mandatory and only one
        entry of each type is allowed within an ACL.</para>

        <para><itemizedlist>
            <listitem>
              <para>ACL_USER_OBJ: the owner's access rights.</para>
            </listitem>

            <listitem>
              <para>ACL_GROUP_OBJ: the owning group's access rights.</para>
            </listitem>

            <listitem>
              <para>ACL_OTHER: everybody's access rights.</para>
            </listitem>
          </itemizedlist></para>

        <para>The remaining entry types expand the traditional permissions
        model:</para>

        <para><itemizedlist>
            <listitem>
              <para>ACL_USER: grants access rights to a certain user.</para>
            </listitem>

            <listitem>
              <para>ACL_GROUP: grants access rights to a certain group.</para>
            </listitem>

            <listitem>
              <para>ACL_MASK: limits the maximum access rights which can be
              granted by entries of type ACL_GROUP_OBJ, ACL_USER and
              ACL_GROUP. As the name suggests, this entry acts as a mask. Only
              one ACL_MASK entry is allowed per ACL. If an ACL contains
              ACL_USER or ACL_GROUP entries, an ACL_MASK entry must be present
              too, otherwise it is optional.</para>
            </listitem>
          </itemizedlist></para>

        <para>In order to maintain compatibility with applications not aware
        of ACLs, POSIX 1003.1e changes the semantics of system calls and
        utilities which retrieve or manipulate an object's UNIX permissions.
        In case an object only has a minimal ACL, the group permissions bits
        of the UNIX permissions correspond to the value of the ACL_GROUP_OBJ
        entry.</para>

        <para>However, if the ACL also contains an ACL_MASK entry, the
        behavior of those system calls and utilities is different. The group
        permissions bits of the UNIX permissions correspond to the value of
        the ACL_MASK entry, i. e. calling "chmod g-w" will not only revoke
        write access for the group, but for all entities which have been
        granted write access by ACL_USER or ACL_GROUP entries.</para>
      </sect3>

      <sect3>
        <title>Mapping POSIX ACLs to macOS ACLs</title>

        <para>When a client wants to read an object's ACL, afpd maps its POSIX
        ACL onto an equivalent macOS ACL. Writing an object's ACL requires
        afpd to map an macOS ACL onto a POSIX ACL. Due to architectural
        restrictions of POSIX ACLs, it is usually impossible to find an exact
        mapping so that the result of the mapping process will be an
        approximation of the original ACL's semantic.</para>

        <para><itemizedlist>
            <listitem>
              <para>afpd silently discard entries which deny a set of
              permissions because they they can't be represented within the
              POSIX architecture.</para>
            </listitem>

            <listitem>
              <para>As entries within POSIX ACLs are unordered, it is
              impossible to preserve order.</para>
            </listitem>

            <listitem>
              <para>Inheritance control is subject to severe limitations as
              well:<itemizedlist>
                  <listitem>
                    <para>Entries with the only_inherit flag set will only
                    become part of the directory's default ACL.</para>
                  </listitem>

                  <listitem>
                    <para>Entries with at least one of the flags file_inherit,
                    directory_inherit or limit_inherit set, will become part
                    of the directory's access and default ACL, but the
                    restrictions they impose on inheritance will be
                    ignored.</para>
                  </listitem>
                </itemizedlist></para>
            </listitem>

            <listitem>
              <para>The lack of a fine-granular permission model on the POSIX
              side will normally result in an increase of granted
              permissions.</para>
            </listitem>
          </itemizedlist></para>

        <para>As macOS clients aren't aware of the POSIX 1003.1e specific
        relationship between UNIX permissions and ACL_MASK, afpd does not
        expose this feature to the client to avoid compatibility issues and
        handles *unix permissions and ACLs the same way as Apple's reference
        implementation of AFP does. When an object's UNIX permissions are
        requested, afpd calculates proper group rights and returns the result
        together with the owner's and everybody's access rights to the caller
        via "permissions" and "ua_permissions" members of the FPUnixPrivs
        structure (see Apple Filing Protocol Reference, page 181). Changing an
        object's permissions, afpd always updates ACL_USER_OBJ, ACL_GROUP_OBJ
        and ACL_OTHERS. If an ACL_MASK entry is present too, afpd recalculates
        its value so that the new group rights become effective and existing
        entries of type ACL_USER or ACL_GROUP stay intact.</para>
      </sect3>
    </sect2>
  </sect1>

  <sect1 id="fce">
    <title>Filesystem Change Events<indexterm>
        <primary>FCE</primary>
      </indexterm></title>

    <para>Netatalk includes a nifty filesystem change event (FCE) mechanism
    where afpd processes notify interested listeners about certain filesystem
    event by UDP network datagrams.</para>

    <para>For the format of the UDP packets and for an example C application
    that demonstrates how to use these in a listener, take a look at the
    Netatalk source file <filename>bin/misc/fce.c</filename>.</para>

    <para>The currently supported FCE v1 events are:<itemizedlist>
        <listitem>
          <para>file modification (fmod)</para>
        </listitem>

        <listitem>
          <para>file deletion (fdel)</para>
        </listitem>

        <listitem>
          <para>directory deletion (ddel)</para>
        </listitem>

        <listitem>
          <para>file creation (fcre)</para>
        </listitem>

        <listitem>
          <para>directory creation (dcre)</para>
        </listitem>
      </itemizedlist></para>

    <para>When using FCE v2 you also get:<itemizedlist>
        <listitem>
          <para>file moving (fmov)</para>
        </listitem>

        <listitem>
          <para>directory moving (dmov)</para>
        </listitem>

        <listitem>
          <para>user login (login)</para>
        </listitem>

        <listitem>
          <para>user logout (logout)</para>
        </listitem>
      </itemizedlist></para>

    <para>For details on the available simple configuration options, take a
    look at <filename><link
    linkend="fceconf">afp.conf</link></filename>.</para>
  </sect1>

  <sect1>
    <title id="spotlight">Spotlight<indexterm>
        <primary>Spotlight</primary>
      </indexterm></title>

    <para>Starting with version 3.1 Netatalk supports Spotlight searching.
    Netatalk uses GNOME <ulink
    url="https://projects.gnome.org/tracker/">Tracker</ulink> or its later
    incarnation TinySPARQL/<ulink
    url="https://gnome.pages.gitlab.gnome.org/localsearch/">LocalSearch
    </ulink> as metadata store, indexer and search engine.</para>

    <sect2>
      <title>Configuration</title>

      <para>You can enable Spotlight and indexing either globally or on a per
      volume basis with the <option>spotlight</option> option.</para>

      <warning>
        <para>Once Spotlight is enabled for a single volume, all other volumes
        for which spotlight is disabled won't be searchable at all.</para>
      </warning>

      <para>The <command>dbus-daemon</command> binary has to be installed for
      Spotlight feature. The path to dbus-daemon is determined at compile time
      the dbus-daemon build system option.</para>

      <para>In case the <command>dbus-daemon</command> binary is installed at
      the other path, you must use the global option <option>dbus
      daemon</option> to point to the path, e.g. for Solaris with Tracker from
      OpenCSW:<screen>dbus daemon = /opt/csw/bin/dbus-daemon</screen></para>

      <sect3>
        <title>Limitations and notes</title>

        <itemizedlist>
          <listitem>
            <para>Large filesystems</para>

            <para>Tracker on Linux uses the inotify Kernel filesystem change
            event API for tracking filesystem changes. On large filesystems
            this may be problematic since the inotify API doesn't offer
            recursive directory watches but instead requires that for every
            subdirectory watches must be added individually.</para>

            <para>On Solaris the FEN file event notification system is used.
            It is unknown which limitations and resource consumption this
            Solaris subsystem may have.</para>

            <para>We therefore recommend to disable live filesystem monitoring
            and let Tracker periodically scan filesystems for changes instead,
            see the Tracker configuration options <link
            linkend="enable-monitors">enable-monitors</link> and <link
            linkend="crawling-interval">crawling-interval</link> below.</para>
          </listitem>

          <listitem>
            <para>Indexing home directories</para>

            <para>A known limitation with the current implementation means
            that shared volumes in a user's home directory does not get
            indexed by Spotlight.</para>

            <para>As a workaround, keep the shared volumes you want to have
            indexed elsewhere on the host filesystem.</para>
          </listitem>
        </itemizedlist>
      </sect3>
    </sect2>

    <sect2>
      <title>Using Tracker commandline tools on the server</title>

      <para>Netatalk must be running, commands must be executed as root and
      some environment variables must be set up.</para>

      <para>If the .tracker_profile file does not exist, create it first. If
      you need to make the environment variables persistent, source
      .tracker_profile from /root/.profile. If needed, adjust PREFIX to point
      to the base directory Netatalk is installed to, and replace "/var" with
      the localstate directory configured at compile time. <screen>$ su
      # cat .tracker_profile
      PREFIX="/usr/local"
      export XDG_DATA_HOME="$PREFIX/var/netatalk/"
      export XDG_CACHE_HOME="$PREFIX/var/netatalk/"
      export DBUS_SESSION_BUS_ADDRESS="unix:path=$PREFIX/var/netatalk/spotlight.ipc"
      # . .tracker_profile
      #
      </screen></para>

      <para>When using Tracker from OpenCSW you must also update your
      PATH:<screen># export PATH=/opt/csw/bin:$PATH</screen></para>

      <sect3>
        <title>Common Tracker commands</title>

        <variablelist>
          <varlistentry>
            <term>Querying Tracker status:</term>

            <listitem>
              <screen># tracker daemon</screen>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Stop Tracker:</term>

            <listitem>
              <screen># tracker daemon -t</screen>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Start Tracker:</term>

            <listitem>
              <screen># tracker daemon -s</screen>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Reindex directory:</term>

            <listitem>
              <screen># tracker index -f PATH</screen>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Query Tracker for information about a file or
            directory:</term>

            <listitem>
              <screen># tracker info PATH</screen>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term>Search Tracker:</term>

            <listitem>
              <screen># tracker search QUERY</screen>
            </listitem>
          </varlistentry>
        </variablelist>
      </sect3>

      <sect3>
        <title>Advanced Tracker command line configuration</title>

        <para>Tracker stores its configuration via Gnome dconf backend which
        can be modified with the command <command>gsettings</command>.</para>

        <para>Gnome dconf settings are per-user settings, so, as Netatalk runs
        the Tracker processes as root, the settings are stored in the root
        user context and reading or changing these settings must be performed
        as root and Netatalk must be running (and again the environment must
        be set up as shown above).</para>

        <para><screen># gsettings list-recursively | grep Tracker
org.freedesktop.Tracker.Writeback verbosity 'debug'
...</screen></para>

        <para>The following list describes some important Tracker options and
        their default settings.</para>

        <variablelist>
          <varlistentry>
            <term>org.freedesktop.Tracker.Miner.Files
            index-recursive-directories</term>

            <listitem>
              <para>This option controls which directories Tracker will index.
              Don't change this option manually as it is automatically set by
              Netatalk reflecting the setting of the
              <option>Spotlight</option> option of Netatalk volumes.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term id="enable-monitors">org.freedesktop.Tracker.Miner.Files
            enable-monitors <parameter> true</parameter></term>

            <listitem>
              <para>The value controls whether Tracker watches all configured
              paths for modification. Depending on the filesystem modification
              backend (FAM on Linux, FEN on Solaris), this feature may not
              work as reliable as one might wish, so it may be safer to
              disable it and instead rely on periodic crawling of Tracker
              itself. See also the option <option>crawling-interval
              </option>.</para>
            </listitem>
          </varlistentry>

          <varlistentry>
            <term id="crawling-interval">org.freedesktop.Tracker.Miner.Files
            crawling-interval <parameter>-1</parameter></term>

            <listitem>
              <para>Interval in days to check the filesystem is up to date in
              the database, maximum is 365, default is -1. -2 = crawling is
              disabled entirely, -1 = crawling *may* occur on startup (if not
              cleanly shutdown), 0 = crawling is forced</para>
            </listitem>
          </varlistentry>
        </variablelist>
      </sect3>
    </sect2>

    <sect2>
      <title>Supported metadata attributes</title>

      <para>The following table lists the supported Spotlight metadata
      attributes</para>

      <table>
        <title>Supported Spotlight metadata attributes</title>

        <tgroup cols="2">
          <thead>
            <row>
              <entry align="center">Description</entry>

              <entry align="center">Spotlight Key</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>Name</entry>

              <entry>kMDItemDisplayName, kMDItemFSName</entry>
            </row>

            <row>
              <entry>Document content (full text search)</entry>

              <entry>kMDItemTextContent</entry>
            </row>

            <row>
              <entry>File type</entry>

              <entry>_kMDItemGroupId, kMDItemContentTypeTree</entry>
            </row>

            <row>
              <entry>File modification date</entry>

              <entry>kMDItemFSContentChangeDate,
              kMDItemContentModificationDate,
              kMDItemAttributeChangeDate</entry>
            </row>

            <row>
              <entry>Content Creation date</entry>

              <entry>kMDItemContentCreationDate</entry>
            </row>

            <row>
              <entry>The author, or authors, of the contents of the
              file</entry>

              <entry>kMDItemAuthors, kMDItemCreator</entry>
            </row>

            <row>
              <entry>The name of the country where the item was
              created</entry>

              <entry>kMDItemCountry</entry>
            </row>

            <row>
              <entry>Duration</entry>

              <entry>kMDItemDurationSeconds</entry>
            </row>

            <row>
              <entry>Number of pages</entry>

              <entry>kMDItemNumberOfPages</entry>
            </row>

            <row>
              <entry>Document title</entry>

              <entry>kMDItemTitle</entry>
            </row>

            <row>
              <entry>The width, in pixels, of the contents. For example, the
              image width or the video frame width</entry>

              <entry>kMDItemPixelWidth</entry>
            </row>

            <row>
              <entry>The height, in pixels, of the contents. For example, the
              image height or the video frame height</entry>

              <entry>kMDItemPixelHeight</entry>
            </row>

            <row>
              <entry>The color space model used by the document
              contents</entry>

              <entry>kMDItemColorSpace</entry>
            </row>

            <row>
              <entry>The number of bits per sample</entry>

              <entry>kMDItemBitsPerSample</entry>
            </row>

            <row>
              <entry>Focal length of the lens, in millimeters</entry>

              <entry>kMDItemFocalLength</entry>
            </row>

            <row>
              <entry>ISO speed</entry>

              <entry>kMDItemISOSpeed</entry>
            </row>

            <row>
              <entry>Orientation of the document. Possible values are 0
              (landscape) and 1 (portrait)</entry>

              <entry>kMDItemOrientation</entry>
            </row>

            <row>
              <entry>Resolution width, in DPI</entry>

              <entry>kMDItemResolutionWidthDPI</entry>
            </row>

            <row>
              <entry>Resolution height, in DPI</entry>

              <entry>kMDItemResolutionHeightDPI</entry>
            </row>

            <row>
              <entry>Exposure time, in seconds</entry>

              <entry>kMDItemExposureTimeSeconds</entry>
            </row>

            <row>
              <entry>The composer of the music contained in the audio
              file</entry>

              <entry>kMDItemComposer</entry>
            </row>

            <row>
              <entry>The musical genre of the song or composition</entry>

              <entry>kMDItemMusicalGenre</entry>
            </row>
          </tbody>
        </tgroup>
      </table>

      <sect3>
        <title>References</title>

        <orderedlist>
          <listitem>
            <para><ulink
            url="https://developer.apple.com/documentation/coreservices/mditemref/">MDItem</ulink></para>
          </listitem>

          <listitem>
            <para><ulink
            url="https://gnome.pages.gitlab.gnome.org/tracker/docs/developer/">Tracker</ulink></para>
          </listitem>
        </orderedlist>
      </sect3>
    </sect2>
  </sect1>
</chapter>
