Example #1
0
int namespace_flags_from_string(const char *name, unsigned long *ret) {
        unsigned long flags = 0;
        int r;

        assert_se(ret);

        for (;;) {
                _cleanup_free_ char *word = NULL;
                unsigned long f = 0;
                unsigned i;

                r = extract_first_word(&name, &word, NULL, 0);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                for (i = 0; namespace_flag_map[i].name; i++)
                        if (streq(word, namespace_flag_map[i].name)) {
                                 f = namespace_flag_map[i].flag;
                                 break;
                        }

                if (f == 0)
                        return -EINVAL;

                flags |= f;
        }

        *ret = flags;
        return 0;
}
Example #2
0
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
        const char *wants, *property, *p;
        int r;

        assert(u);
        assert(dev);

        property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
        wants = udev_device_get_property_value(dev, property);
        for (p = wants;;) {
                _cleanup_free_ char *word = NULL, *k = NULL;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
                if (r == 0)
                        return 0;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0)
                        return log_unit_error_errno(u, r, "Failed to add parse %s: %m", property);

                r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k);
                if (r < 0)
                        return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);

                r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true);
                if (r < 0)
                        return log_unit_error_errno(u, r, "Failed to add wants dependency: %m");
        }
}
Example #3
0
int namespace_flag_from_string_many(const char *name, unsigned long *ret) {
        unsigned long flags = 0;
        int r;

        assert_se(ret);

        if (!name) {
                *ret = 0;
                return 0;
        }

        for (;;) {
                _cleanup_free_ char *word = NULL;
                unsigned long f;

                r = extract_first_word(&name, &word, NULL, 0);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                f = namespace_flag_from_string(word);
                if (f == 0)
                        return -EINVAL;

                flags |= f;
        }

        *ret = flags;
        return 0;
}
Example #4
0
int secure_bits_from_string(const char *s) {
        int secure_bits = 0;
        const char *p;
        int r;

        for (p = s;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
                if (r == -ENOMEM)
                        return r;
                if (r <= 0)
                        break;

                if (streq(word, "keep-caps"))
                        secure_bits |= 1 << SECURE_KEEP_CAPS;
                else if (streq(word, "keep-caps-locked"))
                        secure_bits |= 1 << SECURE_KEEP_CAPS_LOCKED;
                else if (streq(word, "no-setuid-fixup"))
                        secure_bits |= 1 << SECURE_NO_SETUID_FIXUP;
                else if (streq(word, "no-setuid-fixup-locked"))
                        secure_bits |= 1 << SECURE_NO_SETUID_FIXUP_LOCKED;
                else if (streq(word, "noroot"))
                        secure_bits |= 1 << SECURE_NOROOT;
                else if (streq(word, "noroot-locked"))
                        secure_bits |= 1 << SECURE_NOROOT_LOCKED;
        }

        return secure_bits;
}
Example #5
0
int get_proc_cmdline_key(const char *key, char **value) {
        _cleanup_free_ char *line = NULL, *ret = NULL;
        bool found = false;
        const char *p;
        int r;

        assert(key);

        r = proc_cmdline(&line);
        if (r < 0)
                return r;

        p = line;
        for (;;) {
                _cleanup_free_ char *word = NULL;
                const char *e;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                /* Filter out arguments that are intended only for the
                 * initrd */
                if (!in_initrd() && startswith(word, "rd."))
                        continue;

                if (value) {
                        e = startswith(word, key);
                        if (!e)
                                continue;

                        r = free_and_strdup(&ret, e);
                        if (r < 0)
                                return r;

                        found = true;
                } else {
                        if (streq(word, key))
                                found = true;
                }
        }

        if (value) {
                *value = ret;
                ret = NULL;
        }

        return found;

}
Example #6
0
static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
        char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
        _cleanup_free_ int *ifis = NULL;
        _cleanup_free_ char *s = NULL;
        size_t allocated = 0, c = 0;
        const char *x;
        int r;

        assert_return(ifindex > 0, -EINVAL);
        assert_return(ret, -EINVAL);

        xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
        r = parse_env_file(path, NEWLINE, key, &s, NULL);
        if (r == -ENOENT)
                return -ENODATA;
        if (r < 0)
                return r;
        if (isempty(s)) {
                *ret = NULL;
                return 0;
        }

        x = s;
        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&x, &word, NULL, 0);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                r = parse_ifindex(word, &ifindex);
                if (r < 0)
                        return r;

                if (!GREEDY_REALLOC(ifis, allocated, c + 1))
                        return -ENOMEM;

                ifis[c++] = ifindex;
        }

        if (!GREEDY_REALLOC(ifis, allocated, c + 1))
                return -ENOMEM;
        ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/

        *ret = ifis;
        ifis = NULL;

        return c;
}
Example #7
0
int parse_cpu_set_and_warn(
                const char *rvalue,
                cpu_set_t **cpu_set,
                const char *unit,
                const char *filename,
                unsigned line,
                const char *lvalue) {

        const char *whole_rvalue = rvalue;
        _cleanup_cpu_free_ cpu_set_t *c = NULL;
        unsigned ncpus = 0;

        assert(lvalue);
        assert(rvalue);

        for (;;) {
                _cleanup_free_ char *word = NULL;
                unsigned cpu;
                int r;

                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
                        return r;
                }
                if (r == 0)
                        break;

                if (!c) {
                        c = cpu_set_malloc(&ncpus);
                        if (!c)
                                return log_oom();
                }

                r = safe_atou(word, &cpu);
                if (r < 0 || cpu >= ncpus) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", rvalue);
                        return -EINVAL;
                }

                CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
        }

        /* On success, sets *cpu_set and returns ncpus for the system. */
        if (c) {
                *cpu_set = c;
                c = NULL;
        }

        return (int) ncpus;
}
Example #8
0
int config_parse_syscall_filter(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        Settings *settings = data;
        bool negative;
        const char *items;
        int r;

        assert(filename);
        assert(lvalue);
        assert(rvalue);

        negative = rvalue[0] == '~';
        items = negative ? rvalue + 1 : rvalue;

        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&items, &word, NULL, 0);
                if (r == 0)
                        break;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
                        return 0;
                }

                if (negative)
                        r = strv_extend(&settings->syscall_blacklist, word);
                else
                        r = strv_extend(&settings->syscall_whitelist, word);
                if (r < 0)
                        return log_oom();
        }

        return 0;
}
Example #9
0
int config_parse_capability(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        uint64_t u = 0, *result = data;
        int r;

        assert(filename);
        assert(lvalue);
        assert(rvalue);

        for (;;) {
                _cleanup_free_ char *word = NULL;
                int cap;

                r = extract_first_word(&rvalue, &word, NULL, 0);
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
                        return 0;
                }
                if (r == 0)
                        break;

                cap = capability_from_name(word);
                if (cap < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability, ignoring: %s", word);
                        continue;
                }

                u |= 1 << ((uint64_t) cap);
        }

        if (u == 0)
                return 0;

        *result |= u;
        return 0;
}
Example #10
0
int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {

        _cleanup_free_ char *line = NULL;
        const char *p;
        int r;

        assert(parse_item);

        r = proc_cmdline(&line);
        if (r < 0)
                return r;

        p = line;
        for (;;) {
                _cleanup_free_ char *word = NULL;
                char *value, *key, *q;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                key = word;

                /* Filter out arguments that are intended only for the initrd */
                q = startswith(word, "rd.");
                if (q) {
                        if (!in_initrd())
                                continue;

                        if (flags & PROC_CMDLINE_STRIP_RD_PREFIX)
                                key = q;
                }

                value = strchr(key, '=');
                if (value)
                        *(value++) = 0;

                r = parse_item(key, value, data);
                if (r < 0)
                        return r;
        }

        return 0;
}
static int condition_test_kernel_command_line(Condition *c) {
        _cleanup_free_ char *line = NULL;
        const char *p;
        bool equal;
        int r;

        assert(c);
        assert(c->parameter);
        assert(c->type == CONDITION_KERNEL_COMMAND_LINE);

        r = proc_cmdline(&line);
        if (r < 0)
                return r;

        equal = !!strchr(c->parameter, '=');
        p = line;

        for (;;) {
                _cleanup_free_ char *word = NULL;
                bool found;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                if (equal)
                        found = streq(word, c->parameter);
                else {
                        const char *f;

                        f = startswith(word, c->parameter);
                        found = f && (*f == '=' || *f == 0);
                }

                if (found)
                        return true;
        }

        return false;
}
int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
                       void *data,
                       bool strip_prefix) {
        _cleanup_free_ char *line = NULL;
        const char *p;
        int r;

        assert(parse_item);

        r = proc_cmdline(&line);
        if (r < 0)
                return r;

        p = line;
        for (;;) {
                _cleanup_free_ char *word = NULL;
                char *value = NULL, *unprefixed;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                /* Filter out arguments that are intended only for the
                 * initrd */
                unprefixed = startswith(word, "rd.");
                if (unprefixed && !in_initrd())
                        continue;

                value = strchr(word, '=');
                if (value)
                        *(value++) = 0;

                r = parse_item(strip_prefix && unprefixed ? unprefixed : word, value, data);
                if (r < 0)
                        return r;
        }

        return 0;
}
Example #13
0
static void check(const char *test, char** expected, bool trailing) {
        int i = 0, r;

        printf("<<<%s>>>\n", test);
        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&test, &word, NULL, EXTRACT_QUOTES);
                if (r == 0) {
                        assert_se(!trailing);
                        break;
                } else if (r < 0) {
                        assert_se(trailing);
                        break;
                }

                assert_se(streq(word, expected[i++]));
                printf("<%s>\n", word);
        }
        assert_se(expected[i] == NULL);
}
Example #14
0
int manager_parse_server_string(Manager *m, ServerType type, const char *string) {
        ServerName *first;
        int r;

        assert(m);
        assert(string);

        first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers;

        if (type == SERVER_FALLBACK)
                 m->have_fallbacks = true;

        for (;;) {
                _cleanup_free_ char *word = NULL;
                bool found = false;
                ServerName *n;

                r = extract_first_word(&string, &word, NULL, 0);
                if (r < 0)
                        return log_error_errno(r, "Failed to parse timesyncd server syntax \"%s\": %m", string);
                if (r == 0)
                        break;

                /* Filter out duplicates */
                LIST_FOREACH(names, n, first)
                        if (streq_ptr(n->string, word)) {
                                found = true;
                                break;
                        }

                if (found)
                        continue;

                r = server_name_new(m, NULL, type, word);
                if (r < 0)
                        return r;
        }

        return 0;
}
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
        int r;

        assert(m);
        assert(string);

        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&string, &word, NULL, 0);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                r = manager_add_dns_server_by_string(m, type, word);
                if (r < 0)
                        log_warning_errno(r, "Failed to add DNS server address '%s', ignoring: %m", word);
        }

        return 0;
}
int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
        int r;

        assert(m);
        assert(string);

        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                r = manager_add_search_domain_by_string(m, word);
                if (r < 0)
                        log_warning_errno(r, "Failed to add search domain '%s', ignoring: %m", word);
        }

        return 0;
}
Example #17
0
                                /* Ignore failure. E.g. 10.M is valid */
                                frac = l2;
                                for (; e < e2; e++)
                                        frac /= 10;
                        }
                }

                e += strspn(e, WHITESPACE);

                for (i = start_pos; i < n_entries; i++)
                        if (startswith(e, table[i].suffix))
                                break;

                if (i >= n_entries)
                        return -EINVAL;

                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
                        return -ERANGE;

                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
                if (tmp > ULLONG_MAX - r)
                        return -ERANGE;

                r += tmp;
                if ((unsigned long long) (uint64_t) r != r)
                        return -ERANGE;

                p = e + strlen(table[i].suffix);

                start_pos = i + 1;

        } while (*p);

        *size = r;

        return 0;
}

