Пример #1
0
int config_parse_path(const char *unit,
                      const char *filename,
                      unsigned line,
                      const char *section,
                      const char *lvalue,
                      int ltype,
                      const char *rvalue,
                      void *data,
                      void *userdata) {

        char **s = data;
        char *n;

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

        if (!utf8_is_valid(rvalue)) {
                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                           "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
                return 0;
        }

        if (!path_is_absolute(rvalue)) {
                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                           "Not an absolute path, ignoring: %s", rvalue);
                return 0;
        }

        n = strdup(rvalue);
        if (!n)
                return log_oom();

        path_kill_slashes(n);

        free(*s);
        *s = n;

        return 0;
}
Пример #2
0
bool ConvertString(CString &str, const CString &encodings)
{
    CStringArray lst;
    split(encodings, ",", lst);

    for(unsigned i = 0; i < lst.size(); ++i)
    {
        if( lst[i] == "utf-8" )
        {
            /* Is the string already valid utf-8? */
            if( utf8_is_valid(str) )
                return true;
            continue;
        }
        if( lst[i] == "english" )
        {
            if(AttemptEnglishConversion(str))
                return true;
            continue;
        }

        if( lst[i] == "japanese" )
        {
            if(AttemptJapaneseConversion(str))
                return true;
            continue;
        }

        if( lst[i] == "korean" )
        {
            if(AttemptKoreanConversion(str))
                return true;
            continue;
        }

        RageException::Throw( "Unexpected conversion string \"%s\" (string \"%s\")",
                              lst[i].c_str(), str.c_str() );
    }

    return false;
}
Пример #3
0
int config_parse_string(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) {

        char **s = data;
        char *n;

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

        n = strdup(rvalue);
        if (!n)
                return log_oom();

        if (!utf8_is_valid(n)) {
                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                           "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
                free(n);
                return 0;
        }

        free(*s);
        if (*n)
                *s = n;
        else {
                free(n);
                *s = NULL;
        }

        return 0;
}
Пример #4
0
bool env_value_is_valid(const char *e) {
        if (!e)
                return false;

        if (!utf8_is_valid(e))
                return false;

        /* bash allows tabs in environment variables, and so should
         * we */
        if (string_has_cc(e, "\t"))
                return false;

        /* POSIX says the overall size of the environment block cannot
         * be > ARG_MAX, an individual assignment hence cannot be
         * either. Discounting the shortest possible variable name of
         * length 1, the equal sign and trailing NUL this hence leaves
         * ARG_MAX-3 as longest possible variable value. */
        if (strlen(e) > ARG_MAX - 3)
                return false;

        return true;
}
Пример #5
0
int utf8_luacall_utf8_isvalid(lua_State *l) {
    size_t bufsize;
    if (lua_type(l, 1) != LUA_TSTRING) {
        lua_pushstring(l, "invalid argument #1: not a string");
        return lua_error(l);
    }
    const char *p = luaL_checklstring(l, 1, &bufsize);
    if (!p) {
        lua_pushstring(l, "failed to obtain string buffer");
        return lua_error(l);
    }
    if (bufsize == 0) {
        lua_pushboolean(l, 1);
        return 1;
    }
    if (!utf8_is_valid((unsigned char*) p, bufsize)) {
        lua_pushboolean(l, 0);
        return 1;
    }
    lua_pushboolean(l, 1);
    return 1;
}
Пример #6
0
int config_parse_string(
                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) {

        char **s = data, *n;

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

        if (!utf8_is_valid(rvalue)) {
                log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
                return 0;
        }

        if (isempty(rvalue))
                n = NULL;
        else {
                n = strdup(rvalue);
                if (!n)
                        return log_oom();
        }

        free(*s);
        *s = n;

        return 0;
}
Пример #7
0
TEST(Utf8, Validity)
{
    char *error;

    /* check 8 bits */
    LONGS_EQUAL(0, utf8_has_8bits (NULL));
    LONGS_EQUAL(0, utf8_has_8bits (""));
    LONGS_EQUAL(0, utf8_has_8bits ("abc"));
    LONGS_EQUAL(1, utf8_has_8bits ("no\xc3\xabl"));

    /* check validity */
    LONGS_EQUAL(1, utf8_is_valid (NULL, NULL));
    LONGS_EQUAL(1, utf8_is_valid (NULL, &error));
    LONGS_EQUAL(1, utf8_is_valid ("", NULL));
    LONGS_EQUAL(1, utf8_is_valid ("", &error));
    LONGS_EQUAL(1, utf8_is_valid ("abc", &error));
    POINTERS_EQUAL(NULL, error);
    LONGS_EQUAL(1, utf8_is_valid (noel_valid, &error));
    POINTERS_EQUAL(NULL, error);
    LONGS_EQUAL(0, utf8_is_valid (noel_invalid, &error));
    POINTERS_EQUAL(noel_invalid + 2, error);

    /* 2 bytes: code point must be in range U+0080-07FF */
    LONGS_EQUAL(0, utf8_is_valid ("\xc0\x80", NULL));  /* U+0   */
    LONGS_EQUAL(0, utf8_is_valid ("\xc1\xbf", NULL));  /* U+7F  */
    LONGS_EQUAL(1, utf8_is_valid ("\xc2\x80", NULL));  /* U+80  */
    LONGS_EQUAL(1, utf8_is_valid ("\xdf\xbf", NULL));  /* U+7FF */

    /* 3 bytes: code point must be in range: U+0800-FFFF */
    LONGS_EQUAL(0, utf8_is_valid ("\xe0\x80\x80", NULL));  /* U+0    */
    LONGS_EQUAL(0, utf8_is_valid ("\xe0\x9f\xbf", NULL));  /* U+7FF  */
    LONGS_EQUAL(0, utf8_is_valid ("\xed\xa0\x80", NULL));  /* U+D800 */
    LONGS_EQUAL(0, utf8_is_valid ("\xed\xbf\xbf", NULL));  /* U+DFFF */
    LONGS_EQUAL(1, utf8_is_valid ("\xe0\xa0\x80", NULL));  /* U+800  */
    LONGS_EQUAL(1, utf8_is_valid ("\xed\x9f\xbf", NULL));  /* U+D7FF */
    LONGS_EQUAL(1, utf8_is_valid ("\xe7\x80\x80", NULL));  /* U+E000 */
    LONGS_EQUAL(1, utf8_is_valid ("\xef\xbf\xbf", NULL));  /* U+FFFF */

    /* 4 bytes: code point must be in range: U+10000-1FFFFF */
    LONGS_EQUAL(0, utf8_is_valid ("\xf0\x80\x80\x80", NULL));  /* U+0      */
    LONGS_EQUAL(0, utf8_is_valid ("\xf0\x8f\xbf\xbf", NULL));  /* U+FFFF   */
    LONGS_EQUAL(1, utf8_is_valid ("\xf0\x90\x80\x80", NULL));  /* U+10000  */
    LONGS_EQUAL(1, utf8_is_valid ("\xf7\xbf\xbf\xbf", NULL));  /* U+1FFFFF */
}
Пример #8
0
/* Parse a single logical line */
static int parse_line(
                const char* unit,
                const char *filename,
                unsigned line,
                const char *sections,
                ConfigItemLookup lookup,
                const void *table,
                ConfigParseFlags flags,
                char **section,
                unsigned *section_line,
                bool *section_ignored,
                char *l,
                void *userdata) {

        char *e, *include;

        assert(filename);
        assert(line > 0);
        assert(lookup);
        assert(l);

        l = strstrip(l);
        if (!*l)
                return 0;

        if (strchr(COMMENTS "\n", *l))
                return 0;

        include = first_word(l, ".include");
        if (include) {
                _cleanup_free_ char *fn = NULL;

                /* .includes are a bad idea, we only support them here
                 * for historical reasons. They create cyclic include
                 * problems and make it difficult to detect
                 * configuration file changes with an easy
                 * stat(). Better approaches, such as .d/ drop-in
                 * snippets exist.
                 *
                 * Support for them should be eventually removed. */

                if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
                        return 0;
                }

                log_syntax(unit, LOG_WARNING, filename, line, 0,
                           ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
                           "Please use drop-in files instead.");

                fn = file_in_same_dir(filename, strstrip(include));
                if (!fn)
                        return -ENOMEM;

                return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
        }

        if (!utf8_is_valid(l))
                return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);

        if (*l == '[') {
                size_t k;
                char *n;

                k = strlen(l);
                assert(k > 0);

                if (l[k-1] != ']') {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
                        return -EBADMSG;
                }

                n = strndup(l+1, k-2);
                if (!n)
                        return -ENOMEM;

                if (sections && !nulstr_contains(sections, n)) {

                        if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);

                        free(n);
                        *section = mfree(*section);
                        *section_line = 0;
                        *section_ignored = true;
                } else {
                        free_and_replace(*section, n);
                        *section_line = line;
                        *section_ignored = false;
                }

                return 0;
        }

        if (sections && !*section) {

                if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");

                return 0;
        }

        e = strchr(l, '=');
        if (!e) {
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
                return -EINVAL;
        }

        *e = 0;
        e++;

        return next_assignment(unit,
                               filename,
                               line,
                               lookup,
                               table,
                               *section,
                               *section_line,
                               strstrip(l),
                               strstrip(e),
                               flags,
                               userdata);
}
Пример #9
0
int take_etc_passwd_lock(const char *root) {

        struct flock flock = {
                .l_type = F_WRLCK,
                .l_whence = SEEK_SET,
                .l_start = 0,
                .l_len = 0,
        };

        const char *path;
        int fd, r;

        /* This is roughly the same as lckpwdf(), but not as awful. We
         * don't want to use alarm() and signals, hence we implement
         * our own trivial version of this.
         *
         * Note that shadow-utils also takes per-database locks in
         * addition to lckpwdf(). However, we don't given that they
         * are redundant as they invoke lckpwdf() first and keep
         * it during everything they do. The per-database locks are
         * awfully racy, and thus we just won't do them. */

        if (root)
                path = prefix_roota(root, "/etc/.pwd.lock");
        else
                path = "/etc/.pwd.lock";

        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
        if (fd < 0)
                return -errno;

        r = fcntl(fd, F_SETLKW, &flock);
        if (r < 0) {
                safe_close(fd);
                return -errno;
        }

        return fd;
}

