libexplain  1.4.D001
libexplain/buffer/errno/setgid.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2012, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 
00021 #include <libexplain/buffer/dac.h>
00022 #include <libexplain/buffer/eperm.h>
00023 #include <libexplain/buffer/errno/generic.h>
00024 #include <libexplain/buffer/errno/setgid.h>
00025 #include <libexplain/buffer/gid.h>
00026 #include <libexplain/explanation.h>
00027 
00028 
00029 static void
00030 explain_buffer_errno_setgid_system_call(explain_string_buffer_t *sb, int errnum,
00031     gid_t gid)
00032 {
00033     (void)errnum;
00034     explain_string_buffer_puts(sb, "setgid(gid = ");
00035     explain_buffer_gid(sb, gid);
00036     explain_string_buffer_putc(sb, ')');
00037 }
00038 
00039 
00040 void
00041 explain_buffer_errno_setgid_explanation(explain_string_buffer_t *sb, int errnum,
00042     const char *syscall_name, gid_t gid)
00043 {
00044     /*
00045      * http://www.opengroup.org/onlinepubs/009695399/functions/setgid.html
00046      */
00047     switch (errnum)
00048     {
00049     case EPERM:
00050         /*
00051          * gid does not match the real group ID or saved group ID of the
00052          * calling process, and the user is not privileged (Linux: does
00053          * not have the CAP_SETGID capability).
00054          */
00055         {
00056             gid_t rgid;
00057             gid_t egid;
00058             gid_t sgid;
00059 #ifdef HAVE_GETRESUID
00060             if (getresgid(&rgid, &egid, &sgid) < 0)
00061             {
00062                 /* unlikely, only possible error is EFAULT */
00063                 rgid = getgid();
00064                 egid = rgid;
00065                 sgid = rgid;
00066             }
00067 #elif defined(GETREUID)
00068             if (getregid(&rgid, &egid) < 0)
00069             {
00070                 /* unlikely, only possible error is EFAULT */
00071                 rgid = getgid();
00072                 egid = rgid;
00073             }
00074             sgid = rgid;
00075 #else
00076             rgid = getgid();
00077             egid = rgid;
00078             sgid = rgid;
00079 #endif
00080             if (gid != rgid && gid != sgid)
00081             {
00082                 char rgid_str[100];
00083                 explain_string_buffer_t rgid_sb;
00084                 char sgid_str[100];
00085                 explain_string_buffer_t sgid_sb;
00086 
00087                 explain_string_buffer_init(&rgid_sb, rgid_str,
00088                     sizeof(rgid_str));
00089                 explain_buffer_gid(&rgid_sb, rgid);
00090                 explain_string_buffer_init(&sgid_sb, sgid_str,
00091                     sizeof(sgid_str));
00092                 explain_buffer_gid(&sgid_sb, sgid);
00093 
00094                 explain_string_buffer_printf_gettext
00095                 (
00096                     sb,
00097                     i18n
00098                     (
00099                         /*
00100                          * xgettext: This error message is used to explain an
00101                          * EPERM error reported by the setgid system call, in
00102                          * the case where gid does not match the real group ID
00103                          * or saved group ID of the calling process, and the
00104                          * user is not privileged (Linux: does not have the
00105                          * CAP_SETUID capability)
00106                          */
00107                         "gid does not match the real group ID (%1$s) or "
00108                         "the saved group ID (%2$s) of the calling process"
00109                     ),
00110                     rgid_str,
00111                     sgid_str
00112                 );
00113                 explain_buffer_dac_setgid(sb);
00114                 break;
00115             }
00116         }
00117         /* Fall through... */
00118 
00119     default:
00120         explain_buffer_errno_generic(sb, errnum, syscall_name);
00121         break;
00122     }
00123 }
00124 
00125 
00126 void
00127 explain_buffer_errno_setgid(explain_string_buffer_t *sb, int errnum, gid_t gid)
00128 {
00129     explain_explanation_t exp;
00130 
00131     explain_explanation_init(&exp, errnum);
00132     explain_buffer_errno_setgid_system_call(&exp.system_call_sb, errnum, gid);
00133     explain_buffer_errno_setgid_explanation(&exp.explanation_sb, errnum,
00134         "setgid", gid);
00135     explain_explanation_assemble(&exp, sb);
00136 }
00137 
00138 
00139 /* vim: set ts=8 sw=4 et : */