]> arthur.barton.de Git - netatalk.git/commitdiff
Merge remote-tracking branch 'origin/branch-netatalk-3-0' into develop
authorRalph Boehme <sloowfranklin@gmail.com>
Mon, 14 Oct 2013 08:49:05 +0000 (10:49 +0200)
committerRalph Boehme <sloowfranklin@gmail.com>
Mon, 14 Oct 2013 08:49:05 +0000 (10:49 +0200)
26 files changed:
NEWS
doc/manpages/man5/afp.conf.5.xml
etc/afpd/afp_config.c
etc/afpd/afp_dsi.c
etc/afpd/afp_mdns.c
etc/afpd/auth.c
etc/afpd/status.c
etc/afpd/uam.c
etc/afpd/uam_auth.h
etc/uams/uams_dhx2_pam.c
etc/uams/uams_dhx2_passwd.c
etc/uams/uams_dhx_pam.c
etc/uams/uams_dhx_passwd.c
etc/uams/uams_gss.c
etc/uams/uams_guest.c
etc/uams/uams_pam.c
etc/uams/uams_passwd.c
etc/uams/uams_pgp.c
etc/uams/uams_randnum.c
include/atalk/afp.h
include/atalk/globals.h
include/atalk/uam.h
libatalk/adouble/ad_open.c
libatalk/dsi/dsi_getsess.c
libatalk/util/netatalk_conf.c
man/man5/afp.conf.5.in

diff --git a/NEWS b/NEWS
index 9fe7aef13eb8258ddd227bedbfcda515fb94f499..7b9fc6b682326abed1993bca7bd5d326a53c0285 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,18 @@ Changes in 3.0.6
 * NEW: Add support for ZFS ACLs on FreeBSD with libsunacl. From FR#83.
 * FIX: Active Directory LDAP queries for ACL support with new options
        "ldap user filter" and "ldap group filter". Bug #526.
+* NEW: Option "vol dbnest", when set to true, the CNID database for
+       a volume is stored in the volume root of a share in a directory
+       .AppleDB like in Netatalk 2. Defaults to false. From FR#84.
+* FIX: Small fix in the DSI tickle handling. Bug #528.
+* UPD: Enhance handling of connection attempts when hitting the
+       connection limit. Bug #529.
+* FIX: Saving from Word to a folder that is a symlink to a folder on
+       another filesystem results in a crash of the afpd process and
+       the save to fail. This happens only if the option
+       "follow symlinks" is enabled. Bug #532.
+* FIX: Disable Kerberos UAM if AFP service principal name can't be
+       evaluated. Fixes bug #531.
 
 Changes in 3.0.5
 ================
index 4b1b14d6fab43cd9b191b1fd3caebc233809664f..150459cd50a5fe66df7addd3cd485a3bc5d5cbb1 100644 (file)
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>vol dbnest = <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G)</type></term>
+
+          <listitem>
+            <para>Setting this option to true brings back Netatalk 2
+            behaviour of storing the CNID database in a folder called
+            .AppleDB inside the volume root of each share.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term>volnamelen = <replaceable>number</replaceable>
           <type>(G)</type></term>
             Setting the option to true causes afpd to follow symlinks on the
             server. symlinks may point outside of the AFP volume, currently
             afpd doesn't do any checks for "wide symlinks".</para>
+            <note>
+              <para>This option will subtly break when the symlinks point
+              across filesystem boundaries.</para>
+            </note>
           </listitem>
         </varlistentry>
 
index 94adb9938e0a668e6988355117cadd4a27323d09..149593431373c52dc3f56a41511cbfb9a4cf220f 100644 (file)
@@ -93,7 +93,7 @@ int configinit(AFPObj *obj)
     int family, s;
     static char interfaddr[NI_MAXHOST];
 
-    auth_load(obj->options.uampath, obj->options.uamlist);
+    auth_load(obj, obj->options.uampath, obj->options.uamlist);
     set_signature(&obj->options);
 #ifdef HAVE_LDAP
     acl_ldap_freeconfig();