#if 0 /* NM_IGNORED */
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
        _cleanup_free_ char *word = NULL;
        unsigned l, u;
        int r;

        assert(lower);
        assert(upper);

        /* Extract the lower bound. */
        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
        if (r < 0)
                return r;
        if (r == 0)
                return -EINVAL;

        r = safe_atou(word, &l);
        if (r < 0)
                return r;

        /* Check for the upper bound and extract it if needed */
        if (!t)
                /* Single number with no dashes. */
                u = l;
        else if (!*t)
                /* Trailing dash is an error. */
                return -EINVAL;
        else {
                r = safe_atou(t, &u);
                if (r < 0)
                        return r;
        }

        *lower = l;
        *upper = u;
        return 0;
}
Example #18
0
/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
static int mount_legacy_cgns_supported(
                const char *dest,
                CGroupUnified unified_requested,
                bool userns,
                uid_t uid_shift,
                uid_t uid_range,
                const char *selinux_apifs_context) {

        _cleanup_set_free_free_ Set *controllers = NULL;
        const char *cgroup_root = "/sys/fs/cgroup", *c;
        int r;

        (void) mkdir_p(cgroup_root, 0755);

        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
        r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
        if (r < 0)
                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
        if (r == 0) {
                _cleanup_free_ char *options = NULL;

                /* When cgroup namespaces are enabled and user namespaces are
                 * used then the mount of the cgroupfs is done *inside* the new
                 * user namespace. We're root in the new user namespace and the
                 * kernel will happily translate our uid/gid to the correct
                 * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
                 * pass uid 0 and not uid_shift to tmpfs_patch_options().
                 */
                r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
                if (r < 0)
                        return log_oom();

                r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
                                  MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
                if (r < 0)
                        return r;
        }

        r = cg_all_unified();
        if (r < 0)
                return r;
        if (r > 0)
                goto skip_controllers;

        r = get_process_controllers(&controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to determine cgroup controllers: %m");

        for (;;) {
                _cleanup_free_ const char *controller = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
                if (r < 0)
                        return r;

                /* When multiple hierarchies are co-mounted, make their
                 * constituting individual hierarchies a symlink to the
                 * co-mount.
                 */
                c = controller;
                for (;;) {
                        _cleanup_free_ char *target = NULL, *tok = NULL;

                        r = extract_first_word(&c, &tok, ",", 0);
                        if (r < 0)
                                return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
                        if (r == 0)
                                break;

                        if (streq(controller, tok))
                                break;

                        target = prefix_root("/sys/fs/cgroup/", tok);
                        if (!target)
                                return log_oom();

                        r = symlink_idempotent(controller, target, false);
                        if (r == -EINVAL)
                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                        if (r < 0)
                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
                }
        }

skip_controllers:
        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
                r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
                if (r < 0)
                        return r;
        }

        r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
        if (r < 0)
                return r;

        if (!userns)
                return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");

        return 0;
}
Example #19
0
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
        struct ethtool_channels ecmd = {
                .cmd = ETHTOOL_GCHANNELS
        };
        struct ifreq ifr = {
                .ifr_data = (void*) &ecmd
        };

        bool need_update = false;
        int r;

        if (*fd < 0) {
                r = ethtool_connect(fd);
                if (r < 0)
                        return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
        }

        strscpy(ifr.ifr_name, IFNAMSIZ, ifname);

        r = ioctl(*fd, SIOCETHTOOL, &ifr);
        if (r < 0)
                return -errno;

        if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
                ecmd.rx_count = channels->rx_count;
                need_update = true;
        }

        if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
                ecmd.tx_count = channels->tx_count;
                need_update = true;
        }

        if (channels->other_count_set && ecmd.other_count != channels->other_count) {
                ecmd.other_count = channels->other_count;
                need_update = true;
        }

        if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
                ecmd.combined_count = channels->combined_count;
                need_update = true;
        }

        if (need_update) {
                ecmd.cmd = ETHTOOL_SCHANNELS;

                r = ioctl(*fd, SIOCETHTOOL, &ifr);
                if (r < 0)
                        return -errno;
        }

        return 0;
}

