]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/util/netatalk_conf.c
Merge remote-tracking branch 'origin/develop' into spotlight
[netatalk.git] / libatalk / util / netatalk_conf.c
index fd7ebfd124777e99af77c2748f4f59ca7814e319..739a6ab939a35f99d7112242249356f17e59ca7a 100644 (file)
@@ -401,8 +401,11 @@ static char *volxlate(const AFPObj *obj,
 /*!
  * check access list
  *
- * this function wants something of the following form:
- * "@group,name,name2,@group2,name3" or "@group name name2 @group2 name3"
+ * this function wants a string consisting of names seperated by comma
+ * or space. Names may be quoted within a pair of quotes. Groups are
+ * denoted by a leading @ symbol.
+ * Example:
+ * user1 user2, user3, @group1 @group2, @group3 "user name1", "@group name1"
  * A NULL argument allows everybody to have access.
  * We return three things:
  *     -1: no list
@@ -411,26 +414,31 @@ static char *volxlate(const AFPObj *obj,
  */
 static int accessvol(const AFPObj *obj, const char *args, const char *name)
 {
-    char buf[MAXPATHLEN + 1], *p;
+    EC_INIT;
+    char *names = NULL, *p;
     struct group *gr;
 
     if (!args)
-        return -1;
+        EC_EXIT_STATUS(-1);
 
-    strlcpy(buf, args, sizeof(buf));
-    if ((p = strtok(buf, ", ")) == NULL) /* nothing, return okay */
-        return -1;
+    EC_NULL_LOG( names = strdup(args) );
+
+    if ((p = strtok_quote(names, ", ")) == NULL) /* nothing, return okay */
+        EC_EXIT_STATUS(-1);
 
     while (p) {
         if (*p == '@') { /* it's a group */
             if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid, obj->ngroups, obj->groups))
-                return 1;
+                EC_EXIT_STATUS(1);
         } else if (strcasecmp(p, name) == 0) /* it's a user name */
-            return 1;
-        p = strtok(NULL, ", ");
+            EC_EXIT_STATUS(1);
+        p = strtok_quote(NULL, ", ");
     }
 
-    return 0;
+EC_CLEANUP:
+    if (names)
+        free(names);
+    EC_EXIT;
 }
 
 static int hostaccessvol(const AFPObj *obj, const char *volname, const char *args)