index 63d2f286499db68372e57bfa1e285e7fa9273b06..b64d49140f402fc1ddb0f1f0205263563e9808d1 100644 (file)
@@ -322,9 +322,10 @@ static void alarm_handler(int sig _U_)
         return;
     }
 
-    if ((err = pollvoltime(AFPobj)) == 0)
+    if ((err = pollvoltime(AFPobj)) == 0) {
         LOG(log_debug, logtype_afpd, "afp_alarm: sending DSI tickle");
         err = dsi_tickle(AFPobj->dsi);
+    }
     if (err <= 0) {
         if (geteuid() == 0) {
             LOG(log_note, logtype_afpd, "afp_alarm: unauthenticated user, connection problem");
index 3158ce7b7fee9ef3058563309151defdc211b53b..2387edad4f542fbe20acef3acf6fb7cdcf9a5152 100644 (file)
@@ -36,13 +36,13 @@ static pthread_t       poller;
 /*
  * Its easier to use asprintf to set the TXT record values
  */
-#define TXTRecordPrintf(rec, key, args...) {            \
+#define TXTRecordPrintf(rec, key, args, ...) {           \
         char *str;                                      \
         asprintf(&str, args);                           \
         TXTRecordSetValue(rec, key, strlen(str), str);  \
         free(str);                                      \
     }
-#define TXTRecordKeyPrintf(rec, k, var, args...) {      \
+#define TXTRecordKeyPrintf(rec, k, var, args, ...) {     \
         char *key, *str;                                \
         asprintf(&key, k, var);                         \
         asprintf(&str, args);                           \
index dcb36a2ce4701f260273cafeab5a859fd9ab664a..f04404edd2f469af47152fccf96db6ccae7d23e8 100644 (file)
@@ -223,6 +223,11 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi
         return AFPERR_NOTAUTH;
     }
 
+    if (obj->cnx_cnt > obj->cnx_max) {
+        LOG(log_error, logtype_dsi, "login: too many connections, limit: %d", obj->cnx_max);
+        return AFPERR_MAXSESS;
+    }
+
     LOG(log_note, logtype_afpd, "%s Login by %s",
         afp_versions[afp_version_index].av_name, pwd->pw_name);
 
@@ -1013,7 +1018,7 @@ int auth_register(const int type, struct uam_obj *uam)
 }
 
 /* load all of the modules */
