libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2010, 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/errno.h> 00021 #include <libexplain/ac/sys/param.h> 00022 #include <libexplain/ac/sys/stat.h> 00023 #include <libexplain/ac/unistd.h> 00024 00025 #include <libexplain/buffer/access_mode.h> 00026 #include <libexplain/buffer/eacces.h> 00027 #include <libexplain/buffer/efault.h> 00028 #include <libexplain/buffer/einval.h> 00029 #include <libexplain/buffer/eio.h> 00030 #include <libexplain/buffer/eloop.h> 00031 #include <libexplain/buffer/enametoolong.h> 00032 #include <libexplain/buffer/enoent.h> 00033 #include <libexplain/buffer/enomem.h> 00034 #include <libexplain/buffer/enotdir.h> 00035 #include <libexplain/buffer/erofs.h> 00036 #include <libexplain/buffer/errno/access.h> 00037 #include <libexplain/buffer/errno/generic.h> 00038 #include <libexplain/buffer/errno/path_resolution.h> 00039 #include <libexplain/buffer/etxtbsy.h> 00040 #include <libexplain/buffer/gettext.h> 00041 #include <libexplain/buffer/path_to_pid.h> 00042 #include <libexplain/buffer/pathname.h> 00043 #include <libexplain/dirname.h> 00044 #include <libexplain/explanation.h> 00045 #include <libexplain/have_permission.h> 00046 #include <libexplain/pathname_is_a_directory.h> 00047 00048 00049 static void 00050 explain_buffer_errno_access_call(explain_string_buffer_t *sb, int errnum, 00051 const char *pathname, int mode) 00052 { 00053 (void)errnum; 00054 explain_string_buffer_puts(sb, "access(pathname = "); 00055 explain_buffer_pathname(sb, pathname); 00056 explain_string_buffer_puts(sb, ", mode = "); 00057 explain_buffer_access_mode(sb, mode); 00058 explain_string_buffer_putc(sb, ')'); 00059 } 00060 00061 00062 void 00063 explain_buffer_errno_access_explanation(explain_string_buffer_t *sb, 00064 int errnum, const char *syscall_name, const char *pathname, int mode) 00065 { 00066 explain_final_t final_component; 00067 00068 /* 00069 * Translate the mode into final component flags. 00070 */ 00071 explain_final_init(&final_component); 00072 if (mode & R_OK) 00073 final_component.want_to_read = 1; 00074 if (mode & W_OK) 00075 final_component.want_to_write = 1; 00076 if (mode & X_OK) 00077 { 00078 if (explain_pathname_is_a_directory(pathname)) 00079 final_component.want_to_search = 1; 00080 else 00081 final_component.want_to_execute = 1; 00082 } 00083 00084 /* 00085 * The Linux access(2) man page says 00086 * 00087 * The check is done using the process's real UID and 00088 * GID, rather than the effective IDs as is done when actually 00089 * attempting an operation (e.g., open(2)) on the file. This 00090 * allows set-user-ID programs to easily determine the invoking 00091 * user's authority. 00092 * 00093 * we will warn them about this later. 00094 */ 00095 final_component.id.uid = getuid(); 00096 final_component.id.gid = getgid(); 00097 00098 switch (errnum) 00099 { 00100 case EACCES: 00101 explain_buffer_eacces(sb, pathname, "pathname", &final_component); 00102 00103 /* 00104 * If they asked for more than one permission, explain that they 00105 * must all succeed. (Obviously, to get this error, at least 00106 * one failed.) 00107 */ 00108 if (mode != (mode & -mode)) 00109 { 00110 explain_string_buffer_puts(sb->footnotes, "; "); 00111 explain_buffer_gettext 00112 ( 00113 sb->footnotes, 00114 /* 00115 * xgettext: This message is used when supplementing an 00116 * EACCES error returned by the access(2) system call, 00117 * to remind users that it is an error if ANY of the 00118 * access types in mode are denied, even if some of the 00119 * other access types in mode would be permitted. 00120 */ 00121 i18n("note that it is an error if any of the access " 00122 "types in mode are denied, even if some of the other " 00123 "access types in mode would be permitted") 00124 ); 00125 } 00126 00127 if (getuid() != geteuid() || getgid() != getgid()) 00128 { 00129 explain_string_buffer_puts(sb->footnotes, "; "); 00130 explain_buffer_gettext 00131 ( 00132 sb->footnotes, 00133 /* 00134 * xgettext: This message is used when supplementing 00135 * and explanation for an EACCES error reported by 00136 * an access(2) system call, in the case where the 00137 * effective ID does not match the actual ID. 00138 * 00139 * This text taken from the Linux access(2) man page. 00140 */ 00141 i18n("warning: using access(2) to check if a user is " 00142 "authorized, for example to verify a file before actually " 00143 "using open(2), creates a security hole, because an attacker " 00144 "might exploit the short time interval between checking " 00145 "the file and opening the file to manipulate it; for this " 00146 "reason, this use of access(2) should be avoided") 00147 ); 00148 00149 /* 00150 * FIXME: should we mention setresuid as a better way? 00151 */ 00152 } 00153 break; 00154 00155 case ELOOP: 00156 case EMLINK: /* BSD */ 00157 explain_buffer_eloop(sb, pathname, "pathname", &final_component); 00158 break; 00159 00160 case ENAMETOOLONG: 00161 explain_buffer_enametoolong 00162 ( 00163 sb, 00164 pathname, 00165 "pathname", 00166 &final_component 00167 ); 00168 break; 00169 00170 case ENOENT: 00171 explain_buffer_enoent(sb, pathname, "pathname", &final_component); 00172 break; 00173 00174 case ENOTDIR: 00175 explain_buffer_enotdir(sb, pathname, "pathname", &final_component); 00176 break; 00177 00178 case EROFS: 00179 explain_buffer_erofs(sb, pathname, "pathname"); 00180 break; 00181 00182 case EFAULT: 00183 explain_buffer_efault(sb, "pathname"); 00184 break; 00185 00186 case EINVAL: 00187 explain_buffer_einval_bits(sb, "mode"); 00188 break; 00189 00190 case EIO: 00191 explain_buffer_eio_path(sb, pathname); 00192 break; 00193 00194 case ENOMEM: 00195 explain_buffer_enomem_kernel(sb); 00196 break; 00197 00198 case ETXTBSY: 00199 explain_buffer_etxtbsy(sb, pathname); 00200 break; 00201 00202 default: 00203 explain_buffer_errno_generic(sb, errnum, syscall_name); 00204 break; 00205 } 00206 } 00207 00208 00209 void 00210 explain_buffer_errno_access(explain_string_buffer_t *sb, int errnum, 00211 const char *pathname, int mode) 00212 { 00213 explain_explanation_t exp; 00214 00215 explain_explanation_init(&exp, errnum); 00216 explain_buffer_errno_access_call 00217 ( 00218 &exp.system_call_sb, 00219 errnum, 00220 pathname, 00221 mode 00222 ); 00223 explain_buffer_errno_access_explanation 00224 ( 00225 &exp.explanation_sb, 00226 errnum, 00227 "access", 00228 pathname, 00229 mode 00230 ); 00231 explain_explanation_assemble(&exp, sb); 00232 } 00233 00234 00235 /* vim: set ts=8 sw=4 et : */