@@ -562,7 +570,6 @@ static struct vol *creatvol(AFPObj *obj,
 {
     EC_INIT;
     struct vol  *volume = NULL;
-    size_t      current_pathlen, another_pathlen;
     int         i, suffixlen, vlen, tmpvlen, u8mvlen, macvlen;
     char        tmpname[AFPVOL_U8MNAMELEN+1];
     char        path[MAXPATHLEN + 1];
@@ -587,37 +594,26 @@ static struct vol *creatvol(AFPObj *obj,
 
     /* Once volumes are loaded, we never change options again, we just delete em when they're removed from afp.conf */
 
-    /*
-     * Check for duplicated or nested volumes, eg:
-     * /Volumes/name      /Volumes/name     [duplicate], and
-     * /Volumes/name      /Volumes/name/dir [nested], but beware of simple strncmp test:
-     * /Volumes/name      /Volumes/name1    [strncmp match if n=strlen("Volumes/name") -> false positive]
-     */
-    current_pathlen = strlen(path);
     for (struct vol *vol = Volumes; vol; vol = vol->v_next) {
-        another_pathlen = strlen(vol->v_path);
-        if (strncmp(path, vol->v_path, MIN(current_pathlen, another_pathlen)) == 0) {
-            if (current_pathlen == another_pathlen) {
-                LOG(log_error, logtype_afpd, "volume \"%s\" paths is duplicated: \"%s\"", name, path);
-                vol->v_deleted = 0;
-                volume = vol;
-                goto EC_CLEANUP;
-            } else {
-                const char *shorter_path, *longer_path;
-                int shorter_len;
-                if (another_pathlen > current_pathlen) {
-                    shorter_len = current_pathlen;
-                    shorter_path = path;
-                    longer_path = vol->v_path;
-                } else {
-                    shorter_len = another_pathlen;
-                    shorter_path = vol->v_path;
-                    longer_path = path;
-                }
-                if (longer_path[shorter_len] == '/')
-                    LOG(log_info, logtype_afpd, "volume \"%s\" paths are nested: \"%s\" and \"%s\"", name, path, vol->v_path);
-            }
+        if (STRCMP(name, ==, vol->v_localname) && vol->v_deleted) {
+            /* 
+             * reloading config, volume still present, nothing else to do,
+             * we don't change options for volumes once they're loaded
+             */
+            vol->v_deleted = 0;
+            volume = vol;
+            EC_EXIT_STATUS(0);
         }
+        if (STRCMP(path, ==, vol->v_path)) {
+            LOG(log_note, logtype_afpd, "volume \"%s\" path \"%s\" is the same as volumes \"%s\" path",
+                name, path, vol->v_configname);
+            EC_EXIT_STATUS(0);
+        }
+        /*
+         * We could check for nested volume paths here, but
+         * nobody was able to come up with an implementation yet,
+         * that is simple, fast and correct.
+         */
     }
 
     /*
@@ -919,16 +915,16 @@ static struct vol *creatvol(AFPObj *obj,
     initvol_vfs(volume);
 
     /* get/store uuid from file in afpd master*/
-    if (!(pwd) && (volume->v_flags & AFPVOL_TM)) {
-        char *uuid = get_vol_uuid(obj, volume->v_localname);
-        if (!uuid) {
-            LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
-                volume->v_localname);
-        } else {
-            volume->v_uuid = uuid;
-            LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
-                volume->v_localname, volume->v_uuid);
-        }
+    become_root();
+    char *uuid = get_vol_uuid(obj, volume->v_localname);
+    unbecome_root();
+    if (!uuid) {
+        LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
+            volume->v_localname);
+    } else {
+        volume->v_uuid = uuid;
+        LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'",
+            volume->v_localname, volume->v_uuid);
     }
 
     /* no errors shall happen beyond this point because the cleanup would mess the volume chain up */
@@ -939,10 +935,8 @@ static struct vol *creatvol(AFPObj *obj,
 EC_CLEANUP:
     LOG(log_debug, logtype_afpd, "createvol: END: %d", ret);
     if (ret != 0) {
-        if (volume) {
+        if (volume)
             volume_free(volume);
-            free(volume);
-        }
         return NULL;
     }
     return volume;
@@ -1263,12 +1257,14 @@ void volume_unlink(struct vol *volume)
 }
 
 /*!
- * Free all resources allocated in a struct vol, only struct dir *v_root can't be freed
+ * Free all resources allocated in a struct vol in load_volumes()
+ *
+ * Actually opening a volume (afp_openvol()) will allocate additional
+ * ressources which are freed in closevol()
  */
 void volume_free(struct vol *vol)
 {
-    LOG(log_debug, logtype_afpd, "volume_free('%s'): BEGIN", vol->v_localname);
-
+    free(vol->v_configname);
     free(vol->v_localname);
     free(vol->v_u8mname);
     free(vol->v_macname);
@@ -1283,10 +1279,12 @@ void volume_free(struct vol *vol)
     free(vol->v_uuid);
     free(vol->v_cnidserver);
     free(vol->v_cnidport);
+    free(vol->v_preexec);
     free(vol->v_root_preexec);
     free(vol->v_postexec);
+    free(vol->v_root_postexec);
 
-    LOG(log_debug, logtype_afpd, "volume_free: END");
+    free(vol);
 }
 
 /*!
@@ -1315,7 +1313,7 @@ int load_charset(struct vol *vol)
  * @param obj       (r) handle
  * @param delvol_fn (r) callback called for deleted volumes
  */
-int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *))
+int load_volumes(AFPObj *obj)
 {
     EC_INIT;
     int fd = -1;
@@ -1367,12 +1365,24 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *)
 
     EC_ZERO_LOG( readvolfile(obj, pwent) );
 
-    for ( vol = Volumes; vol; vol = vol->v_next ) {
-        if (vol->v_deleted) {
+    struct vol *p, *prevvol;
+
+    vol = Volumes;
+    prevvol = NULL;
+
+    while (vol) {
+        if (vol->v_deleted && !(vol->v_flags & AFPVOL_OPEN)) {
             LOG(log_debug, logtype_afpd, "load_volumes: deleted: %s", vol->v_localname);
-            if (delvol_fn)
-                delvol_fn(obj, vol);
-            vol = Volumes;
+            if (prevvol)
+                prevvol->v_next = vol->v_next;
+            else
+                Volumes = NULL;
+            p = vol->v_next;
+            volume_free(vol);
+            vol = p;
+        } else {
+            prevvol = vol;
+            vol = vol->v_next;
         }
     }
 
@@ -1386,12 +1396,16 @@ EC_CLEANUP:
 
 void unload_volumes(AFPObj *obj)
 {
-    struct vol *vol;
+    struct vol *vol, *p;
 
     LOG(log_debug, logtype_afpd, "unload_volumes: BEGIN");
 
-    for (vol = Volumes; vol; vol = vol->v_next)
+    p = Volumes;
+    while (p) {
+        vol = p;
+        p = vol->v_next;
         volume_free(vol);
+    }
     Volumes = NULL;
     obj->options.volfile.mtime = 0;
     
@@ -1640,6 +1654,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
         options->flags |= OPTION_SHARE_RESERV;
     if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0))
         options->flags |= OPTION_AFP_READ_LOCK;
+    if (iniparser_getboolean(config, INISEC_GLOBAL, "spotlight", 0))
+        options->flags |= OPTION_SPOTLIGHT;
     if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1))
         options->passwdbits |= PASSWD_NOSAVE;
     if (iniparser_getboolean(config, INISEC_GLOBAL, "set password", 0))
@@ -1658,6 +1674,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
     options->k5realm        = iniparser_getstrdup(config, INISEC_GLOBAL, "k5 realm",       NULL);
     options->listen         = iniparser_getstrdup(config, INISEC_GLOBAL, "afp listen",     NULL);
     options->ntdomain       = iniparser_getstrdup(config, INISEC_GLOBAL, "nt domain",      NULL);