-int auth_load(const char *path, const char *list)
+int auth_load(AFPObj *obj, const char *path, const char *list)
 {
     char name[MAXPATHLEN + 1], buf[MAXPATHLEN + 1], *p;
     struct uam_mod *mod;
@@ -1040,7 +1045,7 @@ int auth_load(const char *path, const char *list)
           if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) {
         */
         if (stat(name, &st) == 0) {
-            if ((mod = uam_load(name, p))) {
+            if ((mod = uam_load(obj, name, p))) {
                 uam_attach(&uam_modules, mod);
                 LOG(log_debug, logtype_afpd, "uam: %s loaded", p);
             } else {
index 35e088499db21c56483139df30e3c7b3d5c7f9de..edf744664038965aeb0fffd3f673b587d198d64c 100644 (file)
@@ -311,39 +311,6 @@ static size_t status_netaddress(char *data, int *servoffset,
     return (data - begin);
 }
 
-static bool append_directoryname(char **pdata,
-                                 size_t offset,
-                                 size_t *size,
-                                 char* DirectoryNamesCount,
-                                 size_t len,
-                                 char *principal)
-{
-    if (sizeof(uint8_t) + len  > maxstatuslen - offset - *size) {
-        LOG(log_error, logtype_afpd,
-            "status:DirectoryNames: out of space for principal '%s' (len=%d)",
-            principal, len);
-        return false;
-    } else if (len > 255) {
-        LOG(log_error, logtype_afpd,
-            "status:DirectoryNames: principal '%s' (len=%d) too long (max=255)",
-            principal, len);
-        return false;
-    }
-
-    LOG(log_info, logtype_afpd,
-        "DirectoryNames[%d]=%s",
-        *DirectoryNamesCount, principal);
-
-    *DirectoryNamesCount += 1;
-    char *data = *pdata;
-    *data++ = len;
-    strncpy(data, principal, len);
-
-    *pdata += len + 1;
-    *size += sizeof(uint8_t) + len;
-
-    return true;
-}
 
 /**
  * DirectoryNamesCount offset: uint16_t
@@ -354,7 +321,7 @@ static bool append_directoryname(char **pdata,
 static size_t status_directorynames(char *data,
                                     int *diroffset,
                                     const DSI *dsi _U_,
-                                    const struct afp_options *options _U_)
+                                    const struct afp_options *options)
 {
     char *begin = data;
     uint16_t offset;
@@ -363,130 +330,14 @@ static size_t status_directorynames(char *data,
     offset = ntohs(offset);
     data += offset;
 
-    char *DirectoryNamesCount = data++;
-    size_t size = sizeof(uint8_t);
-    *DirectoryNamesCount = 0;
-
-    if (!uam_gss_enabled())
-        goto offset_calc;
-
-#ifdef HAVE_KERBEROS
-    krb5_context context;
-    krb5_error_code ret;
-    const char *error_msg;
-
-    if (krb5_init_context(&context)) {
-        LOG(log_error, logtype_afpd,
-            "status:DirectoryNames failed to intialize a krb5_context");
-        goto offset_calc;
-    }
-
-    krb5_keytab keytab;
-    if ((ret = krb5_kt_default(context, &keytab)))
-        goto krb5_error;
-
-    // figure out which service principal to use
-    krb5_keytab_entry entry;
-    char *principal;
-    if (options->k5service && options->fqdn && options->k5realm) {
-        LOG(log_debug, logtype_afpd,
-            "status:DirectoryNames: using service principal specified in options");
-
-        krb5_principal service_principal;
-        if ((ret = krb5_build_principal(context,
-                                        &service_principal,
-                                        strlen(options->k5realm),
-                                        options->k5realm,
-                                        options->k5service,
-                                        options->fqdn,
-                                        NULL)))
-            goto krb5_error;
-
-        // try to get the given service principal from keytab
-        ret = krb5_kt_get_entry(context,
-                                keytab,
-                                service_principal,
-                                0, // kvno - wildcard
-                                0, // enctype - wildcard
-                                &entry);
-        if (ret == KRB5_KT_NOTFOUND) {
-            krb5_unparse_name(context, service_principal, &principal);
-            LOG(log_error, logtype_afpd,
-                "status:DirectoryNames: specified service principal '%s' not found in keytab",
-                principal);
-            // XXX: should this be krb5_xfree?
-#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
-            krb5_free_unparsed_name(context, principal);
-#else
-           krb5_xfree(principal);
-#endif
-            goto krb5_cleanup;
-        }
-        krb5_free_principal(context, service_principal);
-        if (ret)
-            goto krb5_error;
+    if (!uam_gss_enabled() || !options->k5principal) {
+        *data = 0;
+        data++;
     } else {
-        LOG(log_debug, logtype_afpd,
-            "status:DirectoryNames: using first entry from keytab as service principal");
-
-        krb5_kt_cursor cursor;
-        if ((ret = krb5_kt_start_seq_get(context, keytab, &cursor)))
-            goto krb5_error;
-
-        ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
-        krb5_kt_end_seq_get(context, keytab, &cursor);
-        if (ret)
-            goto krb5_error;
+        memcpy(data, options->k5principal, options->k5principal_buflen);
+        data += options->k5principal_buflen;
     }
 
-    krb5_unparse_name(context, entry.principal, &principal);
-#ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
-    krb5_free_keytab_entry_contents(context, &entry);
-#elif defined(HAVE_KRB5_KT_FREE_ENTRY)
-    krb5_kt_free_entry(context, &entry);
-#endif
-    append_directoryname(&data,
-                         offset,
-                         &size,
-                         DirectoryNamesCount,
-                         strlen(principal),
-                         principal);
-
-    free(principal);
-    goto krb5_cleanup;
-
-krb5_error:
-    if (ret) {
-        error_msg = krb5_get_error_message(context, ret);
-        LOG(log_note, logtype_afpd, "Can't get principal from default keytab: %s",
-            (char *)error_msg);
-#ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
-        krb5_free_error_message(context, error_msg);
-#else
-       krb5_xfree(error_msg);
-#endif
-    }
-
-krb5_cleanup:
-    krb5_kt_close(context, keytab);
-    krb5_free_context(context);
-#else
-    if (!options->k5service || !options->fqdn || !options->k5realm)
-        goto offset_calc;
-
-    char principal[255];
-    size_t len = snprintf(principal, sizeof(principal), "%s/%s@%s",
-                          options->k5service, options->fqdn, options->k5realm);
-
-    append_directoryname(&data,
-                         offset,
-                         &size,
-                         DirectoryNamesCount,
-                         strlen(principal),
-                         principal);
-#endif // HAVE_KERBEROS
-
-offset_calc:
     /* Calculate and store offset for UTF8ServerName */
     *diroffset += sizeof(uint16_t);
     offset = htons(data - begin);
index 208c9ff234313dd8194a7ac9e488b609b6f9ef99..04e54cbbd2f60c1999337a917412bb4cb87b91d1 100644 (file)
@@ -46,7 +46,7 @@
 /* --- server uam functions -- */
 
 /* uam_load. uams must have a uam_setup function. */
-struct uam_mod *uam_load(const char *path, const char *name)
+struct uam_mod *uam_load(AFPObj *obj, const char *path, const char *name)
 {
     char buf[MAXPATHLEN + 1], *p;
     struct uam_mod *mod;
@@ -82,7 +82,7 @@ struct uam_mod *uam_load(const char *path, const char *name)
     /* version check would go here */
 
     if (!mod->uam_fcn->uam_setup ||
-            ((*mod->uam_fcn->uam_setup)(name) < 0)) {
+        ((*mod->uam_fcn->uam_setup)(obj, name) < 0)) {
         LOG(log_error, logtype_afpd, "uam_load(%s): uam_setup failed", name);
         goto uam_load_err;
     }
index a553ffabff4aaac03c3f787c4e42b77d27c69a39..4eb3bf0464b7251dd89774c7d3109989a62c4603 100644 (file)
@@ -51,11 +51,11 @@ struct uam_obj {
     (a)->uam_next->uam_prev = (a)->uam_prev; \
 } while (0)
 
-extern struct uam_mod *uam_load (const char *, const char *);
+extern struct uam_mod *uam_load (AFPObj *, const char *, const char *);
 extern void uam_unload (struct uam_mod *);
 
 /* auth.c */
-int auth_load (const char *, const char *);
+int auth_load (AFPObj *, const char *, const char *);
 int auth_register (const int, struct uam_obj *);
 #define auth_unregister(a) uam_detach(a)
 struct uam_obj *auth_uamfind (const int, const char *, const int);
index 5229d372433603b810ece221f427e92ed71079ee..8e79b450d4c802e9e6e516c598c2ced645270476 100644 (file)
@@ -923,7 +923,7 @@ static int dhx2_changepw(void *obj _U_, char *uname,
     return ret;
 }
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
     if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHX2", pam_login,
                      pam_logincont, pam_logout, pam_login_ext) < 0)
index a2737d0f920f90b746df9efc8c0495409a7cba7e..b74cc124f7b59cd2127713e90a7ea049db6c24cf 100644 (file)
@@ -603,7 +603,7 @@ static int passwd_logincont(void *obj, struct passwd **uam_pwd,
     return ret;
 }
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
     if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHX2", passwd_login,
                      passwd_logincont, NULL, passwd_login_ext) < 0)
index bc19c7851b294f7eb151f1a384db4c23e23465e5..631f84d9f97ae1c9753549e29ec4a283573fcfbf 100644 (file)
@@ -719,7 +719,7 @@ static int pam_changepw(void *obj, char *username,
 }
 
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128", pam_login, 
                   pam_logincont, pam_logout, pam_login_ext) < 0)