bool valid_user_group_name(const char *u) {
        const char *i;
        long sz;

        /* Checks if the specified name is a valid user/group name. */

        if (isempty(u))
                return false;

        if (!(u[0] >= 'a' && u[0] <= 'z') &&
            !(u[0] >= 'A' && u[0] <= 'Z') &&
            u[0] != '_')
                return false;

        for (i = u+1; *i; i++) {
                if (!(*i >= 'a' && *i <= 'z') &&
                    !(*i >= 'A' && *i <= 'Z') &&
                    !(*i >= '0' && *i <= '9') &&
                    *i != '_' &&
                    *i != '-')
                        return false;
        }

        sz = sysconf(_SC_LOGIN_NAME_MAX);
        assert_se(sz > 0);

        if ((size_t) (i-u) > (size_t) sz)
                return false;

        if ((size_t) (i-u) > UT_NAMESIZE - 1)
                return false;

        return true;
}

bool valid_user_group_name_or_id(const char *u) {

        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
         * range, and not the invalid user ids. */

        if (isempty(u))
                return false;

        if (valid_user_group_name(u))
                return true;

        return parse_uid(u, NULL) >= 0;
}

bool valid_gecos(const char *d) {

        if (!d)
                return false;

        if (!utf8_is_valid(d))
                return false;

        if (string_has_cc(d, NULL))
                return false;

        /* Colons are used as field separators, and hence not OK */
        if (strchr(d, ':'))
                return false;

        return true;
}

