libexplain  1.4.D001
libexplain/have_permission.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/sys/param.h>
00021 #include <libexplain/ac/sys/stat.h>
00022 #include <libexplain/ac/unistd.h>
00023 
00024 #include <libexplain/buffer/dac.h>
00025 #include <libexplain/buffer/file_type.h>
00026 #include <libexplain/buffer/gettext.h>
00027 #include <libexplain/buffer/gid.h>
00028 #include <libexplain/buffer/group_permission_ignored.h>
00029 #include <libexplain/buffer/others_permission_ignored.h>
00030 #include <libexplain/buffer/others_permission.h>
00031 #include <libexplain/buffer/rwx.h>
00032 #include <libexplain/buffer/uid.h>
00033 #include <libexplain/capability.h>
00034 #include <libexplain/gettext.h>
00035 #include <libexplain/group_in_groups.h>
00036 #include <libexplain/have_permission.h>
00037 #include <libexplain/option.h>
00038 #include <libexplain/translate.h>
00039 
00040 
00041 static int
00042 explain_have_permission(const struct stat *st,
00043     const explain_have_identity_t *hip, int wanted)
00044 {
00045     /*
00046      * The first group of three is used when the effective user ID of
00047      * the process equals the owner ID of the file.
00048      */
00049     if (st->st_uid == (uid_t)hip->uid)
00050     {
00051         return (0 != (st->st_mode & wanted & S_IRWXU));
00052     }
00053 
00054     /*
00055      * The second group of three is used when the group ID of the file
00056      * either equals the effective group ID of the process, or
00057      * is one of the supplementary group IDs of the process (as
00058      * set by setgroups(2)).
00059      */
00060     if (explain_group_in_groups(st->st_gid, hip))
00061     {
00062         return (0 != (st->st_mode & wanted & S_IRWXG));
00063     }
00064 
00065     /*
00066      * When neither holds, the third group is used.
00067      */
00068     return (0 != (st->st_mode & wanted & S_IRWXO));
00069 }
00070 
00071 
00072 static void
00073 owner_permission_mode_used(explain_string_buffer_t *sb,
00074     const struct stat *st, const explain_have_identity_t *hip)
00075 {
00076     char            part1[40];
00077     explain_string_buffer_t part1_sb;
00078     char            part2[40];
00079     explain_string_buffer_t part2_sb;
00080     char            part3[8];
00081     explain_string_buffer_t part3_sb;
00082     char            filtyp[100];
00083     explain_string_buffer_t filtyp_sb;
00084 
00085     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00086     explain_buffer_uid(&part1_sb, hip->uid);
00087     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00088     explain_buffer_uid(&part2_sb, st->st_uid);
00089     explain_string_buffer_init(&part3_sb, part3, sizeof(part3));
00090     explain_buffer_rwx(&part3_sb, st->st_mode & S_IRWXU);
00091     explain_string_buffer_init(&filtyp_sb, filtyp, sizeof(filtyp));
00092     explain_buffer_file_type_st(&filtyp_sb, st);
00093 
00094     explain_string_buffer_puts(sb, ", ");
00095     explain_string_buffer_printf_gettext
00096     (
00097         sb,
00098         /*
00099          * xgettext: This message is used when explaining which
00100          * permission mode bits are used when determining file access
00101          * permissions.
00102          *
00103          * %1$s => the kind of UID, "real UID" or "effective UID",
00104          *         already translated.
00105          * %2$s => the UID of the process, number and name.
00106          * %3$s => the file type, e.g. "directory" or "regular file"
00107          * %4$s => the owner of the file, number and name.
00108          * %5$s => The mode bits like "rwx", including the quotes, in
00109          *         a form resembling the ls -l representation of mode
00110          *         bits.
00111          */
00112         i18n("the process %s %s matches the %s owner UID %s and the "
00113             "owner permission mode is %s"),
00114         explain_have_identity_kind_of_uid(hip),
00115         part1,
00116         filtyp,
00117         part2,
00118         part3
00119     );
00120 }
00121 
00122 
00123 static void
00124 owner_permission_mode_ignored(explain_string_buffer_t *sb,
00125     const struct stat *st, const explain_have_identity_t *hip)
00126 {
00127     char            part1[40];
00128     explain_string_buffer_t part1_sb;
00129     char            part2[40];
00130     explain_string_buffer_t part2_sb;
00131     char            part3[8];
00132     explain_string_buffer_t part3_sb;
00133     char            filtyp[100];
00134     explain_string_buffer_t filtyp_sb;
00135 
00136     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00137     explain_buffer_uid(&part1_sb, hip->uid);
00138     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00139     explain_buffer_uid(&part2_sb, st->st_uid);
00140     explain_string_buffer_init(&part3_sb, part3, sizeof(part3));
00141     explain_buffer_rwx(&part3_sb, st->st_mode & S_IRWXU);
00142     explain_string_buffer_init(&filtyp_sb, filtyp, sizeof(filtyp));
00143     explain_buffer_file_type_st(&filtyp_sb, st);
00144 
00145     explain_string_buffer_puts(sb, ", ");
00146     explain_string_buffer_printf_gettext
00147     (
00148         sb,
00149         /*
00150          * xgettext: This message is used when explaining which
00151          * permission mode bits are ignored when determining
00152          * file access permissions.
00153          *
00154          * %1$s => the kind of GID, "real GID" or "effective GID",
00155          *         already translated
00156          * %2$s => the GID of the process, number and name.
00157          * %3$s => the file type, e.g. "directory" or "regular file"
00158          * %4$s => the owner of the file, number and name.
00159          * %5$s => The mode bits like "rwx", including the quotes, in
00160          *         a form resembling the ls -l representation of mode
00161          *         bits.
00162          */
00163         i18n("the process %s %s does not match the %s owner "
00164             "%s so the owner permission mode %s is ignored"),
00165         explain_have_identity_kind_of_uid(hip),
00166         part1,
00167         filtyp,
00168         part2,
00169         part3
00170     );
00171 }
00172 
00173 
00174 static void
00175 group_permission_mode_used(explain_string_buffer_t *sb,
00176     const struct stat *st, const explain_have_identity_t *hip)
00177 {
00178     char            part1[40];
00179     explain_string_buffer_t part1_sb;
00180     char            part2[40];
00181     explain_string_buffer_t part2_sb;
00182     char            part3[8];
00183     explain_string_buffer_t part3_sb;
00184     char            filtyp[100];
00185     explain_string_buffer_t filtyp_sb;
00186 
00187     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00188     explain_buffer_gid(&part1_sb, hip->gid);
00189     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00190     explain_buffer_gid(&part2_sb, st->st_gid);
00191     explain_string_buffer_init(&part3_sb, part3, sizeof(part3));
00192     explain_buffer_rwx(&part3_sb, st->st_mode & S_IRWXG);
00193     explain_string_buffer_init(&filtyp_sb, filtyp, sizeof(filtyp));
00194     explain_buffer_file_type_st(&filtyp_sb, st);
00195 
00196     explain_string_buffer_puts(sb, ", ");
00197     explain_string_buffer_printf_gettext
00198     (
00199         sb,
00200         /*
00201          * xgettext: This message is used when explaining which
00202          * permission mode bits are used when determining file access
00203          * permissions.
00204          *
00205          * %1$s => the kind of GID, "real GID" or "effective GID",
00206          *         already translated
00207          * %2$s => the GID of the process, number and name.
00208          * %3$s => the file type, e.g. 'directory' or 'regular file'
00209          * %4$s => the group of the file, number and name.
00210          * %5$s => The mode bits like "rwx", including the quotes, in
00211          *         a form resembling the ls -l representation of mode
00212          *         bits.
00213          */
00214         i18n("the process %s %s matches the %s group GID %s and the "
00215             "group permission mode is %s"),
00216         explain_have_identity_kind_of_gid(hip),
00217         part1,
00218         filtyp,
00219         part2,
00220         part3
00221     );
00222 }
00223 
00224 
00225 static int
00226 explain_explain_permission(explain_string_buffer_t *sb,
00227     const struct stat *st, const explain_have_identity_t *hip, int wanted)
00228 {
00229     if (!explain_option_dialect_specific())
00230     {
00231         /*
00232          * The test suite doesn't need to see the uid and name, or the
00233          * gid and name, because these give false negatives.
00234          */
00235         return -1;
00236     }
00237 
00238     /*
00239      * The first group of three (0700) is used when the effective user
00240      * ID of the process equals the owner ID of the file.
00241      */
00242     if (st->st_uid == (uid_t)hip->uid)
00243     {
00244         owner_permission_mode_used(sb, st, hip);
00245 
00246         if
00247         (
00248             (st->st_mode & wanted & S_IRWXG)
00249         &&
00250             explain_group_in_groups(st->st_gid, hip)
00251         )
00252         {
00253             explain_buffer_group_permission_ignored(sb, st->st_mode);
00254         }
00255         if (st->st_mode & wanted & S_IRWXO)
00256         {
00257             explain_buffer_others_permission_ignored(sb, st->st_mode);
00258         }
00259         return (0 != (st->st_mode & wanted & S_IRWXU));
00260     }
00261 
00262     /*
00263      * The second group of three (0070) is used when the group ID of the
00264      * file either equals the effective group ID of the process,
00265      * or is one of the supplementary group IDs of the process
00266      * (as set by setgroups(2)).
00267      *
00268      * FIXME: when the file is on a remote NFS mount, only the first 16
00269      * groups are consulted.  This can be a problem when a process is in
00270      * more than 16 groups.
00271      */
00272     if (explain_group_in_groups(st->st_gid, hip))
00273     {
00274         if (st->st_mode & wanted & S_IRWXU)
00275         {
00276             owner_permission_mode_ignored(sb, st, hip);
00277         }
00278 
00279         group_permission_mode_used(sb, st, hip);
00280 
00281         if (st->st_mode & wanted & S_IRWXO)
00282         {
00283             explain_buffer_others_permission_ignored(sb, st->st_mode);
00284         }
00285         return (0 != (st->st_mode & wanted & S_IRWXG));
00286     }
00287 
00288     /*
00289      * When neither holds, the third group is used.
00290      */
00291     if (st->st_mode & wanted & S_IRWXU)
00292     {
00293         owner_permission_mode_ignored(sb, st, hip);
00294     }
00295     if (st->st_mode & wanted & S_IRWXG)
00296     {
00297         explain_buffer_group_permission_ignored(sb, st->st_mode);
00298     }
00299     explain_buffer_others_permission(sb, st->st_mode);
00300     return (0 != (st->st_mode & wanted & S_IRWXO));
00301 }
00302 
00303 
00304 int
00305 explain_have_read_permission(const struct stat *st,
00306     const explain_have_identity_t *hip)
00307 {
00308     if (explain_capability_dac_read_search())
00309         return 1;
00310     return explain_have_permission(st, hip, 0444);
00311 }
00312 
00313 
00314 int
00315 explain_explain_read_permission(explain_string_buffer_t *sb,
00316     const struct stat *st, const explain_have_identity_t *hip)
00317 {
00318     int             result;
00319 
00320     if (explain_capability_dac_read_search())
00321         return 1;
00322     result = explain_explain_permission(sb, st, hip, 0444);
00323     if (!result)
00324         explain_buffer_dac_read_search(sb);
00325     return result;
00326 }
00327 
00328 
00329 int
00330 explain_have_write_permission(const struct stat *st,
00331     const explain_have_identity_t *hip)
00332 {
00333     if (explain_capability_dac_override())
00334         return 1;
00335     return explain_have_permission(st, hip, 0222);
00336 }
00337 
00338 
00339 int
00340 explain_explain_write_permission(explain_string_buffer_t *sb,
00341     const struct stat *st, const explain_have_identity_t *hip)
00342 {
00343     int             result;
00344 
00345     if (explain_capability_dac_override())
00346         return 1;
00347     result = explain_explain_permission(sb, st, hip, 0222);
00348     if (!result)
00349         explain_buffer_dac_override(sb);
00350     return result;
00351 }
00352 
00353 
00354 int
00355 explain_have_execute_permission(const struct stat *st,
00356     const explain_have_identity_t *hip)
00357 {
00358     if (!S_ISREG(st->st_mode))
00359         return 0;
00360     if
00361     (
00362         explain_capability_dac_override()
00363 #ifdef __linux__
00364     &&
00365         (st->st_mode & 0111)
00366 #endif
00367     )
00368         return 1;
00369     return explain_have_permission(st, hip, 0111);
00370 }
00371 
00372 
00373 int
00374 explain_explain_execute_permission(explain_string_buffer_t *sb,
00375     const struct stat *st, const explain_have_identity_t *hip)
00376 {
00377     int             result;
00378 
00379     if (!S_ISREG(st->st_mode))
00380         return 0;
00381     if
00382     (
00383         explain_capability_dac_override()
00384 #ifdef __linux__
00385     &&
00386         (st->st_mode & 0111)
00387 #endif
00388     )
00389         return 1;
00390     result = explain_explain_permission(sb, st, hip, 0111);
00391     if (!result)
00392         explain_buffer_dac_override(sb);
00393     return result;
00394 }
00395 
00396 
00397 int
00398 explain_have_search_permission(const struct stat *st,
00399     const explain_have_identity_t *hip)
00400 {
00401     if (!S_ISDIR(st->st_mode))
00402         return 0;
00403     if (explain_capability_dac_read_search())
00404         return 1;
00405     return explain_have_permission(st, hip, 0111);
00406 }
00407 
00408 
00409 int
00410 explain_explain_search_permission(explain_string_buffer_t *sb,
00411     const struct stat *st, const explain_have_identity_t *hip)
00412 {
00413     int             result;
00414 
00415     if (!S_ISDIR(st->st_mode))
00416         return 0;
00417     if (explain_capability_dac_read_search())
00418         return 1;
00419     result = explain_explain_permission(sb, st, hip, 0111);
00420     if (!result)
00421         explain_buffer_dac_read_search(sb);
00422     return result;
00423 }
00424 
00425 
00426 int
00427 explain_have_inode_permission(const struct stat *st,
00428     const explain_have_identity_t *hip)
00429 {
00430     if (explain_capability_fowner())
00431         return 1;
00432     return ((uid_t)hip->uid == st->st_uid);
00433 }
00434 
00435 
00436 const char *
00437 explain_have_identity_kind_of_uid(const explain_have_identity_t *hip)
00438 {
00439     if ((uid_t)hip->uid != geteuid())
00440     {
00441         return explain_translate_real_uid();
00442     }
00443     else
00444     {
00445         return explain_translate_effective_uid();
00446     }
00447 }
00448 
00449 
00450 const char *
00451 explain_have_identity_kind_of_gid(const explain_have_identity_t *hip)
00452 {
00453     if ((gid_t)hip->gid != getegid())
00454     {
00455         return explain_translate_real_gid();
00456     }
00457     else
00458     {
00459         return explain_translate_effective_gid();
00460     }
00461 }
00462 
00463 
00464 void
00465 explain_have_identity_init(explain_have_identity_t *hip)
00466 {
00467     hip->uid = geteuid();
00468     hip->gid = getegid();
00469 }
00470 
00471 
00472 /* vim: set ts=8 sw=4 et : */