index d390f76b4da29d556fb07bdf559849e3610e9362..e407d9d05f773c392c38214f4ee8376cb4ceff8d 100644 (file)
@@ -371,7 +371,7 @@ static int passwd_logincont(void *obj, struct passwd **uam_pwd,
 }
 
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "DHCAST128",
                   passwd_login, passwd_logincont, NULL, passwd_login_ext) < 0)
index 29ea36c04842ebf85c8aeb87195ad407eb54b952..28ed7444f4ea3bef2ebab93b7d071bef95da8eb3 100644 (file)
@@ -21,6 +21,7 @@
 #include <atalk/uam.h>
 #include <atalk/util.h>
 #include <atalk/compat.h>
+#include <atalk/globals.h>
 
 /* Kerberos includes */
 #ifdef HAVE_GSSAPI_GSSAPI_H
 #include <gssapi.h>
 #endif // HAVE_GSSAPI_GSSAPI_H
 
+#ifdef HAVE_KERBEROS
+#ifdef HAVE_KRB5_KRB5_H
+#include <krb5/krb5.h>
+#else
+#include <krb5.h>
+#endif /* HAVE_KRB5_KRB5_H */
+#endif /* HAVE_KERBEROS */
+
 #define LOG_UAMS(log_level, ...) \
     LOG(log_level, logtype_uams, __VA_ARGS__)
 