int config_parse_advertise(const char *unit,
                           const char *filename,
                           unsigned line,
                           const char *section,
                           unsigned section_line,
                           const char *lvalue,
                           int ltype,
                           const char *rvalue,
                           void *data,
                           void *userdata) {
        link_config *config = data;
        const char *p;
        int r;

        assert(filename);
        assert(section);
        assert(lvalue);
        assert(rvalue);
        assert(data);

        if (isempty(rvalue)) {
                /* Empty string resets the value. */
                zero(config->advertise);
                return 0;
        }

        for (p = rvalue;;) {
                _cleanup_free_ char *w = NULL;
                enum ethtool_link_mode_bit_indices mode;

                r = extract_first_word(&p, &w, NULL, 0);
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
                        break;
                }
                if (r == 0)
                        break;

                mode = ethtool_link_mode_bit_from_string(w);
                /* We reuse the kernel provided enum which does not contain negative value. So, the cast
                 * below is mandatory. Otherwise, the check below always passes and access an invalid address. */
                if ((int) mode < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
                        continue;
                }

                config->advertise[mode / 32] |= 1UL << (mode % 32);
        }

        return 0;
}
int config_parse_ip_address_access(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        IPAddressAccessItem **list = data;
        const char *p;
        int r;

        assert(list);

        if (isempty(rvalue)) {
                *list = ip_address_access_free_all(*list);
                return 0;
        }

        p = rvalue;

        for (;;) {
                _cleanup_free_ IPAddressAccessItem *a = NULL;
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&p, &word, NULL, 0);
                if (r == 0)
                        break;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0) {
                        log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
                        break;
                }

                a = new0(IPAddressAccessItem, 1);
                if (!a)
                        return log_oom();

                if (streq(word, "any")) {
                        /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */

                        a->family = AF_INET;
                        LIST_APPEND(items, *list, a);

                        a = new0(IPAddressAccessItem, 1);
                        if (!a)
                                return log_oom();

                        a->family = AF_INET6;

                } else if (is_localhost(word)) {
                        /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */

                        a->family = AF_INET;
                        a->address.in.s_addr = htobe32(0x7f000000);
                        a->prefixlen = 8;
                        LIST_APPEND(items, *list, a);

                        a = new0(IPAddressAccessItem, 1);
                        if (!a)
                                return log_oom();

                        a->family = AF_INET6;
                        a->address.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
                        a->prefixlen = 128;

                } else if (streq(word, "link-local")) {

                        /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */

                        a->family = AF_INET;
                        a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
                        a->prefixlen = 16;
                        LIST_APPEND(items, *list, a);

                        a = new0(IPAddressAccessItem, 1);
                        if (!a)
                                return log_oom();

                        a->family = AF_INET6;
                        a->address.in6 = (struct in6_addr) {
                                .s6_addr32[0] = htobe32(0xfe800000)
                        };
                        a->prefixlen = 64;

                } else if (streq(word, "multicast")) {

                        /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */

                        a->family = AF_INET;
                        a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
                        a->prefixlen = 4;
                        LIST_APPEND(items, *list, a);

                        a = new0(IPAddressAccessItem, 1);
                        if (!a)
                                return log_oom();

                        a->family = AF_INET6;
                        a->address.in6 = (struct in6_addr) {
                                .s6_addr32[0] = htobe32(0xff000000)
                        };
                        a->prefixlen = 8;

                } else {
Example #21
0
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
        struct ethtool_channels ecmd = {
                .cmd = ETHTOOL_GCHANNELS
        };
        struct ifreq ifr = {
                .ifr_data = (void*) &ecmd
        };

        bool need_update = false;
        int r;

        if (*fd < 0) {
                r = ethtool_connect(fd);
                if (r < 0)
                        return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
        }

        strscpy(ifr.ifr_name, IFNAMSIZ, ifname);

        r = ioctl(*fd, SIOCETHTOOL, &ifr);
        if (r < 0)
                return -errno;

        if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
                ecmd.rx_count = channels->rx_count;
                need_update = true;
        }

        if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
                ecmd.tx_count = channels->tx_count;
                need_update = true;
        }

        if (channels->other_count_set && ecmd.other_count != channels->other_count) {
                ecmd.other_count = channels->other_count;
                need_update = true;
        }

        if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
                ecmd.combined_count = channels->combined_count;
                need_update = true;
        }

        if (need_update) {
                ecmd.cmd = ETHTOOL_SCHANNELS;

                r = ioctl(*fd, SIOCETHTOOL, &ifr);
                if (r < 0)
                        return -errno;
        }

        return 0;
}