bool valid_home(const char *p) {

        if (isempty(p))
                return false;

        if (!utf8_is_valid(p))
                return false;

        if (string_has_cc(p, NULL))
                return false;

        if (!path_is_absolute(p))
                return false;

        if (!path_is_safe(p))
                return false;

        /* Colons are used as field separators, and hence not OK */
        if (strchr(p, ':'))
                return false;

        return true;
}

int maybe_setgroups(size_t size, const gid_t *list) {
        int r;

        /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
        if (size == 0) { /* Dropping all aux groups? */
                _cleanup_free_ char *setgroups_content = NULL;
                bool can_setgroups;

                r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
                if (r == -ENOENT)
                        /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
                        can_setgroups = true;
                else if (r < 0)
                        return r;
                else
                        can_setgroups = streq(setgroups_content, "allow");

                if (!can_setgroups) {
                        log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
                        return 0;
                }
        }

        if (setgroups(size, list) < 0)
                return -errno;

        return 0;
}
Пример #10
0
static int add_locales_from_archive(Set *locales) {
        /* Stolen from glibc... */

        struct locarhead {
                uint32_t magic;
                /* Serial number.  */
                uint32_t serial;
                /* Name hash table.  */
                uint32_t namehash_offset;
                uint32_t namehash_used;
                uint32_t namehash_size;
                /* String table.  */
                uint32_t string_offset;
                uint32_t string_used;
                uint32_t string_size;
                /* Table with locale records.  */
                uint32_t locrectab_offset;
                uint32_t locrectab_used;
                uint32_t locrectab_size;
                /* MD5 sum hash table.  */
                uint32_t sumhash_offset;
                uint32_t sumhash_used;
                uint32_t sumhash_size;
        };

        struct namehashent {
                /* Hash value of the name.  */
                uint32_t hashval;
                /* Offset of the name in the string table.  */
                uint32_t name_offset;
                /* Offset of the locale record.  */
                uint32_t locrec_offset;
        };

        const struct locarhead *h;
        const struct namehashent *e;
        const void *p = MAP_FAILED;
        _cleanup_close_ int fd = -1;
        size_t sz = 0;
        struct stat st;
        size_t i;
        int r;

        fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
        if (fd < 0)
                return errno == ENOENT ? 0 : -errno;

        if (fstat(fd, &st) < 0)
                return -errno;

        if (!S_ISREG(st.st_mode))
                return -EBADMSG;

        if (st.st_size < (off_t) sizeof(struct locarhead))
                return -EBADMSG;

        p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
        if (p == MAP_FAILED)
                return -errno;

        h = (const struct locarhead *) p;
        if (h->magic != 0xde020109 ||
            h->namehash_offset + h->namehash_size > st.st_size ||
            h->string_offset + h->string_size > st.st_size ||
            h->locrectab_offset + h->locrectab_size > st.st_size ||
            h->sumhash_offset + h->sumhash_size > st.st_size) {
                r = -EBADMSG;
                goto finish;
        }

        e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
        for (i = 0; i < h->namehash_size; i++) {
                char *z;

                if (e[i].locrec_offset == 0)
                        continue;

                if (!utf8_is_valid((char*) p + e[i].name_offset))
                        continue;

                z = strdup((char*) p + e[i].name_offset);
                if (!z) {
                        r = -ENOMEM;
                        goto finish;
                }

                r = set_consume(locales, z);
                if (r < 0)
                        goto finish;
        }

        r = 0;

 finish:
        if (p != MAP_FAILED)
                munmap((void*) p, sz);

        return r;
}
Пример #11
0
static void test_utf8_is_valid(void) {
        assert_se(utf8_is_valid("ascii is valid unicode"));
        assert_se(utf8_is_valid("\342\204\242"));
        assert_se(!utf8_is_valid("\341\204"));
}
Пример #12
0
const char *
gui_mouse_event_code2key (const char *code)
{
    int i, x, y, code_utf8, length;
    double diff_x, diff_y, distance, angle, pi4;
    static char key[128];
    const char *ptr_code;

    key[0] = '\0';

    /*
     * mouse code must have at least:
     *   one code (for event) + X + Y == 3 bytes or 3 UTF-8 chars
     */
    code_utf8 = utf8_is_valid (code, NULL);
    length = (code_utf8) ? utf8_strlen (code) : (int)strlen (code);
    if (length < 3)
        return NULL;

    /* get coordinates and button */
    if (code_utf8)
    {
        /* get coordinates using UTF-8 chars in code */
        x = utf8_char_int (code + 1) - 33;
        ptr_code = utf8_next_char (code + 1);
        if (!ptr_code)
            return NULL;
        y = utf8_char_int (ptr_code) - 33;
    }
    else
    {
        /* get coordinates using ISO chars in code */
        x = ((unsigned char)code[1]) - 33;
        y = ((unsigned char)code[2]) - 33;
    }
    if (x < 0)
        x = 0;
    if (y < 0)
        y = 0;

    /* ignore code if it's motion/end code received as first event */
    if ((gui_mouse_event_index == 0)
        && (MOUSE_CODE_MOTION(code[0]) || MOUSE_CODE_END(code[0])))
    {
        return NULL;
    }

    /* set data in "gui_mouse_event_xxx" */
    gui_mouse_event_x[gui_mouse_event_index] = x;
    gui_mouse_event_y[gui_mouse_event_index] = y;
    if (gui_mouse_event_index == 0)
        gui_mouse_event_button = code[0];

    if (gui_mouse_event_index == 0)
        gui_mouse_event_index = 1;

    /*
     * browse wheel codes, if one code is found, return event name immediately
     */
    for (i = 0; gui_mouse_wheel_codes[i][0]; i++)
    {
        if (code[0] == gui_mouse_wheel_codes[i][0][0])
        {
            strcat (key, gui_mouse_wheel_codes[i][1]);
            gui_mouse_event_x[1] = gui_mouse_event_x[0];
            gui_mouse_event_y[1] = gui_mouse_event_y[0];
            return key;
        }
    }

    /* add name of button event */
    for (i = 0; gui_mouse_button_codes[i][0]; i++)
    {
        if (gui_mouse_event_button == gui_mouse_button_codes[i][0][0])
        {
            strcat (key, gui_mouse_button_codes[i][1]);
            break;
        }
    }

    /* nothing found, reset now or mouse will be stuck */
    if (!key[0])
    {
        gui_mouse_event_reset ();
        return NULL;
    }

    if (!MOUSE_CODE_END(code[0]))
    {
        strcat (key, "-event-");
        if (MOUSE_CODE_MOTION(code[0])) {
            strcat (key, "drag");
        }
        else
        {
            gui_mouse_event_x[1] = gui_mouse_event_x[0];
            gui_mouse_event_y[1] = gui_mouse_event_y[0];
            strcat (key, "down");
        }
        return key;
    }

    /*
     * Mouse gesture: if (x,y) on release is different from (x,y) on click,
     * compute distance and angle between 2 points.
     *
     * Distance: sqrt((x2-x1)²+(y2-y1)²)
     * Angle   : atan2(x1-x1, y2-y1)
     *
     * Angle:
     *
     *              3.14             pi
     *               /\
     *       -2.35   ||   2.35       3/4 * pi
     *               ||
     *   -1.57  /----++----\  1.57   1/2 * pi
     *          \----++----/
     *               ||
     *       -0.78   ||   0.78       1/4 * pi
     *               \/
     *              0.00             0
     *
     * Possible returned gestures are:
     *
     *   key name                   | dist. | angle
     *   ---------------------------+-------+--------------------------
     *   buttonX-gesture-up         | 3..19 | -2.35..-3.14 + 2.35..3.14
     *   buttonX-gesture-up-long    | >= 20 |
     *   buttonX-gesture-down       | 3..19 | -0.78..0.78
     *   buttonX-gesture-down-long  | >= 20 |
     *   buttonX-gesture-left       | 3..39 | -0.78..-2.35
     *   buttonX-gesture-left-long  | >= 40 |
     *   buttonX-gesture-right      | 3..39 |  0.78..2.35
     *   buttonX-gesture-right-long | >= 40 |
     */

    if (key[0]
        && ((gui_mouse_event_x[0] != gui_mouse_event_x[1])
            || (gui_mouse_event_y[0] != gui_mouse_event_y[1])))
    {
        diff_x = gui_mouse_event_x[1] - gui_mouse_event_x[0];
        diff_y = gui_mouse_event_y[1] - gui_mouse_event_y[0];
        distance = sqrt ((diff_x * diff_x) + (diff_y * diff_y));
        if (distance >= 3)
        {
            angle = atan2 ((double)(gui_mouse_event_x[1] - gui_mouse_event_x[0]),
                           (double)(gui_mouse_event_y[1] - gui_mouse_event_y[0]));
            pi4 = 3.14159265358979 / 4;
            if ((angle <= pi4 * (-3)) || (angle >= pi4 * 3))
            {
                strcat (key, "-gesture-up");
                if (distance >= 20)
                    strcat (key, "-long");
            }
            else if ((angle >= pi4 * (-1)) && (angle <= pi4))
            {
                strcat (key, "-gesture-down");
                if (distance >= 20)
                    strcat (key, "-long");
            }
            else if ((angle >= pi4 * (-3)) && (angle <= pi4 * (-1)))
            {
                strcat (key, "-gesture-left");
                if (distance >= 40)
                    strcat (key, "-long");
            }
            else if ((angle >= pi4) && (angle <= pi4 * 3))
            {
                strcat (key, "-gesture-right");
                if (distance >= 40)
                    strcat (key, "-long");
            }
        }
    }

    return key;
}
Пример #13
0
int take_etc_passwd_lock(const char *root) {

        struct flock flock = {
                .l_type = F_WRLCK,
                .l_whence = SEEK_SET,
                .l_start = 0,
                .l_len = 0,
        };

        const char *path;
        int fd, r;

        /* This is roughly the same as lckpwdf(), but not as awful. We
         * don't want to use alarm() and signals, hence we implement
         * our own trivial version of this.
         *
         * Note that shadow-utils also takes per-database locks in
         * addition to lckpwdf(). However, we don't given that they
         * are redundant as they invoke lckpwdf() first and keep
         * it during everything they do. The per-database locks are
         * awfully racy, and thus we just won't do them. */

        if (root)
                path = prefix_roota(root, "/etc/.pwd.lock");
        else
                path = "/etc/.pwd.lock";

        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
        if (fd < 0)
                return -errno;

        r = fcntl(fd, F_SETLKW, &flock);
        if (r < 0) {
                safe_close(fd);
                return -errno;
        }

        return fd;
}