@@ -479,8 +488,140 @@ static int gss_login_ext(void *obj,
     return gss_login(obj, uam_pwd, ibuf, ibuflen, rbuf, rbuflen);
 }
 
-static int uam_setup(const char *path)
+static int set_principal(AFPObj *obj, char *principal)
 {
+    size_t len = strlen(principal);
+
+    if (len > 255) {
+        LOG(log_error, logtype_afpd, "set_principal: principal '%s' too long (max=255)", principal, len);
+        return -1;
+    }
+
+    /* We store: 1 byte number principals (1) + 1 byte principal name length + zero terminated principal */
+    if ((obj->options.k5principal = malloc(len + 3)) == NULL) {
+        LOG(log_error, logtype_afpd, "set_principal: OOM");
+        return -1;
+    }
+
+    LOG(log_info, logtype_afpd, "Using AFP Kerberos service principal name: %s", principal);
+
+    obj->options.k5principal[0] = 1;
+    obj->options.k5principal[1] = (unsigned char)len;
+    obj->options.k5principal_buflen = len + 2;
+    strncpy(obj->options.k5principal + 2, principal, len);
+
+    return 0;
+}
+
+static int gss_create_principal(AFPObj *obj)
+{
+    int rv = -1;
+#ifdef HAVE_KERBEROS
+    krb5_context context;
+    krb5_error_code ret;
+    const char *error_msg;
+    krb5_keytab keytab;
+    krb5_keytab_entry entry;
+    krb5_principal service_principal;
+    char *principal;
+    krb5_kt_cursor cursor;
+
+    if (krb5_init_context(&context)) {
+        LOG(log_error, logtype_afpd, "gss_create_principal: failed to intialize a krb5_context");
+        goto exit;
+    }
+    if ((ret = krb5_kt_default(context, &keytab)))
+        goto krb5_error;
+
+    if (obj->options.k5service && obj->options.fqdn && obj->options.k5realm) {
+        LOG(log_debug, logtype_afpd, "gss_create_principal: using service principal specified in options");
+            
+        if ((ret = krb5_build_principal(context,
+                                        &service_principal,
+                                        strlen(obj->options.k5realm),
+                                        obj->options.k5realm,
+                                        obj->options.k5service,
+                                        obj->options.fqdn,
+                                        NULL)))
+            goto krb5_error;
+
+        if ((ret = krb5_kt_get_entry(context,
+                                     keytab,
+                                     service_principal,
+                                     0, // kvno - wildcard
+                                     0, // enctype - wildcard
+                                     &entry)) == KRB5_KT_NOTFOUND) {
+            krb5_unparse_name(context, service_principal, &principal);
+            LOG(log_error, logtype_afpd, "gss_create_principal: specified service principal '%s' not found in keytab", principal);
+#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
+            krb5_free_unparsed_name(context, principal);
+#else
+            krb5_xfree(principal);
+#endif
+            goto krb5_cleanup;
+        }
+        krb5_free_principal(context, service_principal);
+        if (ret)
+            goto krb5_error;
+    } else {
+        LOG(log_debug, logtype_afpd, "gss_create_principal: using first entry from keytab as service principal");
+        if ((ret = krb5_kt_start_seq_get(context, keytab, &cursor)))
+            goto krb5_error;
+        ret = krb5_kt_next_entry(context, keytab, &entry, &cursor);
+        krb5_kt_end_seq_get(context, keytab, &cursor);
+        if (ret)
+            goto krb5_error;
+    }
+
+    krb5_unparse_name(context, entry.principal, &principal);
+#ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
+    krb5_free_keytab_entry_contents(context, &entry);
+#elif defined(HAVE_KRB5_KT_FREE_ENTRY)
+    krb5_kt_free_entry(context, &entry);
+#endif
+    set_principal(obj, principal);
+    free(principal);
+    rv = 0;
+    goto krb5_cleanup;
+
+krb5_error:
+    if (ret) {
+        error_msg = krb5_get_error_message(context, ret);
+        LOG(log_note, logtype_afpd, "Can't get principal from default keytab: %s",
+            (char *)error_msg);
+#ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
+        krb5_free_error_message(context, error_msg);
+#else
+        krb5_xfree(error_msg);
+#endif
+    }
+
+krb5_cleanup:
+    krb5_kt_close(context, keytab);
+    krb5_free_context(context);
+
+#else /* ! HAVE_KERBEROS */
+
+    if (!options->k5service || !options->fqdn || !options->k5realm)
+        goto exit;
+
+    char principal[255];
+    size_t len = snprintf(principal, sizeof(principal), "%s/%s@%s",
+                          options->k5service, options->fqdn, options->k5realm);
+    (void)set_principal(&obj, principal);
+    rv = 0;
+#endif /* HAVE_KERBEROS */
+
+exit:
+    return rv;
+}
+
+static int uam_setup(void *handle, const char *path)
+{
+    AFPObj *obj = (AFPObj *)handle;
+    if (gss_create_principal(obj) != 0)
+        return -1;
+
     return uam_register(UAM_SERVER_LOGIN_EXT, path, "Client Krb v2",
                         gss_login, gss_logincont, gss_logout, gss_login_ext);
 }
