Ignore:
Files:
3 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • ChangeLog

    r1783 r1761  
    1 2012-12-20  Miloslav Trmač  <mitr@redhat.com> 
    2  
    3         * lib/fs.c (struct copy_access_options): New member ignore_eexist. 
    4         (lu_copy_dir_and_close): Use access_options->ignore_eexist. 
    5         (lu_homedir_populate, lu_homedir_move): Set 
    6         access_options.ignore_eexist. 
    7         * tests/fs_test.py (main): Don't output a full traceback if moveHome 
    8         fails. 
    9         * tests/fs_test: Test that moving onto an existing directory is 
    10         prohibited. 
    11  
    12         * lib/fs.c (lu_copy_dir_and_close): Only set the ownership and mode 
    13         of newly created files after the content is copied.  This is better 
    14         because 1) write(3) is allowed to reset the S_ISUID and S_ISGID bits, 
    15         and 2) if write() didn't reset the bits, having a set-uid/set-gid 
    16         executable with partial content might be a security risk. 
    17  
    18 2012-12-13  Miloslav Trmač  <mitr@redhat.com> 
    19  
    20         * tests/fs_test: Add tests for lu_homedir_populate() and 
    21         lu_homedir_move().  Make sure even inaccessible files are removed 
    22         on exit.  Actually test code from the current build instead of the 
    23         system installation.  Make the existing tests locale-independent. 
    24         * tests/fs_test.py: New modes --move and --populate. 
    25  
    26         * tests/fs_test: Check the final situation more thoroughly. 
    27  
    28         * tests/fs.conf.in 
    29         * tests/fs_test 
    30         * tests/fs_test.py: New files. 
    31         * Makefile.am (TESTS): Add tests/fs_test. 
    32         (EXTRA_DIST): Add tests/fs_test and dependencies. 
    33  
    34 2012-12-11  Miloslav Trmač  <mitr@redhat.com> 
    35  
    36         * lib/fs.c (lu_copy_dir_and_close): Don't unnecessarily ftruncate() a 
    37         file we just created. 
    38  
    39         * lib/fs.c (lu_copy_dir_and_close): Only make the directory accessible 
    40         to the target user after all work in it is done.  Still doesn't handle 
    41         pre-existing directories. 
    42  
    4312012-12-08  Miloslav Trmač  <mitr@redhat.com> 
    44  
    45         * lib/fs.c (lu_homedir_copy): Allow src_dir to be a symlink again. 
    46         This fixes an API incompatibility. 
    47  
    48         * lib/fs.c (lu_copy_dir_and_close): Rename again from... 
    49         (lu_homedir_copy_and_close): ... this. 
    50         (lu_homedir_copy): New helper function. 
    51         (lu_homedir_populate, lu_homedir_move): Simplify by using 
    52         the new lu_homedir_copy().  Better document security assumptios. 
    53  
    54         * lib/fs.c (copy_access_options): Rename member preserve_contexts 
    55         to preserve_source.  Document that other fields apply only if 
    56         !preserve_source. 
    57         (uid_for_copy): Implement preserve_source.  Fix a spectacular typo. 
    58         (gid_for_copy, mode_for_copy): Implement preserve_srouce. 
    59         (lu_homedir_copy_and_close, (lu_homedir_populate): Update for renamed 
    60         field preserve_source. 
    61         (lu_homedir_move): Update for renamed field preserve source.  This 
    62         also means that while moving the directory we do not override the 
    63         original owner in the copy, fixing a security hole (the user could 
    64         have a had hardlink to a file they couldn't read, and we would 
    65         helpfully create a copy owned by them). 
    66  
    67         * lib/fs.c (copy_access_options): Fix description of member umask. 
    68         (mode_for_copy): New helper function. 
    69         (lu_homedir_copy_and_close): Use mode_for_copy(). 
    70  
    71         * lib/fs.c (lu_homedir_copy_and_close): Rename from ... 
    72         (lu_homedir_copy) ... this.  When scanning a directory, open() each 
    73         entry and then fstat() instead of fstatat() + possible openat(), which 
    74         is racy. 
    75         (lu_homedir_populate, lu_homedir_move): Update for 
    76         lu_homedir_copy_and_close(). 
    77  
    78         * lib/user_private.h (lu_util_fscreate_from_fd) 
    79         (lu_util_fscreate_from_lfile): New declarations and fallback macros. 
    80         * lib/util.c (lu_util_fscreate_from_fd, lu_util_fscreate_from_lfile): 
    81         New functions. 
    82         * lib/fs.c (lu_homedir_copy): Set SELinux context immediately 
    83         before creating a new file, based on the file descriptor we will 
    84         be using, removing another path lookup race and avoiding the 
    85         top-level-directory special case.  Use lu_util_fscreate_from_lfile() 
    86         for symbolic links, fixing a bug. 
    87         (lu_homedir_populate, lu_homedir_move): Stop setting SELinux contexts 
    88         manually. 
    89  
    90         * lib/fs.c (lu_homedir_copy): Modify file times through existing 
    91         descriptors if possible. 
    92  
    93         * lib/fs.c (lu_homedir_copy): When creating copies, start with 
    94         minimal permissions, set owner, then set the desired permissions. 
    95         Thus, start preserving S_IS[UG]ID flags on copied regular files, and 
    96         make sure they aren't even momentarily undesirably acessible. 
    97  
    98         * lib/fs.c (copy_access_options): Drop member is_toplevel again. 
    99         (gid_for_copy): Don't use options->is_toplevel. 
    100         (lu_homedir_populate): Don't make a special case for the top-level 
    101         directory: just use the mode of the source directory for the copy, and 
    102         the same rules for the group.  All users updated. 
    103         (lu_homedir_populate): Manually set ownership and group to handle the 
    104         special case of a new home directory. 
    105  
    106         * lib/fs.c (copy_access_options): New members is_toplevel, uid and gid. 
    107         (uid_for_copy, gid_for_copy): New functions. 
    108         (lu_homedir_copy): Use access_options to pass around ownership 
    109         information.  All users updated, no change in semantics. 
    110  
    111         * lib/fs.c (copy_access_options): New structure. 
    112         (lu_homedir_copy): Use struct copy_access_options for keep_contexts 
    113         and umask.  All users updated, no change in semantics. 
    114  
    115         * lib/fs.c (lu_homedir_copy): Use a (parent FD, entry name) pair when 
    116         creating the existing directory to start avoiding symlink races.  Start 
    117         preserving nanosecond timestamp in the process. 
    118  
    119         * lib/fs.c (lu_homedir_copy): Rename path to dest_ent_path for 
    120         consistency. 
    121  
    122         * lib/fs.c (lu_homedir_copy): Use a (parent FD, entry name) pair when 
    123         reading the existing directory to avoid symlink races. 
    124  
    125         * lib/fs.c (lu_homedir_copy): Rename srcpath to src_ent_path to avoid 
    126         confusion with names added in the future. 
    1272 
    1283        * lib/fs.c (remove_subdirectory): Split from lu_homedir_remove(). 
  • Makefile.am

    r1779 r1755  
    2525## Targets 
    2626SUBDIRS = po docs 
    27 TESTS = tests/config_test.sh tests/fs_test tests/files_test tests/pwhash_test \ 
    28         tests/utils_test 
     27TESTS = tests/config_test.sh tests/files_test tests/pwhash_test tests/utils_test 
    2928if LDAP 
    3029TESTS += tests/default_pw_test tests/ldap_test 
     
    4241        tests/default_pw.conf.in tests/default_pw_test tests/default_pw_test.py \ 
    4342        tests/files.conf.in tests/files_test tests/files_test.py \ 
    44         tests/fs.conf.in tests/fs_tests tests/fs_test.py \ 
    4543        tests/ldap.conf.in tests/ldaprc tests/ldap_skel.ldif tests/ldap_test \ 
    4644        tests/ldap_test.py \ 
  • lib/fs.c

    r1783 r1761  
    5959} 
    6060 
    61 /* What should the ownership and permissions of the copied files be? */ 
    62 struct copy_access_options 
    63 { 
    64         /* Preserve ownership and permissions of the original unmodified; 
    65            otherwise, use matchpathcon() for SELinux contexts and apply 
    66            the following fields.. */ 
    67         gboolean preserve_source; 
    68         /* Ignore EEXIST errors.  This will go away in the future. */ 
    69         gboolean ignore_eexist; 
    70         uid_t uid;           /* UID to use for the copy if !preserve_source. */ 
    71         /* GID to use for the copy if !preserve_source and original is owned by 
    72            GID 0. */ 
    73         gid_t gid; 
    74         mode_t umask;         /* umask to apply to modes if !preserve_source */ 
    75 }; 
    76  
    77 /* Return an UID appropriate for a copy of ST given OPTIONS. */ 
    78 static uid_t 
    79 uid_for_copy(const struct copy_access_options *options, const struct stat *st) 
    80 { 
    81         if (options->preserve_source) 
    82                 return st->st_uid; 
    83         return options->uid; 
    84 } 
    85  
    86 /* Return a GID appropriate for a copy of ST given OPTIONS. */ 
    87 static gid_t 
    88 gid_for_copy(const struct copy_access_options *options, const struct stat *st) 
    89 { 
    90         if (options->preserve_source) 
    91                 return st->st_gid; 
    92         if (st->st_gid != 0) /* Skeleton wants us to us a different group */ 
    93                 return st->st_gid; 
    94         return options->gid; 
    95 } 
    96  
    97 /* Return a mode_t value appropriate for a copy of ST given OPTIONS. */ 
    98 static mode_t 
    99 mode_for_copy(const struct copy_access_options *options, const struct stat *st) 
    100 { 
    101         if (options->preserve_source) 
    102                 return st->st_mode; 
    103         return st->st_mode & ~options->umask; 
    104 } 
    105  
    106 /* Copy SRC_DIR_FD, which corresponds to SRC_DIR_PATH, to DEST_DIR_NAME under 
    107    DEST_PARENT_FD, which corresponds to DEST_DIR_PATH.  Use ACCESS_OPTIONS.  Use 
    108    SRC_DIR_STAT for data about SRC_DIR_PATH. 
    109  
    110    In every case, even on error, close SRC_DIR_FD. 
    111  
    112    DEST_PARENT_FD may be AT_FDCWD. 
    113  
    114    Note that SRC_DIR_PATH should only be used for error messages, not to access 
    115    the files; if the user is still logged in, a directory in the path may be 
    116    replaced by a symbolic link, redirecting the access outside of 
    117    SRC_PARENT_FD/SRC_DIR_NAME.   Likewise for DEST_*. */ 
     61/* Copy the "src" directory to "dest", setting all ownerships as given, and 
     62   setting the mode of the top-level directory as given.  The group ID of the 
     63   copied files is preserved if it is nonzero.  If keep_contexts, preserve 
     64   SELinux contexts in files under dest; use matchpathcon otherwise.  Assume 
     65   umask_value is the current value of umask. 
     66 
     67   Note that keep_contexts does NOT affect the context of dest; the caller must 
     68   perform an explicit setfscreatecon() before calling lu_homedir_copy() to set 
     69   the context of dest.  The SELinux fscreate context is on return from this 
     70   function is unspecified. */ 
    11871static gboolean 
    119 lu_copy_dir_and_close(int src_dir_fd, const char *src_dir_path, 
    120                       int dest_parent_fd, const char *dest_dir_name, 
    121                       const char *dest_dir_path, 
    122                       const struct stat *src_dir_stat, 
    123                       const struct copy_access_options *access_options, 
    124                       struct lu_error **error) 
     72lu_homedir_copy(const char *src, const char *dest, uid_t owner, gid_t group, 
     73                mode_t mode, gboolean keep_contexts, mode_t umask_value, 
     74                struct lu_error **error) 
    12575{ 
    12676        struct dirent *ent; 
    12777        DIR *dir; 
    128         int dest_dir_fd, ifd, ofd; 
    129         struct timespec timebuf[2]; 
     78        int ifd, ofd; 
    13079        gboolean ret = FALSE; 
    13180 
    13281        LU_ERROR_CHECK(error); 
    13382 
    134         if (*dest_dir_path != '/') { 
     83        if (*dest != '/') { 
    13584                lu_error_new(error, lu_error_generic, 
    13685                             _("Home directory path `%s' is not absolute"), 
    137                              dest_dir_path); 
    138                 goto err_src_dir_fd; 
    139         } 
    140  
    141         dir = fdopendir(src_dir_fd); 
     86                             dest); 
     87                goto err; 
     88        } 
     89 
     90        dir = opendir(src); 
    14291        if (dir == NULL) { 
    14392                lu_error_new(error, lu_error_generic, 
    144                              _("Error reading `%s': %s"), src_dir_path, 
    145                              strerror(errno)); 
    146                 goto err_src_dir_fd; 
    147         } 
    148  
    149         if (access_options->preserve_source) { 
    150                 if (!lu_util_fscreate_from_fd(src_dir_fd, src_dir_path, error)) 
    151                         goto err_dir; 
    152         } else if (!lu_util_fscreate_for_path(dest_dir_path, 
    153                                               src_dir_stat->st_mode & S_IFMT, 
    154                                               error)) 
     93                             _("Error reading `%s': %s"), src, 
     94                             strerror(errno)); 
     95                goto err; 
     96        } 
     97 
     98        /* Create the top-level directory. */ 
     99        if (mkdir(dest, mode) == -1 && errno != EEXIST) { 
     100                lu_error_new(error, lu_error_generic, 
     101                             _("Error creating `%s': %s"), dest, 
     102                             strerror(errno)); 
    155103                goto err_dir; 
    156  
    157         /* Create the directory.  It starts owned by us (presumbaly root), with 
    158            fairly restrictive permissions that still allow us to use the 
    159            directory. */ 
    160         if (mkdirat(dest_parent_fd, dest_dir_name, S_IRWXU) == -1 
    161             && (errno != EEXIST || !access_options->ignore_eexist)) { 
    162                 lu_error_new(error, lu_error_generic, 
    163                              _("Error creating `%s': %s"), dest_dir_path, 
     104        } 
     105 
     106        /* Set the ownership on the top-level directory. */ 
     107        if (chown(dest, owner, group) == -1 && errno != EPERM) { 
     108                lu_error_new(error, lu_error_generic, 
     109                             _("Error changing owner of `%s': %s"), dest, 
    164110                             strerror(errno)); 
    165111                goto err_dir; 
    166112        } 
    167         /* FIXME: O_SEARCH would be ideal here, but Linux doesn't currently 
    168            provide it. */ 
    169         dest_dir_fd = openat(dest_parent_fd, dest_dir_name, 
    170                              O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW); 
    171         if (dest_dir_fd == -1) { 
    172                 lu_error_new(error, lu_error_open, _("Error opening `%s': %s"), 
    173                              dest_dir_path, strerror(errno)); 
     113 
     114        /* Set modes explicitly to preserve S_ISGID and other bits.  Do this 
     115           after chown, because chown is permitted to reset these bits. */ 
     116        if (chmod(dest, mode & ~umask_value) == -1) { 
     117                lu_error_new(error, lu_error_generic, 
     118                             _("Error setting mode of `%s': %s"), dest, 
     119                             strerror(errno)); 
    174120                goto err_dir; 
    175121        } 
    176         /* The openat() after mkdirat() is not 100% safe; we may be modifying 
    177            ownership/permissions of another user's directory that was moved to 
    178            dest_dir_name in the mean time!  (Although why there would exist an 
    179            another user's directory, assuming lack hardlinks of directories, is 
    180            not clear.) 
    181  
    182            There's no way to do this completely atomically; so, rely on 
    183            permissions of the parent directory (write access to parent is 
    184            required to rename directories).  This holds for the top-level 
    185            directory, and for the others we achieve this by creating them 
    186            root-owned and S_IRWXU, and only applying the original ownership and 
    187            permissions after finishing other work.  See also the comment below 
    188            about symlinks. 
    189  
    190            Handling any preexisting directory structure complicates this - 
    191            should we temporarily chown/chmod any existing directory to 
    192            root:root/S_IRWXU?  That might be very disruptive, and such 
    193            structures should not exist in the first place. */ 
    194122 
    195123        while ((ent = readdir(dir)) != NULL) { 
    196                 char src_ent_path[PATH_MAX], dest_ent_path[PATH_MAX]; 
    197                 char buf[PATH_MAX]; 
     124                char srcpath[PATH_MAX], path[PATH_MAX], buf[PATH_MAX]; 
    198125                struct stat st; 
     126                struct utimbuf timebuf; 
    199127 
    200128                /* Iterate through each item in the directory. */ 
     
    209137                /* Build the path of the source file or directory and its 
    210138                   corresponding member in the new tree. */ 
    211                 snprintf(src_ent_path, sizeof(src_ent_path), "%s/%s", 
    212                          src_dir_path, ent->d_name); 
    213                 snprintf(dest_ent_path, sizeof(dest_ent_path), "%s/%s", 
    214                          dest_dir_path, ent->d_name); 
    215  
    216                 /* Open the input entry first, then we can fstat() it and be 
    217                    certain that it is still the same file.  O_NONBLOCK protects 
    218                    us against FIFOs and perhaps side-effects of the open() of a 
    219                    device file if there ever was one here, and doesn't matter 
    220                    for regular files or directories. */ 
    221                 ifd = openat(src_dir_fd, ent->d_name, 
    222                              O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK); 
    223                 if (ifd == -1) { 
     139                snprintf(srcpath, sizeof(srcpath), "%s/%s", src, ent->d_name); 
     140                snprintf(path, sizeof(path), "%s/%s", dest, ent->d_name); 
     141 
     142                /* What we do next depends on the type of entry we're 
     143                 * looking at. */ 
     144                if (lstat(srcpath, &st) != 0) 
     145                        continue; 
     146 
     147                if (keep_contexts != 0) { 
     148                        if (!lu_util_fscreate_from_file(srcpath, error)) 
     149                                goto err_dir; 
     150                } else if (!lu_util_fscreate_for_path(path, st.st_mode & S_IFMT, 
     151                                                      error)) 
     152                        goto err_dir; 
     153 
     154                /* We always want to preserve atime/mtime. */ 
     155                timebuf.actime = st.st_atime; 
     156                timebuf.modtime = st.st_mtime; 
     157 
     158                /* If it's a directory, descend into it. */ 
     159                if (S_ISDIR(st.st_mode)) { 
     160                        if (!lu_homedir_copy(srcpath, path, owner, 
     161                                             st.st_gid ?: group, st.st_mode, 
     162                                             keep_contexts, umask_value, error)) 
     163                                /* Aargh!  Fail up. */ 
     164                                goto err_dir; 
     165                        /* Set the date on the directory. */ 
     166                        utime(path, &timebuf); 
     167                        continue; 
     168                } 
     169 
     170                /* If it's a symlink, duplicate it. */ 
     171                if (S_ISLNK(st.st_mode)) { 
    224172                        ssize_t len; 
    225                         int saved_errno; 
    226  
    227                         saved_errno = errno; 
    228                         if (errno != ELOOP 
    229                             || fstatat(src_dir_fd, ent->d_name, &st, 
    230                                        AT_SYMLINK_NOFOLLOW) != 0 
    231                             || !S_ISLNK(st.st_mode)) { 
    232                                 lu_error_new(error, lu_error_open, 
    233                                              _("Error opening `%s': %s"), 
    234                                              src_ent_path, 
    235                                              strerror(saved_errno)); 
    236                                 goto err_dest_dir_fd; 
    237                         } 
    238  
    239                         /* OK, we have a symlink.  Duplicate it. */ 
    240  
    241                         /* In the worst case here, we end up with a wrong 
    242                            SELinux context for a symbolic link due to a path 
    243                            name lookup race.  That's unfortunate, but symlink 
    244                            contents are more or less public anyway... (A 
    245                            possible improvement would be to use Linux-only 
    246                            O_PATH to open src_ent_path first, then see if it is 
    247                            a symlink, and "upgrade" to an O_RDONLY if not.  But 
    248                            O_PATH is available only in Linux >= 2.6.39.) 
    249  
    250                            The symlinkat()/fchownat()/utimensat() calls are 
    251                            also not safe against an user meddling; we might be 
    252                            able to ensure the fchownat()/utimensat() are done 
    253                            on the same file using O_PATH again, but 
    254                            symlinkat()/the rest is definitely unatomic.  Rely 
    255                            on having an unwritable the parent directory, same 
    256                            as in the mkdirat()/openat() case. */ 
    257                         if (access_options->preserve_source) { 
    258                                 if (!lu_util_fscreate_from_lfile(src_ent_path, 
    259                                                                  error)) 
    260                                         goto err_dest_dir_fd; 
    261                         } else if (!lu_util_fscreate_for_path 
    262                                    (dest_ent_path, st.st_mode & S_IFMT, error)) 
    263                                 goto err_dest_dir_fd; 
    264  
    265                         len = readlinkat(src_dir_fd, ent->d_name, buf, 
    266                                          sizeof(buf) - 1); 
     173 
     174                        len = readlink(srcpath, buf, sizeof(buf) - 1); 
    267175                        if (len == -1) { 
    268176                                lu_error_new(error, lu_error_generic, 
    269177                                             _("Error reading `%s': %s"), 
    270                                              src_ent_path, strerror(errno)); 
    271                                 goto err_dest_dir_fd; 
     178                                             srcpath, strerror(errno)); 
     179                                goto err_dir; 
    272180                        } 
    273181                        buf[len] = '\0'; 
    274                         if (symlinkat(buf, dest_dir_fd, ent->d_name) == -1) { 
    275                                 if (errno == EEXIST 
    276                                     && access_options->ignore_eexist) 
     182                        if (symlink(buf, path) == -1) { 
     183                                if (errno == EEXIST) 
    277184                                        continue; 
    278185                                lu_error_new(error, lu_error_generic, 
    279186                                             _("Error creating `%s': %s"), 
    280                                              dest_ent_path, strerror(errno)); 
    281                                 goto err_dest_dir_fd; 
    282                         } 
    283                         if (fchownat(dest_dir_fd, ent->d_name, 
    284                                      uid_for_copy(access_options, &st), 
    285                                      gid_for_copy(access_options, &st), 
    286                                      AT_SYMLINK_NOFOLLOW) == -1 
     187                                             path, strerror(errno)); 
     188                                goto err_dir; 
     189                        } 
     190                        if (lchown(path, owner, st.st_gid ?: group) == -1 
    287191                            && errno != EPERM && errno != EOPNOTSUPP) { 
    288192                                lu_error_new(error, lu_error_generic, 
    289193                                             _("Error changing owner of `%s': " 
    290                                                "%s"), dest_ent_path, 
    291                                              strerror(errno)); 
    292                                 goto err_dest_dir_fd; 
    293                         } 
    294                         timebuf[0] = st.st_atim; 
    295                         timebuf[1] = st.st_mtim; 
    296                         utimensat(dest_dir_fd, ent->d_name, timebuf, 
    297                                   AT_SYMLINK_NOFOLLOW); 
    298                         continue; 
    299                 } 
    300  
    301                 if (fstat(ifd, &st) != 0) { 
    302                         lu_error_new(error, lu_error_stat, 
    303                                      _("couldn't stat `%s': %s"), src_ent_path, 
    304                                      strerror(errno)); 
    305                         goto err_ifd; 
    306                 } 
    307                 g_assert(!S_ISLNK(st.st_mode)); 
    308  
    309                 /* If it's a directory, descend into it. */ 
    310                 if (S_ISDIR(st.st_mode)) { 
    311                         if (!lu_copy_dir_and_close(ifd, src_ent_path, 
    312                                                    dest_dir_fd, ent->d_name, 
    313                                                    dest_ent_path, &st, 
    314                                                    access_options, error)) 
    315                                 /* Aargh!  Fail up. */ 
    316                                 goto err_dest_dir_fd; 
     194                                               "%s"), dest, strerror(errno)); 
     195                                goto err_dir; 
     196                        } 
     197                        utime(path, &timebuf); 
    317198                        continue; 
    318199                } 
     
    320201                /* If it's a regular file, copy it. */ 
    321202                if (S_ISREG(st.st_mode)) { 
    322                         if (access_options->preserve_source) { 
    323                                 if (!lu_util_fscreate_from_fd(ifd, src_ent_path, 
    324                                                               error)) 
    325                                         goto err_ifd; 
    326                         } else if (!lu_util_fscreate_for_path 
    327                                    (dest_ent_path, st.st_mode & S_IFMT, error)) 
    328                                 goto err_ifd; 
    329                         /* Start with absolutely restrictive permissions; the 
    330                            original file may be e.g. a hardlink to 
    331                            /etc/shadow. */ 
    332                         ofd = openat(dest_dir_fd, ent->d_name, 
    333                                      O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW, 
    334                                      0); 
     203                        off_t offset; 
     204 
     205                        /* Open both the input and output files.  If we fail to 
     206                           do either, we have to give up. */ 
     207                        ifd = open(srcpath, O_RDONLY); 
     208                        if (ifd == -1) { 
     209                                lu_error_new(error, lu_error_open, 
     210                                             _("Error reading `%s': %s"), 
     211                                             srcpath, strerror(errno)); 
     212                                goto err_dir; 
     213                        } 
     214                        ofd = open(path, O_EXCL | O_CREAT | O_WRONLY, 
     215                                   st.st_mode); 
    335216                        if (ofd == -1) { 
    336                                 if (errno == EEXIST 
    337                                     && access_options->ignore_eexist) { 
     217                                if (errno == EEXIST) { 
    338218                                        close(ifd); 
    339219                                        continue; 
     
    341221                                lu_error_new(error, lu_error_open, 
    342222                                             _("Error writing `%s': %s"), 
    343                                              dest_ent_path, strerror(errno)); 
     223                                             path, strerror(errno)); 
    344224                                goto err_ifd; 
    345225                        } 
     
    356236                                        lu_error_new(error, lu_error_read, 
    357237                                                     _("Error reading `%s': " 
    358                                                        "%s"), src_ent_path, 
     238                                                       "%s"), srcpath, 
    359239                                                     strerror(errno)); 
    360240                                        goto err_ofd; 
     
    374254                                                             _("Error writing " 
    375255                                                               "`%s': %s"), 
    376                                                              dest_ent_path, 
     256                                                             path, 
    377257                                                             strerror(errno)); 
    378258                                                goto err_ofd; 
     
    383263                        } 
    384264 
    385                         /* Set the ownership; permissions are still 
    386                            restrictive. */ 
    387                         if (fchown(ofd, uid_for_copy(access_options, &st), 
    388                                    gid_for_copy(access_options, &st)) == -1 
     265                        /* Close the files. */ 
     266                        offset = lseek(ofd, 0, SEEK_CUR); 
     267                        if (offset != ((off_t) -1)) { 
     268                                if (ftruncate(ofd, offset) == -1) { 
     269                                        lu_error_new(error, lu_error_generic, 
     270                                                     _("Error writing `%s': " 
     271                                                       "%s"), path, 
     272                                                     strerror(errno)); 
     273                                        goto err_ofd; 
     274                                } 
     275                        } 
     276                        close (ifd); 
     277                        close (ofd); 
     278 
     279                        /* Set the ownership and timestamp on the new file. */ 
     280                        if (chown(path, owner, st.st_gid ?: group) == -1 
    389281                            && errno != EPERM) { 
    390282                                lu_error_new(error, lu_error_generic, 
    391283                                             _("Error changing owner of `%s': " 
    392                                                "%s"), dest_ent_path, 
    393                                              strerror(errno)); 
    394                                 goto err_ofd; 
    395                         } 
    396  
    397                         /* Set the desired mode.  Do this explicitly to 
    398                            preserve S_ISGID and other bits.  Do this after 
    399                            chown, because chown is permitted to reset these 
    400                            bits. */ 
    401                         if (fchmod(ofd, mode_for_copy(access_options, &st)) 
    402                             == -1) { 
    403                                 lu_error_new(error, lu_error_generic, 
    404                                              _("Error setting mode of `%s': " 
    405                                                "%s"), dest_ent_path, 
    406                                              strerror(errno)); 
    407                                 goto err_ofd; 
    408                         } 
    409  
    410                         close (ifd); 
    411  
    412                         timebuf[0] = st.st_atim; 
    413                         timebuf[1] = st.st_mtim; 
    414                         futimens(ofd, timebuf); 
    415  
    416                         close (ofd); 
    417  
     284                                               "%s"), dest, strerror(errno)); 
     285                                goto err_dir; 
     286                        } 
     287                        utime(path, &timebuf); 
    418288                        continue; 
    419289                } 
    420290                /* Note that we don't copy device specials. */ 
    421                 close(ifd); 
    422         } 
    423  
    424         /* Set the ownership on the directory.  Permissions are still 
    425            fairly restrictive. */ 
    426         if (fchown(dest_dir_fd, uid_for_copy(access_options, src_dir_stat), 
    427                    gid_for_copy(access_options, src_dir_stat)) == -1 
    428             && errno != EPERM) { 
    429                 lu_error_new(error, lu_error_generic, 
    430                              _("Error changing owner of `%s': %s"), 
    431                              dest_dir_path, strerror(errno)); 
    432                 goto err_dest_dir_fd; 
    433         } 
    434  
    435         /* Set the desired mode.  Do this explicitly to preserve S_ISGID and 
    436            other bits.  Do this after chown, because chown is permitted to 
    437            reset these bits. */ 
    438         if (fchmod(dest_dir_fd, 
    439                    mode_for_copy(access_options, src_dir_stat)) == -1) { 
    440                 lu_error_new(error, lu_error_generic, 
    441                              _("Error setting mode of `%s': %s"), dest_dir_path, 
    442                              strerror(errno)); 
    443                 goto err_dest_dir_fd; 
    444         } 
    445  
    446         timebuf[0] = src_dir_stat->st_atim; 
    447         timebuf[1] = src_dir_stat->st_mtim; 
    448         futimens(dest_dir_fd, timebuf); 
    449  
     291        } 
    450292        ret = TRUE; 
    451         goto err_dest_dir_fd; 
     293        goto err_dir; 
    452294 
    453295 err_ofd: 
     
    455297 err_ifd: 
    456298        close(ifd); 
    457  err_dest_dir_fd: 
    458         close(dest_dir_fd); 
    459299 err_dir: 
    460300        closedir(dir); 
    461         src_dir_fd = -1; 
    462  err_src_dir_fd: 
    463         if (src_dir_fd != -1) 
    464                 close(src_dir_fd); 
    465         return ret; 
    466 } 
    467  
    468 /* Copy SRC_DIR to DEST_DIR.  Use ACCESS_OPTIONS. 
    469  
    470    Return TRUE on error. 
    471  
    472    To be secure, neither SRC_DIR nor DEST_DIR should contain any 
    473    user-controlled parent directories in the path.  SRC_DIR may be an 
    474    user-owned directory, or even a symlink, but its parent should not be 
    475    user-writable (so that the user can't replace it with a symlink or change 
    476    the symlink). */ 
    477 static gboolean 
    478 lu_homedir_copy(const char *src_dir, const char *dest_dir, 
    479                 const struct copy_access_options *access_options, 
    480                 struct lu_error **error) 
    481 { 
    482         lu_security_context_t fscreate; 
    483         int fd; 
    484         struct stat st; 
    485         gboolean ret; 
    486  
    487         ret = FALSE; 
    488         if (!lu_util_fscreate_save(&fscreate, error)) 
    489                 goto err; 
    490  
    491         fd = open(src_dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY); 
    492         if (fd == -1) { 
    493                 lu_error_new(error, lu_error_open, _("Error opening `%s': %s"), 
    494                              src_dir, strerror(errno)); 
    495                 goto err_fscreate; 
    496         } 
    497         if (fstat(fd, &st) == -1) { 
    498                 lu_error_new(error, lu_error_stat, _("couldn't stat `%s': %s"), 
    499                              src_dir, strerror(errno)); 
    500                 goto err_fd; 
    501         } 
    502  
    503         ret = lu_copy_dir_and_close(fd, src_dir, AT_FDCWD, dest_dir, dest_dir, 
    504                                     &st, access_options, error); 
    505         goto err_fscreate; 
    506  
    507 err_fd: 
    508         close(fd); 
    509 err_fscreate: 
    510         lu_util_fscreate_restore(fscreate); 
    511 err: 
     301 err: 
    512302        return ret; 
    513303} 
     
    526316 * Creates a new home directory for an user. 
    527317 * 
    528  * If you want to use this in a hostile environment, ensure that no untrusted 
    529  * user has write permission to any parent of @sekeleton or @directory.  Usually 
    530  * /home is only writable by root, which is safe. 
    531  * 
    532318 * Returns: %TRUE on success 
    533319 */ 
     
    537323                    mode_t mode, struct lu_error **error) 
    538324{ 
    539         struct copy_access_options access_options; 
     325        lu_security_context_t fscreate; 
     326        gboolean ret; 
    540327 
    541328        if (skeleton == NULL) 
    542329                skeleton = lu_cfg_read_single(ctx, "defaults/skeleton", 
    543330                                              "/etc/skel"); 
    544         access_options.preserve_source = FALSE; 
    545         access_options.ignore_eexist = TRUE; 
    546         access_options.uid = owner; 
    547         access_options.gid = group; 
    548         access_options.umask = current_umask(); 
    549         if (!lu_homedir_copy(skeleton, directory, &access_options, error)) 
    550                 return FALSE; 
    551  
    552         /* Now reconfigure the toplevel directory as desired.  The directory 
    553            thus might have incorrect owner/permissions for a while; this is OK 
    554            because the contents are public anyway (every users sees them on 
    555            first access), and write access is not allowed because the skeleton 
    556            is not writable. */ 
    557  
    558         /* Set the ownership on the top-level directory manually again, 
    559            lu_homedir_copy() would have preserved st.st_gid if it were not root 
    560            for some reason; our API promises to use precisely "owner" and 
    561            "group". */ 
    562         if (chown(directory, owner, group) == -1 && errno != EPERM) { 
    563                 lu_error_new(error, lu_error_generic, 
    564                              _("Error changing owner of `%s': %s"), directory, 
    565                              strerror(errno)); 
    566                 return FALSE; 
    567         } 
    568         /* Set modes as required instead of preserving st.st_mode.  Do this 
    569            after chown, because chown is permitted to reset these bits. */ 
    570         if (chmod(directory, mode & ~access_options.umask) == -1) { 
    571                 lu_error_new(error, lu_error_generic, 
    572                              _("Error setting mode of `%s': %s"), directory, 
    573                              strerror(errno)); 
    574                 return FALSE; 
    575         } 
    576  
    577         return TRUE; 
     331        ret = FALSE; 
     332        if (!lu_util_fscreate_save(&fscreate, error)) 
     333                goto err; 
     334        if (!lu_util_fscreate_for_path(directory, S_IFDIR, error)) 
     335                goto err_fscreate; 
     336        ret = lu_homedir_copy(skeleton, directory, owner, group, mode, 0, 
     337                              current_umask(), error); 
     338err_fscreate: 
     339        lu_util_fscreate_restore(fscreate); 
     340err: 
     341        return ret; 
    578342} 
    579343 
     
    587351   Note that DIR_PATH should only be used for error messages, not to access 
    588352   the files; if the user is still logged in, a directory in the path may be 
    589    replaced by a symbolic link, redirecting the access outside of 
    590    PARENT_FD/DIR_NAME. */ 
     353   replaced by a symbolic link, redirecting the access outside of DIRFD. */ 
    591354static gboolean 
    592355remove_subdirectory(int parent_fd, const char *dir_name, const char *dir_path, 
     
    679442 * 
    680443 * If you want to use this in a hostile environment, ensure that no untrusted 
    681  * user has write permission to any parent of @directory. 
     444 * use has write permission to any parent of @directory. 
    682445 * 
    683446 * Returns: %TRUE on success 
     
    702465 * expect this to take a long time. 
    703466 * 
    704  * If you want to use this in a hostile environment, ensure that no untrusted 
    705  * user has write permission to any parent of @oldhome or @newhome.  Usually 
    706  * /home is only writable by root, which is safe; user's write permission to 
    707  * @oldhome itself is OK. 
    708  * 
    709467 * Returns: %TRUE on success 
    710468 */ 
     
    713471                struct lu_error ** error) 
    714472{ 
    715         struct copy_access_options access_options; 
     473        struct stat st; 
     474        lu_security_context_t fscreate; 
    716475 
    717476        LU_ERROR_CHECK(error); 
    718477 
    719         access_options.preserve_source = TRUE; 
    720         access_options.ignore_eexist = FALSE; 
    721         if (!lu_homedir_copy(oldhome, newhome, &access_options, error)) 
    722                 return FALSE; 
    723  
     478        /* If the directory exists... */ 
     479        if (stat(oldhome, &st) != 0) 
     480                goto err; 
     481 
     482        if (!lu_util_fscreate_save(&fscreate, error)) 
     483                goto err; 
     484        if (!lu_util_fscreate_from_file(oldhome, error)) 
     485                goto err_fscreate; 
     486        /* ... and we can copy it ... */ 
     487        if (!lu_homedir_copy(oldhome, newhome, st.st_uid, st.st_gid, 
     488                             st.st_mode, 1, current_umask(), error)) 
     489                goto err_fscreate; 
     490        lu_util_fscreate_restore(fscreate); 
     491        /* ... remove the old one. */ 
    724492        return lu_homedir_remove(oldhome, error); 
     493 
     494err_fscreate: 
     495        lu_util_fscreate_restore(fscreate); 
     496err: 
     497        return FALSE; 
    725498} 
    726499 
  • lib/user_private.h

    r1771 r1713  
    310310                                      struct lu_error **error); 
    311311void lu_util_fscreate_restore(security_context_t ctx); 
    312 gboolean lu_util_fscreate_from_fd(int fd, const char *path, 
    313                                   struct lu_error **error); 
    314312gboolean lu_util_fscreate_from_file(const char *file, struct lu_error **error); 
    315 gboolean lu_util_fscreate_from_lfile(const char *file, struct lu_error **error); 
    316313gboolean lu_util_fscreate_for_path(const char *path, mode_t mode, 
    317314                                   struct lu_error **error); 
     
    321318#define lu_util_fscreate_save(CTX, ERROR) ((void)(CTX), (void)(ERROR), TRUE) 
    322319#define lu_util_fscreate_restore(CTX) ((void)(CTX)) 
    323 #define lu_util_fscreate_from_fd(FD, PATH, ERROR) \ 
    324   ((void)(FILE), (void)(PATH), (void)(ERROR), TRUE) 
    325320#define lu_util_fscreate_from_file(FILE, ERROR) \ 
    326   ((void)(FILE), (void)(ERROR), TRUE) 
    327 #define lu_util_fscreate_from_lfile(FILE, ERROR) \ 
    328321  ((void)(FILE), (void)(ERROR), TRUE) 
    329322#define lu_util_fscreate_for_path(PATH, MODE, ERROR) \ 
  • lib/util.c

    r1771 r1760  
    707707} 
    708708 
    709 /* Set fscreate context from context of fd.  Use path only for diagnostics. */ 
    710 gboolean 
    711 lu_util_fscreate_from_fd(int fd, const char *path, struct lu_error **error) 
    712 { 
    713         if (is_selinux_enabled() > 0) { 
    714                 security_context_t ctx; 
    715  
    716                 if (fgetfilecon(fd, &ctx) < 0) { 
    717                         lu_error_new(error, lu_error_stat, 
    718                                      _("couldn't get security context of " 
    719                                        "`%s': %s"), path, strerror(errno)); 
    720                         return FALSE; 
    721                 } 
    722                 if (setfscreatecon(ctx) < 0) { 
    723                         lu_error_new(error, lu_error_generic, 
    724                                      _("couldn't set default security context " 
    725                                        "to `%s': %s"), ctx, strerror(errno)); 
    726                         freecon(ctx); 
    727                         return FALSE; 
    728                 } 
    729                 freecon(ctx); 
    730         } 
    731         return TRUE; 
    732 } 
    733  
    734  
    735709/* Set fscreate context from context of file. */ 
    736710gboolean 
     
    741715 
    742716                if (getfilecon(file, &ctx) < 0) { 
    743                         lu_error_new(error, lu_error_stat, 
    744                                      _("couldn't get security context of " 
    745                                        "`%s': %s"), file, strerror(errno)); 
    746                         return FALSE; 
    747                 } 
    748                 if (setfscreatecon(ctx) < 0) { 
    749                         lu_error_new(error, lu_error_generic, 
    750                                      _("couldn't set default security context " 
    751                                        "to `%s': %s"), ctx, strerror(errno)); 
    752                         freecon(ctx); 
    753                         return FALSE; 
    754                 } 
    755                 freecon(ctx); 
    756         } 
    757         return TRUE; 
    758 } 
    759  
    760 /* Set fscreate context from context of file, not resolving it if it is a 
    761    symlink. */ 
    762 gboolean 
    763 lu_util_fscreate_from_lfile(const char *file, struct lu_error **error) 
    764 { 
    765         if (is_selinux_enabled() > 0) { 
    766                 security_context_t ctx; 
    767  
    768                 if (lgetfilecon(file, &ctx) < 0) { 
    769717                        lu_error_new(error, lu_error_stat, 
    770718                                     _("couldn't get security context of " 
Note: See TracChangeset for help on using the changeset viewer.