Hi

> Hi!
>> +#include<sys/types.h>
>> +#include<sys/stat.h>
>> +#include<pwd.h>
>> +#include<unistd.h>
>> +#include<stdio.h>
>> +#include<stdlib.h>
>> +#include<string.h>
>> +#include<signal.h>
>> +
>> +#include "test.h"
>> +#include "usctest.h"
>> +#include "safe_macros.h"
>> +
>> +char *TCID = "prot_hsymlinks";
>> +int TST_TOTAL = 396;
>> +
>> +/* create 3 files and 1 dir in each base dir */
>> +#define MAX_FILES_CREATED   4
>> +#define MAX_PATH            128
>> +#define MAX_CMD_LEN         64
>> +#define MAX_USER_NAME               16
>> +
>> +enum {
>> +    ROOT = 0,
>> +    TEST_USER,
>> +    USERS_NUM
>> +};
>> +
>> +#define BASE_DIR_NUM                (USERS_NUM+1)
>> +/*
>> + * max test files and directories
>> + * that will be created during the test
>> + * is't not include symlinks and hardlinks
>> + * and base directories
>> + */
>> +#define MAX_ENTITIES                (MAX_FILES_CREATED*BASE_DIR_NUM)
>> +
>> +struct dir_params {
>> +    char path[MAX_PATH];
>> +    int world_writable;
>> +    int sticky;
>> +    int owner;
>> +};
>> +
>> +static struct dir_params bdirs[BASE_DIR_NUM];
>> +
>> +static const char *file_postfix = ".hs";
> Although postfix is synonym for suffix it is also mailer daenom, name as
> file_suffix or file_ext (as for extension) would be better.
>
>> +enum {
>> +    IS_FILE = 0,
>> +    IS_DIRECTORY,
>> +};
>> +
>> +struct user_file {
>> +    char path[MAX_PATH];
>> +    int is_dir;
>> +};
>> +
>> +struct test_user {
>> +    char name[MAX_USER_NAME];
>> +    struct user_file file[MAX_ENTITIES];
>> +    int num;
>> +};
>> +
>> +static struct test_user users[USERS_NUM];
>> +
>> +struct link_info {
>> +    char path[MAX_PATH];
>> +    int owner;
>> +    int source_owner;
>> +    int in_world_write;
>> +    int in_sticky;
>> +    int is_dir;
>> +    int dir_owner;
>> +};
>> +
>> +/* test flags */
>> +enum {
>> +    CANNOT_FOLLOW = -1,
>> +    CAN_FOLLOW = 0,
>> +};
>> +
>> +enum {
>> +    CANNOT_CREATE = -1,
>> +    CAN_CREATE = 0,
>> +};
>> +
>> +static char *tmp_user_name;
>> +static char *default_user = "hsym";
>> +static int nflag;
>> +static int skip_cleanup;
>> +
>> +option_t options[] = {
>> +    {"u:",&nflag,&tmp_user_name},   /* -u #user name */
>> +    {"s",&skip_cleanup, NULL},
>> +    {NULL, NULL, NULL}
>> +};
>> +/* full length of the test tmpdir path in /tmp */
>> +static int cwd_offset;
>> +
>> +static const char *hrdlink_proc_path        = 
>> "/proc/sys/fs/protected_hardlinks";
>> +static const char *symlink_proc_path        = 
>> "/proc/sys/fs/protected_symlinks";
>> +
>> +static void help(void);
>> +static void setup(int ac, char **av);
>> +static void cleanup(void);
>> +
>> +static void create_test_user(void);
>> +static void delete_test_user(void);
>> +
>> +static int disable_protected_slinks;
>> +static int disable_protected_hlinks;
>> +
>> +/*
>> + * changes links restrictions
>> + * @param value can be:
>> + * 0 - restrictions is off
>> + * 1 - restrictions is on
>> + */
>> +static void switch_protected_slinks(int value);
>> +static void switch_protected_hlinks(int value);
>> +
>> +static int get_protected_slinks(void);
>> +static int get_protected_hlinks(void);
>> +
>> +static void create_link_path(char *buffer, int size, const char *path);
>> +static int create_check_hlinks(const struct user_file *ufile, int 
>> owner_idx);
>> +static int create_check_slinks(const struct user_file *ufile, int 
>> owner_idx);
>> +static int check_symlink(const struct link_info *li);
>> +static int try_fopen(const char *name, int mode);
>> +/* try to open symlink in diff modes */
>> +static int try_symlink(const char *name);
>> +
>> +static int test_run(void);
>> +static void init_base_dirs(void);
>> +static void init_files_dirs(void);
>> +
>> +/* change effective user id and group id by name
>> + * pass NULL to set root
>> + */
>> +static void set_user(const char *name);
>> +
>> +/* add new created files to user struct */
>> +static void ufiles_add(int user_idx, char *path, int type);
>> +
>> +int main(int ac, char **av)
>> +{
>> +    setup(ac, av);
>> +
>> +    test_run();
>> +
>> +    cleanup();
>> +
>> +    tst_exit();
>> +}
>> +
>> +static void setup(int ac, char **av)
>> +{
>> +    char *msg;
>> +    msg = parse_opts(ac, av, options,&help);
>> +    if (msg != NULL)
>> +            tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
>> +
>> +    tst_require_root(NULL);
>> +
>> +    if (tst_kvercmp(3, 7, 0)<  0) {
>> +            tst_brkm(TCONF,&cleanup,
>> +            "Test must be run with kernel 3.7 or newer");
>> +    }
>> +
>> +    /* initialize user names */
>> +    strcpy(users[ROOT].name, "root");
>> +
>> +    if (tmp_user_name == NULL)
>> +            tmp_user_name = default_user;
>> +    snprintf(users[TEST_USER].name, MAX_USER_NAME, "%s", tmp_user_name);
>> +
>> +    tst_sig(FORK, DEF_HANDLER,&cleanup);
>> +
>> +    create_test_user();
>> +    /*
>> +     * enable hardlinks and symlinks restrictions,
>> +     * it's not defualt but have to check
>> +     */
>> +    if (!get_protected_hlinks()) {
>> +        switch_protected_hlinks(1);
>> +        disable_protected_hlinks = 1;
>> +    }
>> +    if (!get_protected_slinks()) {
>> +        switch_protected_slinks(1);
>> +        disable_protected_slinks = 1;
> Use tabs for indentation. And look for lines over 80 chars. Please use
> checkpatch.pl from linux kernel sources to check the patch next time.
I used checkpatch.pl on this code, but considered 80 chars limit as not 
strict warning, I will fix it.
>> +    }
>> +
>> +    init_base_dirs();
>> +
>> +    init_files_dirs();
>> +}
>> +
>> +static int test_run(void)
>> +{
>> +    tst_resm(TINFO, " --- HARDLINKS AND SYMLINKS RESTRICTIONS TEST ---\n");
>> +
>> +    int     result_slink = 0,
>> +            result_hlink = 0,
>> +            owner_idx,
>> +            file_idx;
>> +
>> +    const struct user_file *ufile;
>> +    /*
>> +     * create symlinks and hardlinks from each user's files
>> +     * to each world writable directory
>> +     */
>> +    for (owner_idx = 0; owner_idx<  USERS_NUM; ++owner_idx) {
>> +            /* get all users files and directories */
>> +            for (file_idx = 0; file_idx<  users[owner_idx].num; ++file_idx) 
>> {
>> +                    ufile =&users[owner_idx].file[file_idx];
>> +                    result_slink |= create_check_slinks(ufile, owner_idx);
>> +                    result_hlink |= create_check_hlinks(ufile, owner_idx);
>> +            }
>> +    }
>> +
>> +    /* final results */
>> +    tst_resm(TINFO, "All test-cases have been completed, summary:\n"
>> +            " - symlinks  test:\t%s\n"
>> +            " - hardlinks test:\t%s",
>> +            (result_slink == 1) ? "FAIL" : "PASS",
>> +            (result_hlink == 1) ? "FAIL" : "PASS");
>> +
>> +    return result_slink | result_hlink;
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +    set_user(NULL);
>> +
>> +    if (skip_cleanup)
>> +            return;
>> +
>> +    delete_test_user();
>> +
>> +    if (disable_protected_hlinks) {
>> +            tst_resm(TINFO, "Disable protected hardlinks mode back");
>> +            switch_protected_hlinks(0);
>> +    }
>> +    if (disable_protected_slinks) {
>> +            tst_resm(TINFO, "Disable protected symlinks mode back");
>> +            switch_protected_slinks(0);
>> +    }
>> +
>> +    tst_rmdir();
>> +    TEST_CLEANUP;
>> +}
>> +
>> +static int get_protected_hlinks(void)
>> +{
>> +    int value = 0;
>> +    SAFE_FILE_SCANF(&cleanup, hrdlink_proc_path, "%d",&value);
>> +    return value;
>> +}
>> +
>> +static int get_protected_slinks(void)
>> +{
>> +    int value = 0;
>> +    SAFE_FILE_SCANF(&cleanup, symlink_proc_path, "%d",&value);
>> +    return value;
>> +}
>> +
>> +static void switch_protected_hlinks(int value)
>> +{
>> +    SAFE_FILE_PRINTF(&cleanup, hrdlink_proc_path, "%d", value == 1);
>> +}
>> +
>> +static void switch_protected_slinks(int value)
>> +{
>> +    SAFE_FILE_PRINTF(&cleanup, symlink_proc_path, "%d", value == 1);
>> +}
>> +
>> +static void create_test_user(void)
>> +{
>> +    char cmd[MAX_CMD_LEN];
>> +    snprintf(cmd, MAX_CMD_LEN, "%s %s", "useradd", users[TEST_USER].name);
> You can change the format string to "useradd %s" ;)
that's right :), at first I thought to use it as a function parameter to 
pass "useradd" or "userdel -r"
>> +    if (system(cmd) != 0) {
>> +            tst_brkm(TBROK,&cleanup, "Can't create new user: %s",
>> +                    users[TEST_USER].name);
>> +    }
>> +}
>> +
>> +static void delete_test_user(void)
>> +{
>> +    char cmd[MAX_CMD_LEN];
>> +    snprintf(cmd, MAX_CMD_LEN, "%s %s", "userdel -r", 
>> users[TEST_USER].name);
> Here as well.
>
>> +    if (system(cmd) != 0) {
>> +            tst_brkm(TBROK,&cleanup, "Can't delete user: %s",
>> +                    users[TEST_USER].name);
> You are calling this function from cleanup right? So if this fails the
> cleanup function will be called which would again get to this point and
> call cleanup etc...
>
>> +    }
>> +}
>> +
>> +static void help(void)
>> +{
>> +    printf("  -s      Skip cleanup.\n");
>> +    printf("  -u #user name : Define test user\n");
>> +}
>> +
>> +static void create_sub_dir(const char *path,
>> +    struct dir_params *bdir, mode_t mode)
>> +{
>> +    snprintf(bdir->path, MAX_PATH, "%s/tmp_%s", path, 
>> users[bdir->owner].name);
>> +    SAFE_MKDIR(&cleanup, bdir->path, mode);
>> +
>> +    if (bdir->sticky)
>> +        mode |= S_ISVTX;
>> +    chmod(bdir->path, mode);
>> +}
>> +
>> +static void init_base_dirs(void)
>> +{
>> +    memset(&bdirs, 0, sizeof(bdirs));
> Again bdirs is global variable and as such is initialized to zero
> automatically.
>
>> +    /* create main dir, world-writable */
>> +    tst_tmpdir();
> It is customary to call this function in setup, so that everyone knows
> the test creates temporary directory.
>
>> +    char *cwd = get_tst_tmpdir();
>> +    cwd_offset = strlen(cwd);
>> +
>> +    mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
>> +    chmod(cwd, mode);
>> +
>> +    struct dir_params *bdir = bdirs;
>> +    strcpy(bdir->path, cwd);
>> +    free(cwd);
> Do you really need the global path to the tst tmp dir? The call to
> tst_tmpdir() changes your CWD to it, so at least the subdirs could be
> created with local paths.
It's simplify hardlinks and symlinks creation, otherwise I have to 
construct relative paths that a bit more complicated.
Also, some test-cases can be added to deal with files which are outside 
of test tmpdir.
>> +    bdir->sticky  = 0;
>> +    bdir->world_writable = 1;
>> +
>> +    /* create subdir for each user */
>> +    ++bdir;
>> +    int idx;
>> +    for (idx = 0; idx<  USERS_NUM; ++idx, ++bdir) {
>> +            set_user(users[idx].name);
>> +
>> +            bdir->sticky  = 1;
>> +            bdir->world_writable = 1;
>> +            bdir->owner = idx;
>> +
>> +            create_sub_dir(bdirs[0].path, bdir, mode);
>> +    }
>> +}
>> +
>> +static void init_files_dirs(void)
>> +{
>> +    int i, owner_idx;
>> +    /* create all other dirs and files */
>> +    const struct dir_params *bdir = bdirs;
>> +    for (i = 0; i<  ARRAY_SIZE(bdirs); ++i, ++bdir) {
>> +            for (owner_idx = 0; owner_idx<  USERS_NUM; ++owner_idx) {
>> +                    set_user(users[owner_idx].name);
>> +                    char path[MAX_PATH];
>> +
>> +                    /* create file in the main directory */
>> +                    snprintf(path, MAX_PATH, "%s/%s%s",
>> +                            bdir->path, users[owner_idx].name, 
>> file_postfix);
>> +                    ufiles_add(owner_idx, path, IS_FILE);
>> +
>> +                    /* create file with S_IWOTH bit set */
>> +                    strcat(path, "_w");
>> +                    ufiles_add(owner_idx, path, IS_FILE);
>> +
>> +                    chmod(path, S_IRUSR | S_IRGRP | S_IWOTH | S_IROTH);
>> +
>> +                    /* create sub directory */
>> +                    snprintf(path, MAX_PATH, "%s/%s", bdir->path,
>> +                            users[owner_idx].name);
>> +                    ufiles_add(owner_idx, path, IS_DIRECTORY);
>> +
>> +                    /* create local file inside sub directory */
>> +                    snprintf(path + strlen(path), MAX_PATH - strlen(path),
>> +                            "/local_%s%s", users[owner_idx].name, 
>> file_postfix);
>> +                    ufiles_add(owner_idx, path, IS_FILE);
>> +            }
>> +    }
>> +}
>> +
>> +static void ufiles_add(int user_idx, char *path, int type)
>> +{
>> +    int file_idx = users[user_idx].num;
>> +
>> +    if (file_idx>= MAX_ENTITIES)
>> +            tst_brkm(TBROK,&cleanup, "Unexpected number of files");
>> +
>> +    struct user_file *ufile =&users[user_idx].file[file_idx];
>> +
>> +    if (type == IS_FILE)
>> +            SAFE_CREAT(&cleanup, path, 0644);
>> +    else
>> +            SAFE_MKDIR(&cleanup, path, 0755);
>> +
>> +    strcpy(ufile->path, path);
>> +
>> +    ufile->is_dir = (type == IS_DIRECTORY);
>> +    ++users[user_idx].num;
>> +}
>> +
>> +static void create_link_path(char *buffer, int size, const char *path)
>> +{
>> +    /* to make sure name is unique */
>> +    static int count;
>> +    ++count;
>> +
>> +    /* construct link name */
>> +    snprintf(buffer, size, "%s/link_%d", path, count);
>> +}
>> +
>> +static int create_check_slinks(const struct user_file *ufile, int owner_idx)
>> +{
>> +    int result = 0;
>> +    int i, user_idx;
>> +
>> +    const struct dir_params *bdir = bdirs;
>> +    for (i = 0; i<  ARRAY_SIZE(bdirs); ++i, ++bdir) {
>> +            for (user_idx = 0; user_idx<  USERS_NUM; ++user_idx) {
>> +                    /* set user who will create symlink */
>> +                    set_user(users[user_idx].name);
>> +
>> +                    struct link_info slink_info;
>> +                    create_link_path(slink_info.path, MAX_PATH, bdir->path);
>> +
>> +                    slink_info.owner = user_idx;
>> +                    slink_info.source_owner = owner_idx;
>> +                    slink_info.in_world_write = bdir->world_writable;
>> +                    slink_info.in_sticky = bdir->sticky;
>> +                    slink_info.dir_owner = bdir->owner;
>> +
>> +                    if (symlink(ufile->path, slink_info.path) == -1) {
>> +                            tst_brkm(TBROK,&cleanup, "Can't create symlink: 
>> %s",
>> +                                    slink_info.path);
>> +                    }
>> +                    result |= check_symlink(&slink_info);
>> +            }
>> +    }
>> +    return result;
>> +}
>> +
>> +static int create_check_hlinks(const struct user_file *ufile, int owner_idx)
>> +{
>> +    int result = 0;
>> +    int i, user_idx;
>> +    const struct dir_params *bdir = bdirs;
>> +    for (i = 0; i<  ARRAY_SIZE(bdirs); ++i, ++bdir) {
>> +            for (user_idx = 0; user_idx<  USERS_NUM; ++user_idx) {
>> +                    /* can't create hardlink to directory */
>> +                    if (ufile->is_dir)
>> +                            continue;
>> +                    /* set user who will create hardlink */
>> +                    set_user(users[user_idx].name);
>> +
>> +                    struct link_info hlink_info;
>> +                    create_link_path(hlink_info.path, MAX_PATH, bdir->path);
>> +
>> +                    int can_write = try_fopen(ufile->path, O_WRONLY) == 0;
>> +
>> +                    int tst_flag = (can_write || user_idx == owner_idx ||
>> +                            user_idx == ROOT) ? CAN_CREATE : CANNOT_CREATE;
>> +
>> +                    int fail = tst_flag != link(ufile->path, 
>> hlink_info.path);
>> +
>> +                    result |= fail;
>> +                    tst_resm((fail) ? TFAIL : TPASS,
>> +                            "Expect: %s create hardlink \"...%s\" to 
>> \"...%s\", "
>> +                            "owner \"%s\", curr.user \"%s\", w(%d)",
>> +                            (tst_flag == CAN_CREATE) ? "can" : "can't",
>> +                            ufile->path + cwd_offset,
>> +                            hlink_info.path + cwd_offset,
>> +                            users[owner_idx].name, users[user_idx].name,
>> +                            can_write);
>> +            }
>> +    }
>> +    return result;
>> +}
>> +
>> +static int check_symlink(const struct link_info *li)
>> +{
>> +    int symlink_result = 0;
>> +    int user_idx;
>> +    for (user_idx = 0; user_idx<  USERS_NUM; ++user_idx) {
>> +            set_user(users[user_idx].name);
>> +            int tst_flag = (user_idx == li->dir_owner&&
>> +                    li->in_world_write&&  li->in_sticky&&
>> +                    user_idx != li->owner) ? CANNOT_FOLLOW : CAN_FOLLOW;
>> +
>> +            int fail = tst_flag != try_symlink(li->path);
>> +
>> +            symlink_result |= fail;
>> +
>> +            tst_resm((fail) ? TFAIL : TPASS,
>> +                    "Expect: %s follow symlink \"...%s\", "
>> +                    "owner \"%s\", src.owner \"%s\", "
>> +                    "curr.user \"%s\", dir.owner \"%s\"",
>> +                    (tst_flag == CAN_FOLLOW) ? "can" : "can't",
>> +                    li->path + cwd_offset, users[li->owner].name,
>> +                    users[li->source_owner].name, users[user_idx].name,
>> +                    users[li->dir_owner].name);
>> +    }
> If you use simple quotes you don't have to escape then in the format
> string such as: "Failed to find usere '%s'"
>
>> +    return symlink_result;
>> +}
>> +
>> +/* differenet modes to try in the test */
>> +static const int o_modes[] = {
>> +    O_RDONLY,
>> +    O_WRONLY,
>> +    O_RDWR,
>> +    O_RDONLY | O_NONBLOCK | O_DIRECTORY,
>> +};
>> +
>> +static int try_symlink(const char *name)
>> +{
>> +    int i;
>> +    for (i = 0; i<  ARRAY_SIZE(o_modes); ++i) {
>> +            if (try_fopen(name, o_modes[i]) != -1)
>> +                    return CAN_FOLLOW;
>> +    }
>> +
>> +    return CANNOT_FOLLOW;
>> +}
>> +
>> +static int try_fopen(const char *name, int mode)
>> +{
>> +    int fd = open(name, mode);
>> +
>> +    if (fd == -1)
>> +            return fd;
>> +
>> +    if (close(fd) == -1)
>> +            tst_brkm(TBROK,&cleanup, "Can't close file: %s", name);
>> +
>> +    return 0;
>> +}
> This function name is confusing, it has fopen in name but calls open.
>
>> +static void set_user(const char *name)
>> +{
>> +    uid_t user_id = 0;
>> +    gid_t user_gr = 0;
>> +
>> +    if (name != NULL) {
>> +            struct passwd *pswd = getpwnam(name);
>> +
>> +            if (pswd == 0)
>> +                    tst_brkm(TBROK,&cleanup, "Failed to find user \"%s\"", 
>> name);
>> +            user_id = pswd->pw_uid;
>> +            user_gr = pswd->pw_gid;
>> +    }
>> +
>> +    SAFE_SETEGID(&cleanup, user_gr);
>> +    SAFE_SETEUID(&cleanup, user_id);
>> +}
Thank you for your comments!

Could you please tell me how should I send the corrected patch, just in 
the same way?

Thanks,
Alexey

------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to