index 82ee43ef5d552dc3fe7fc78441942c125a368bd0..baaf9eb2e611560d4360dc713905acb767fc73fd 100644 (file)
@@ -121,7 +121,7 @@ static int noauth_printer(char *start, char *stop, char *username, struct papfil
 }
 
 
-static int uam_setup(const char *path)
+static int uam_setup(void *handle, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "No User Authent",
                    noauth_login, NULL, NULL, noauth_login_ext) < 0)
index b490c2ee20aaf81cd5d5f61888a49a03680e4cc2..da5be62132a0dd073f53abdc880c6f4e2e06faf6 100644 (file)
@@ -445,7 +445,7 @@ static int pam_printer(char *start, char *stop, char *username, struct papfile *
 }
 
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd", 
                   pam_login, NULL, pam_logout, pam_login_ext) < 0)
index bec45a360813bd502affc3a9ac5eed8902f6fae3..9cd738cc08a723e4458b60592c4731212ebd9256 100644 (file)
@@ -353,7 +353,7 @@ static int passwd_printer(char      *start, char *stop, char *username, struct papfil
     return(0);
 }
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
     if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
                      passwd_login, NULL, NULL, passwd_login_ext) < 0)
index 6a2994401c493d5cadd33a5f86161904d17f644c..679a160117770a6d2914b4abbba84cf2cc92451b 100644 (file)
@@ -174,7 +174,7 @@ static int pgp_logincont(void *obj, struct passwd **uam_pwd,
 }
 
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN, path, "PGPuam 1.0",
                   pgp_login, pgp_logincont, NULL) < 0)