bool valid_user_group_name(const char *u) {
        const char *i;
        long sz;

        /* Checks if the specified name is a valid user/group name. */

        if (isempty(u))
                return false;

        if (!(u[0] >= 'a' && u[0] <= 'z') &&
            !(u[0] >= 'A' && u[0] <= 'Z') &&
            u[0] != '_')
                return false;

        for (i = u+1; *i; i++) {
                if (!(*i >= 'a' && *i <= 'z') &&
                    !(*i >= 'A' && *i <= 'Z') &&
                    !(*i >= '0' && *i <= '9') &&
                    *i != '_' &&
                    *i != '-')
                        return false;
        }

        sz = sysconf(_SC_LOGIN_NAME_MAX);
        assert_se(sz > 0);

        if ((size_t) (i-u) > (size_t) sz)
                return false;

        if ((size_t) (i-u) > UT_NAMESIZE - 1)
                return false;

        return true;
}

bool valid_user_group_name_or_id(const char *u) {

        /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
         * range, and not the invalid user ids. */

        if (isempty(u))
                return false;

        if (valid_user_group_name(u))
                return true;

        return parse_uid(u, NULL) >= 0;
}

bool valid_gecos(const char *d) {

        if (!d)
                return false;

        if (!utf8_is_valid(d))
                return false;

        if (string_has_cc(d, NULL))
                return false;

        /* Colons are used as field separators, and hence not OK */
        if (strchr(d, ':'))
                return false;

        return true;
}