+    options->addomain       = iniparser_getstrdup(config, INISEC_GLOBAL, "ad domain",      NULL);
     options->ntseparator    = iniparser_getstrdup(config, INISEC_GLOBAL, "nt separator",   NULL);
     options->mimicmodel     = iniparser_getstrdup(config, INISEC_GLOBAL, "mimic model",    NULL);
     options->adminauthuser  = iniparser_getstrdup(config, INISEC_GLOBAL, "admin auth user",NULL);
@@ -1743,11 +1760,11 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
             LOG(log_debug, logtype_afpd, "Locale charset is '%s'", p);
 #else /* system doesn't have LOCALE support */
             LOG(log_warning, logtype_afpd, "system doesn't have LOCALE support");
-            p = strdup("UTF8");
+            p = "UTF8";
 #endif
         }
         if (strcasecmp(p, "UTF-8") == 0) {
-            p = strdup("UTF8");
+            p = "UTF8";
         }
         options->unixcodepage = strdup(p);
         set_charset_name(CH_UNIX, p);
@@ -1760,7 +1777,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
         options->volcodepage = strdup(options->unixcodepage);
     } else {
         if (strcasecmp(p, "UTF-8") == 0) {
-            p = strdup("UTF8");
+            p = "UTF8";
         }
         options->volcodepage = strdup(p);
     }
@@ -1804,3 +1821,80 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
 EC_CLEANUP:
     EC_EXIT;
 }
+
+#define CONFIG_ARG_FREE(a) do {                     \
+    free(a);                                        \
+    a = NULL;                                       \
+    } while (0);
+
+/* get rid of any allocated afp_option buffers. */
+void afp_config_free(AFPObj *obj)
+{
+    if (obj->options.configfile)
+        CONFIG_ARG_FREE(obj->options.configfile);
+    if (obj->options.sigconffile)
+        CONFIG_ARG_FREE(obj->options.sigconffile);
+    if (obj->options.uuidconf)
+        CONFIG_ARG_FREE(obj->options.uuidconf);
+    if (obj->options.logconfig)
+        CONFIG_ARG_FREE(obj->options.logconfig);
+    if (obj->options.logfile)
+        CONFIG_ARG_FREE(obj->options.logfile);
+    if (obj->options.loginmesg)
+        CONFIG_ARG_FREE(obj->options.loginmesg);
+    if (obj->options.guest)
+        CONFIG_ARG_FREE(obj->options.guest);
+    if (obj->options.extmapfile)
+        CONFIG_ARG_FREE(obj->options.extmapfile);
+    if (obj->options.passwdfile)
+        CONFIG_ARG_FREE(obj->options.passwdfile);
+    if (obj->options.uampath)
+        CONFIG_ARG_FREE(obj->options.uampath);
+    if (obj->options.uamlist)
+        CONFIG_ARG_FREE(obj->options.uamlist);
+    if (obj->options.port)
+        CONFIG_ARG_FREE(obj->options.port);
+    if (obj->options.signatureopt)
+        CONFIG_ARG_FREE(obj->options.signatureopt);
+    if (obj->options.k5service)
+        CONFIG_ARG_FREE(obj->options.k5service);
+    if (obj->options.k5realm)
+        CONFIG_ARG_FREE(obj->options.k5realm);
+    if (obj->options.listen)
+        CONFIG_ARG_FREE(obj->options.listen);
+    if (obj->options.ntdomain)
+        CONFIG_ARG_FREE(obj->options.ntdomain);
+    if (obj->options.addomain)
+        CONFIG_ARG_FREE(obj->options.addomain);
+    if (obj->options.ntseparator)
+        CONFIG_ARG_FREE(obj->options.ntseparator);
+    if (obj->options.mimicmodel)
+        CONFIG_ARG_FREE(obj->options.mimicmodel);
+    if (obj->options.adminauthuser)
+        CONFIG_ARG_FREE(obj->options.adminauthuser);
+    if (obj->options.hostname)
+        CONFIG_ARG_FREE(obj->options.hostname);
+    if (obj->options.k5keytab)
+        CONFIG_ARG_FREE(obj->options.k5keytab);
+    if (obj->options.Cnid_srv)
+        CONFIG_ARG_FREE(obj->options.Cnid_srv);
+    if (obj->options.Cnid_port)
+        CONFIG_ARG_FREE(obj->options.Cnid_port);
+    if (obj->options.fqdn)
+        CONFIG_ARG_FREE(obj->options.fqdn);
+
+    if (obj->options.unixcodepage)
+        CONFIG_ARG_FREE(obj->options.unixcodepage);
+    if (obj->options.maccodepage)
+        CONFIG_ARG_FREE(obj->options.maccodepage);
+    if (obj->options.volcodepage)
+        CONFIG_ARG_FREE(obj->options.volcodepage);
+
+    obj->options.flags = 0;
+    obj->options.passwdbits = 0;
+
+    /* Free everything called from afp_config_parse() */
+    free_extmap();
+    iniparser_freedict(obj->iniconfig);
+    free_charset_names();
+}