index 22687fcc8921cf74304f23791390580c326b8b2e..50ce6ce5fadc05c594be6f541ba2827ce415b363 100644 (file)
@@ -531,7 +531,7 @@ static int randnum_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
     return (rand_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
 }
 
-static int uam_setup(const char *path)
+static int uam_setup(void *obj, const char *path)
 {
   if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Randnum exchange", 
                   randnum_login, randnum_logincont, NULL, randnum_login_ext) < 0)
index 76315aa41acd661b4e7b8b6c8dc454496ce6b38c..0c2489ea906d4d884c1a2b87f41c971db45e26e4 100644 (file)
@@ -49,6 +49,7 @@ typedef uint16_t AFPUserBytes;
 #define AFPSRVRINFO_FASTBOZO     (1<<15) /* fast copying */
 
 #define AFP_OK         0
+#define AFPERR_MAXSESS  -1068   /* maximum number of allowed sessions reached */
 #define AFPERR_DID1     -4000   /* not an afp error DID is 1*/
 #define AFPERR_ACCESS  -5000   /* permission denied */
 #define AFPERR_AUTHCONT        -5001   /* logincont */
index 11a35867b5c160eb1d8cab5f8eba601b597c85e6..b876280860ce015a4f8b703a7269816f61cd6201 100644 (file)
@@ -107,6 +107,8 @@ struct afp_options {
     char *signatureopt;
     unsigned char signature[16];
     char *k5service, *k5realm, *k5keytab;
+    size_t k5principal_buflen;
+    char *k5principal;
     char *unixcodepage, *maccodepage, *volcodepage;
     charset_t maccharset, unixcharset; 
     mode_t umask;
@@ -141,6 +143,7 @@ typedef struct AFPObj {
     gid_t *groups;
     int ngroups;
     int afp_version;
+    int cnx_cnt, cnx_max;
     /* Functions */
     void (*logout)(void);
     void (*exit)(int);
index dcb32e99d2e726b7feaaf67c0799e9454f35de59..d2890e75674cdd0c978fed8c87b575a5567e22b6 100644 (file)
@@ -60,7 +60,7 @@
  * support is braindead. it also allows me to do a little versioning. */
 struct uam_export {
   int uam_type, uam_version;
-  int (*uam_setup)(const char *);
+  int (*uam_setup)(void *, const char *);
   void (*uam_cleanup)(void);
 };
 
index 06c3c71e49a7cfaca6ada37276237d0a4ae66f4f..1708d08b18e8200f35d85bb86698d4424b4e15ae 100644 (file)
@@ -1897,7 +1897,7 @@ int ad_openat(struct adouble  *ad,
     mode_t mode = 0;
 
     if (dirfd != -1) {
-        if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0))
+        if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0))
             EC_FAIL;
     }
 