bool valid_home(const char *p) {

        if (isempty(p))
                return false;

        if (!utf8_is_valid(p))
                return false;

        if (string_has_cc(p, NULL))
                return false;

        if (!path_is_absolute(p))
                return false;

        if (!path_is_safe(p))
                return false;

        /* Colons are used as field separators, and hence not OK */
        if (strchr(p, ':'))
                return false;

        return true;
}
Пример #14
0
void
gui_key_flush (int paste)
{
    int i, key, last_key_used, insert_ok, undo_done;
    static char key_str[64] = { '\0' };
    static int length_key_str = 0;
    char key_temp[2], *key_utf, *input_old, *ptr_char, *next_char, *ptr_error;
    char utf_partial_char[16];
    struct t_gui_buffer *old_buffer;

    /* if paste pending or bracketed paste detected, just return */
    if (gui_key_paste_pending || gui_key_paste_bracketed)
        return;

    /* if buffer is empty, just return */
    if (gui_key_buffer_size == 0)
        return;

    /*
     * if there's no paste pending, then we use buffer and do actions
     * according to keys
     */
    gui_key_last_activity_time = time (NULL);
    last_key_used = -1;
    undo_done = 0;
    old_buffer = NULL;
    for (i = 0; i < gui_key_buffer_size; i++)
    {
        key = gui_key_buffer[i];
        insert_ok = 1;
        utf_partial_char[0] = '\0';

        if (gui_mouse_event_pending || (key < 32) || (key == 127))
        {
            if (gui_mouse_event_pending)
            {
                insert_ok = 0;
                key_str[0] = (char)key;
                key_str[1] = '\0';
                length_key_str = 1;
            }
            else if (key < 32)
            {
                insert_ok = 0;
                key_str[0] = '\x01';
                key_str[1] = (char)key + '@';
                key_str[2] = '\0';
                length_key_str = 2;
            }
            else if (key == 127)
            {
                key_str[0] = '\x01';
                key_str[1] = '?';
                key_str[2] = '\0';
                length_key_str = 2;
            }
        }
        else
        {
            if (local_utf8)
            {
                key_str[length_key_str] = (char)key;
                key_str[length_key_str + 1] = '\0';
                length_key_str++;

                /*
                 * replace invalid chars by "?", but NOT last char of
                 * string, if it is incomplete UTF-8 char (another char
                 * will be added to the string on next iteration)
                 */
                ptr_char = key_str;
                while (ptr_char && ptr_char[0])
                {
                    (void) utf8_is_valid (ptr_char, -1, &ptr_error);
                    if (!ptr_error)
                        break;
                    next_char = (char *)utf8_next_char (ptr_error);
                    if (next_char && next_char[0])
                    {
                        ptr_char = ptr_error;
                        while (ptr_char < next_char)
                        {
                            ptr_char[0] = '?';
                            ptr_char++;
                        }
                    }
                    else
                    {
                        strcpy (utf_partial_char, ptr_char);
                        ptr_char[0] = '\0';
                        break;
                    }
                    ptr_char = next_char;
                }
            }
            else
            {
                /* convert input to UTF-8 */
                key_temp[0] = (char)key;
                key_temp[1] = '\0';
                key_utf = string_iconv_to_internal (NULL, key_temp);
                strcat (key_str, key_utf);
            }
        }

        if (key_str[0])
        {
            (void) hook_signal_send ("key_pressed",
                                     WEECHAT_HOOK_SIGNAL_STRING, key_str);

            if (gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED)
                input_old = (gui_current_window->buffer->input_buffer) ?
                    strdup (gui_current_window->buffer->input_buffer) : strdup ("");
            else
                input_old = NULL;
            old_buffer = gui_current_window->buffer;

            if ((gui_key_pressed (key_str) != 0) && (insert_ok)
                && (!gui_cursor_mode))
            {
                if (!paste || !undo_done)
                    gui_buffer_undo_snap (gui_current_window->buffer);
                gui_input_insert_string (gui_current_window->buffer,
                                         key_str, -1);
                gui_input_text_changed_modifier_and_signal (gui_current_window->buffer,
                                                            (!paste || !undo_done) ? 1 : 0,
                                                            1); /* stop completion */
                undo_done = 1;
            }

            /* incremental text search in buffer */
            if ((old_buffer == gui_current_window->buffer)
                && (gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED)
                && ((input_old == NULL)
                    || (gui_current_window->buffer->input_buffer == NULL)
                    || (strcmp (input_old, gui_current_window->buffer->input_buffer) != 0)))
            {
                /*
                 * if following conditions are all true, then do not search
                 * again (search will not find any result and can take some time
                 * on a buffer with many lines):
                 * - old search was not successful
                 * - searching a string (not a regex)
                 * - current input is longer than old input
                 * - beginning of current input is exactly equal to old input.
                 */
                if (!gui_current_window->buffer->text_search_found
                    && !gui_current_window->buffer->text_search_regex
                    && (input_old != NULL)
                    && (input_old[0])
                    && (gui_current_window->buffer->input_buffer != NULL)
                    && (gui_current_window->buffer->input_buffer[0])
                    && (strlen (gui_current_window->buffer->input_buffer) > strlen (input_old))
                    && (strncmp (gui_current_window->buffer->input_buffer, input_old,
                                 strlen (input_old)) == 0))
                {
                    /*
                     * do not search text in buffer, just alert about text not
                     * found
                     */
                    if (CONFIG_BOOLEAN(config_look_search_text_not_found_alert))
                    {
                        fprintf (stderr, "\a");
                        fflush (stderr);
                    }
                }
                else
                {
                    gui_window_search_restart (gui_current_window);
                }
            }

            if (input_old)
                free (input_old);
        }

        /* prepare incomplete UTF-8 char for next iteration */
        if (utf_partial_char[0])
            strcpy (key_str, utf_partial_char);
        else
            key_str[0] = '\0';
        length_key_str = strlen (key_str);

        /* set last key used in buffer if combo buffer is empty */
        if (gui_key_grab || gui_mouse_event_pending || !gui_key_combo_buffer[0])
            last_key_used = i;
    }

    if (last_key_used == gui_key_buffer_size - 1)
        gui_key_buffer_reset ();
    else if (last_key_used >= 0)
        gui_key_buffer_remove (0, last_key_used + 1);

    if (!gui_key_grab && !gui_mouse_event_pending)
        gui_key_combo_buffer[0] = '\0';
}
Пример #15
0
int utf8_luacall_utf8_sub(lua_State *l) {
    /// Reimplements lua's sub, but with unicode char indexes (the regular
    /// sub is not unicode aware and supports byte indexes only).
    /// Will throw error for any strings that aren't valid utf-8.
    luaL_checkstack(l, 4, "");
    if (lua_type(l, 1) != LUA_TSTRING) {
        lua_pushstring(l, "invalid argument #1: not a string");
        return lua_error(l);
    }
    if (lua_type(l, 2) != LUA_TNUMBER) {
        lua_pushstring(l, "invalid argument #2: not a number");
        return lua_error(l);
    }
    if (lua_type(l, 3) != LUA_TNUMBER && lua_type(l, 3) != LUA_TNIL
            && lua_type(l, 3) != LUA_TNONE) {
        lua_pushstring(l, "invalid argument #3: not a number");
        return lua_error(l);
    }
    size_t bufsize;
    const unsigned char *buf = (unsigned char*)luaL_checklstring(l, 1,
        &bufsize);
    if (!utf8_is_valid(buf, bufsize)) {
        lua_pushstring(l, "not a valid utf-8 string");
        return lua_error(l);
    }

    // obtain start, end:
    int start = (int)lua_tonumber(l, 2);
    int end = -1;
    if (lua_type(l, 3) == LUA_TNUMBER) {
        end = (int)lua_tonumber(l, 3);
    }
    size_t length = utf8_length(buf, bufsize);
    if (start < 0) {
        start = (length + 1) + start;
    }
    if (end < 0) {
        end = (length + 1) + end;
    }

    // enforce sane limits:
    if (start < 1) {start = 1;}
    if (end > (int)length) {end = length;}
    if (start > (int)length || end < 1 || end < start) {
        // empty string.
        lua_pushstring(l, "");
        return 1;
    }

    // obtain the result:
    UChar32 c;
    size_t startbytepos, endbytepos;
    int currentpos = 1;
    int i = 0;
    while (i < (int)bufsize) {
        if (currentpos == start) {
            startbytepos = i;
        }
        if (currentpos == end) {
            endbytepos = i + 1;
            break;
        }
        U8_NEXT(buf, i, bufsize, c);
        currentpos = currentpos + 1;
    }
    assert(endbytepos > startbytepos);
    char *resultbuf = malloc(1 + endbytepos - startbytepos);
    if (!resultbuf) {
        lua_pushstring(l, "allocation of end result failed");
        return lua_error(l);
    }
    free_later(resultbuf);
    memcpy(resultbuf, buf + startbytepos, endbytepos - startbytepos);
    resultbuf[endbytepos - startbytepos] = 0;
    lua_pushstring(l, resultbuf);
    dont_free_later(resultbuf);
    free(resultbuf);
    return 1;
}