int config_parse_advertise(const char *unit,
                           const char *filename,
                           unsigned line,
                           const char *section,
                           unsigned section_line,
                           const char *lvalue,
                           int ltype,
                           const char *rvalue,
                           void *data,
                           void *userdata) {
        link_config *config = data;
        NetDevAdvertise mode, a = 0;
        const char *p;
        int r;

        assert(filename);
        assert(section);
        assert(lvalue);
        assert(rvalue);
        assert(data);

        if (isempty(rvalue)) {
                /* Empty string resets the value. */
                config->advertise = 0;
                return 0;
        }

        for (p = rvalue;;) {
                _cleanup_free_ char *w = NULL;

                r = extract_first_word(&p, &w, NULL, 0);
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
                        break;
                }
                if (r == 0)
                        break;

                mode = advertise_from_string(w);
                if (mode == _NET_DEV_ADVERTISE_INVALID) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
                        continue;
                }
                a |= mode;
        }

        config->advertise |= a;

        return 0;
}
Example #22
0
int config_parse_duid_rawdata(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {
        int r, n1, n2, byte;
        char *cbyte;
        const char *pduid = rvalue;
        Manager *m = userdata;
        Network *n = userdata;
        DUIDType duidtype;
        uint16_t dhcp_duid_type = 0;
        uint8_t dhcp_duid[MAX_DUID_LEN];
        size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0;

        assert(filename);
        assert(lvalue);
        assert(rvalue);
        assert(userdata);

        duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type
                                                        : n->duid_type;

        if (duidtype == _DUID_TYPE_INVALID)
                duidtype = DUID_TYPE_RAW;

        switch (duidtype) {
        case DUID_TYPE_LLT:
                /* RawData contains DUID-LLT link-layer address (offset 6) */
                duid_start_offset = 6;
                break;
        case DUID_TYPE_EN:
                /* RawData contains DUID-EN identifier (offset 4) */
                duid_start_offset = 4;
                break;
        case DUID_TYPE_LL:
                /* RawData contains DUID-LL link-layer address (offset 2) */
                duid_start_offset = 2;
                break;
        case DUID_TYPE_UUID:
                /* RawData specifies UUID (offset 0) - fall thru */
        case DUID_TYPE_RAW:
                /* First two bytes of RawData is DUID Type - fall thru */
        default:
                break;
        }

        if (duidtype != DUID_TYPE_RAW)
                dhcp_duid_type = (uint16_t)duidtype;

        /* RawData contains DUID in format " NN:NN:NN... " */
        for (;;) {
                r = extract_first_word(&pduid, &cbyte, ":", 0);
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r,
                                   "Failed to read DUID, ignoring assignment: %s.", rvalue);
                        goto exit;
                }
                if (r == 0)
                        break;
                if ((duid_start_offset + dhcp_duid_len) >= MAX_DUID_LEN) {
                        log_syntax(unit, LOG_ERR, filename, line, 0,
                                   "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
                        goto exit;
                }

                len = strlen(cbyte);
                if ((len == 0) || (len > 2)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0,
                                   "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
                        goto exit;
                }
                n2 = 0;
                n1 = unhexchar(cbyte[0]);
                if (len == 2)
                        n2 = unhexchar(cbyte[1]);
                if ((n1 < 0) || (n2 < 0)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0,
                                   "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue);
                        goto exit;
                }
                byte = (n1 << (4 * (len-1))) | n2;

                /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */
                if ((duidtype == DUID_TYPE_RAW) && (count < 2)) {
                        dhcp_duid_type |= (byte << (8 * (1 - count)));
                        count++;
                        continue;
                }

                dhcp_duid[duid_start_offset + dhcp_duid_len] = byte;
                dhcp_duid_len++;
        }

        if (ltype == DUID_CONFIG_SOURCE_GLOBAL) {
                m->duid_type = duidtype;
                m->dhcp_duid_type = dhcp_duid_type;
                m->dhcp_duid_len = dhcp_duid_len;
                memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
        } else {
                /* DUID_CONFIG_SOURCE_NETWORK */
                n->duid_type = duidtype;
                n->dhcp_duid_type = dhcp_duid_type;
                n->dhcp_duid_len = dhcp_duid_len;
                memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
        }

exit:
        return 0;
}
Example #23
0
int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
        _cleanup_free_ char *line = NULL, *ret = NULL;
        bool found = false;
        const char *p;
        int r;

        /* Looks for a specific key on the kernel command line. Supports two modes:
         *
         * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
         *    is searched, and the value following this is returned in "value".
         *
         * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a
         *    separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
         *    this is also accepted, and "value" is returned as NULL.
         *
         * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
         *
         * In all three cases, > 0 is returned if the key is found, 0 if not. */

        if (isempty(key))
                return -EINVAL;

        if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
                return -EINVAL;

        r = proc_cmdline(&line);
        if (r < 0)
                return r;

        p = line;
        for (;;) {
                _cleanup_free_ char *word = NULL;
                const char *e;

                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                if (r < 0)
                        return r;
                if (r == 0)
                        break;

                /* Automatically filter out arguments that are intended only for the initrd, if we are not in the
                 * initrd. */
                if (!in_initrd() && startswith(word, "rd."))
                        continue;

                if (value) {
                        e = proc_cmdline_key_startswith(word, key);
                        if (!e)
                                continue;

                        if (*e == '=') {
                                r = free_and_strdup(&ret, e+1);
                                if (r < 0)
                                        return r;

                                found = true;

                        } else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
                                found = true;

                } else {
                        if (streq(word, key))
                                found = true;
                }
        }

        if (value)
                *value = TAKE_PTR(ret);

        return found;
}
int config_parse_duid_rawdata(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        DUID *ret = data;
        uint8_t raw_data[MAX_DUID_LEN];
        unsigned count = 0;

        assert(filename);
        assert(lvalue);
        assert(rvalue);
        assert(ret);

        /* RawData contains DUID in format "NN:NN:NN..." */
        for (;;) {
                int n1, n2, len, r;
                uint32_t byte;
                _cleanup_free_ char *cbyte = NULL;

                r = extract_first_word(&rvalue, &cbyte, ":", 0);
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue);
                        return 0;
                }
                if (r == 0)
                        break;
                if (count >= MAX_DUID_LEN) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
                        return 0;
                }

                len = strlen(cbyte);
                if (!IN_SET(len, 1, 2)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
                        return 0;
                }
                n1 = unhexchar(cbyte[0]);
                if (len == 2)
                        n2 = unhexchar(cbyte[1]);
                else
                        n2 = 0;

                if (n1 < 0 || n2 < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue);
                        return 0;
                }

                byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2;
                raw_data[count++] = byte;
        }

        assert_cc(sizeof(raw_data) == sizeof(ret->raw_data));
        memcpy(ret->raw_data, raw_data, count);
        ret->raw_data_len = count;
        return 0;
}
int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
        _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
        DnssdService *s = userdata;
        DnsTxtItem *last = NULL;

        assert(filename);
        assert(lvalue);
        assert(rvalue);
        assert(s);

        if (isempty(rvalue)) {
                /* Flush out collected items */
                s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items);
                return 0;
        }

        txt_data = new0(DnssdTxtData, 1);
        if (!txt_data)
                return log_oom();

        for (;;) {
                _cleanup_free_ char *word = NULL;
                _cleanup_free_ char *key = NULL;
                _cleanup_free_ char *value = NULL;
                _cleanup_free_ void *decoded = NULL;
                size_t length = 0;
                DnsTxtItem *i;
                int r;

                r = extract_first_word(&rvalue, &word, NULL,
                                       EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX);
                if (r == 0)
                        break;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0)
                        return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);

                r = split_pair(word, "=", &key, &value);
                if (r == -ENOMEM)
                        return log_oom();
                if (r == -EINVAL)
                        key = TAKE_PTR(word);

                if (!ascii_is_valid(key)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", key);
                        return -EINVAL;
                }

                switch (ltype) {

                case DNS_TXT_ITEM_DATA:
                        if (value) {
                                r = unbase64mem(value, strlen(value), &decoded, &length);
                                if (r == -ENOMEM)
                                        return log_oom();
                                if (r < 0)
                                        return log_syntax(unit, LOG_ERR, filename, line, r,
                                                          "Invalid base64 encoding, ignoring: %s", value);
                        }

                        r = dnssd_txt_item_new_from_data(key, decoded, length, &i);
                        if (r < 0)
                                return log_oom();
                        break;

                case DNS_TXT_ITEM_TEXT:
                        r = dnssd_txt_item_new_from_string(key, value, &i);
                        if (r < 0)
                                return log_oom();
                        break;

                default:
                        assert_not_reached("Unknown type of Txt config");
                }

                LIST_INSERT_AFTER(items, txt_data->txt, last, i);
                last = i;
        }

        if (!LIST_IS_EMPTY(txt_data->txt)) {
                LIST_PREPEND(items, s->txt_data_items, txt_data);
                txt_data = NULL;
        }

        return 0;
}