index a928d34ee38d8f23f9fd34350198d00fffc91e75..89af152b76aa6e312de2d0096002ea8283fec737 100644 (file)
@@ -65,7 +65,7 @@ int dsi_getsession(DSI *dsi, server_child_t *serv_children, int tickleval, afp_c
       LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
       close(ipc_fds[0]);
       dsi->header.dsi_flags = DSIFL_REPLY;
-      dsi->header.dsi_data.dsi_code = DSIERR_SERVBUSY;
+      dsi->header.dsi_data.dsi_code = htonl(DSIERR_SERVBUSY);
       dsi_send(dsi);
       dsi->header.dsi_data.dsi_code = DSIERR_OK;
       kill(pid, SIGKILL);
@@ -75,16 +75,9 @@ int dsi_getsession(DSI *dsi, server_child_t *serv_children, int tickleval, afp_c
     return 0;
   }
   
-  /* child: check number of open connections. this is one off the
-   * actual count. */
-  if ((serv_children->servch_count >= serv_children->servch_nsessions) &&
-      (dsi->header.dsi_command == DSIFUNC_OPEN)) {
-    LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
-    dsi->header.dsi_flags = DSIFL_REPLY;
-    dsi->header.dsi_data.dsi_code = DSIERR_TOOMANY;
-    dsi_send(dsi);
-    exit(EXITERR_CLNT);
-  }
+  /* Save number of existing and maximum connections */
+  dsi->AFPobj->cnx_cnt = serv_children->servch_count;
+  dsi->AFPobj->cnx_max = serv_children->servch_nsessions;
 
   /* get rid of some stuff */
   dsi->AFPobj->ipc_fd = ipc_fds[1];
index d6fb4a17c03a8a681e3644a558bc8b687cd18dac..5ad325693c1ccd46668cee3c560318fb21696920 100644 (file)
@@ -667,11 +667,16 @@ static struct vol *creatvol(AFPObj *obj,
     for(i = 0; i < vlen; i++)
         if(tmpname[i] == '/') tmpname[i] = ':';
 
-    bstring dbpath;
-    EC_NULL( val = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol dbpath", _PATH_STATEDIR "CNID/") );
-    EC_NULL( dbpath = bformat("%s/%s/", val, tmpname) );
-    EC_NULL( volume->v_dbpath = strdup(cfrombstr(dbpath)) );
-    bdestroy(dbpath);
+
+    if (!atalk_iniparser_getboolean(obj->iniconfig, INISEC_GLOBAL, "vol dbnest", 0)) {
+        bstring dbpath;
+        EC_NULL( val = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol dbpath", _PATH_STATEDIR "CNID/") );
+        EC_NULL( dbpath = bformat("%s/%s/", val, tmpname) );
+        EC_NULL( volume->v_dbpath = strdup(cfrombstr(dbpath)) );
+        bdestroy(dbpath);
+    } else {
+        EC_NULL( volume->v_dbpath = strdup(path) );
+    }
 
     if ((val = getoption(obj->iniconfig, section, "cnid scheme", preset, NULL)))
         EC_NULL( volume->v_cnidscheme = strdup(val) );
@@ -1987,6 +1992,8 @@ void afp_config_free(AFPObj *obj)
         CONFIG_ARG_FREE(obj->options.k5service);
     if (obj->options.k5realm)
         CONFIG_ARG_FREE(obj->options.k5realm);
+    if (obj->options.k5principal)
+        CONFIG_ARG_FREE(obj->options.k5principal);
     if (obj->options.listen)
         CONFIG_ARG_FREE(obj->options.listen);
     if (obj->options.interfaces)
index 2cac69d423e9eb0ecc96d254e5ad015c5f26f4fa..74d7a609a0c13f28708c4d7581e2acedd7550c93 100644 (file)
@@ -611,6 +611,11 @@ Sets the database information to be stored in path\&. You have to specify a writ
 @localstatedir@/netatalk/CNID/\&.
 .RE
 .PP
+vol dbnest = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
+.RS 4
+Setting this option to true brings back Netatalk 2 behaviour of storing the CNID database in a folder called \&.AppleDB inside the volume root of each share\&.
+.RE
+.PP
 volnamelen = \fInumber\fR \fB(G)\fR
 .RS 4
 Max length of UTF8\-MAC volume name for Mac OS X\&. Note that Hangul is especially sensitive to this\&.
@@ -1097,6 +1102,21 @@ If this option is set to yes, then Netatalk will attempt to recursively delete a
 follow symlinks = \fIBOOLEAN\fR (default: \fIno\fR) \fB(V)\fR
 .RS 4
 The default setting is false thus symlinks are not followed on the server\&. This is the same behaviour as OS X\*(Aqs AFP server\&. Setting the option to true causes afpd to follow symlinks on the server\&. symlinks may point outside of the AFP volume, currently afpd doesn\*(Aqt do any checks for "wide symlinks"\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
+This option will subtly break when the symlinks point across filesystem boundaries\&.
+.sp .5v
+.RE
 .RE
 .PP
 invisible dots = \fIBOOLEAN\fR (default: \fIno\fR) \fB(V)\fR