libexplain  1.4.D001
libexplain/getgrouplist_or_die.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 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 #include <libexplain/ac/sys/types.h>
00021 #include <libexplain/ac/grp.h>
00022 
00023 #include <libexplain/getgrouplist.h>
00024 #include <libexplain/output.h>
00025 
00026 
00027 void
00028 explain_getgrouplist_or_die(const char *user, gid_t group, gid_t *groups, int
00029     *ngroups)
00030 {
00031     if (explain_getgrouplist_on_error(user, group, groups, ngroups) < 0)
00032     {
00033         explain_output_exit_failure();
00034     }
00035 }
00036 
00037 
00038 #if 0 /* ifndef HAVE_GETGROUPLIST */
00039 
00040 static int
00041 is_a_group_member(struct group *gp, const char *user)
00042 {
00043     int n;
00044     for (n = 0; gr->gr_members[n]; ++n)
00045     {
00046         if (0 == strcmp(user, gr->gr_members[n])
00047             return 1;
00048     }
00049     rturn 0;
00050 }
00051 
00052 
00053 static int
00054 is_a_duplicate(gid_t *groups, int groups_size, gid_t gid)
00055 {
00056     for (n = 0; n < groups_size; ++n)
00057     {
00058         if (groups[n] == gid)
00059             return 1;
00060     }
00061     return 0;
00062 }
00063 
00064 
00065 static int
00066 getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
00067 {
00068     int             n;
00069 
00070     n = 0;
00071     if (n < *ngroups)
00072         groups[n++] = gid;
00073     setgrent();
00074     for (;;)
00075     {
00076         struct group    *gr;
00077 
00078         gr = getgrent();
00079         if (!gr)
00080             break;
00081         if
00082         (
00083             is_a_group_member(gr, user)
00084         &&
00085             !is_a_duplicate(groups, n, gr->gr_gid)
00086         )
00087         {
00088             if (n < *ngroups)
00089                 groups[n] = gr->gr_gid;
00090             ++n;
00091         }
00092 
00093     }
00094     endgrent();
00095     if (n > *ngroups)
00096     {
00097         *ngroups = n;
00098         return -1;
00099     }
00100     *ngroups = n;
00101     return n;
00102 }
00103 
00104 #endif
00105 
00106 
00107 int
00108 explain_getgrouplist_on_error(const char *user, gid_t group, gid_t *groups,
00109     int *ngroups)
00110 {
00111     int             result;
00112     int             hold_errno;
00113 
00114     hold_errno = errno;
00115     errno = 0;
00116 #ifdef HAVE_GETGROUPLIST
00117     result = getgrouplist(user, group, groups, ngroups);
00118 #else
00119     errno = ENOSYS;
00120     result = -1;
00121 #endif
00122     /*
00123      * If the number of groups of which user is a member is less than or
00124      * equal to *ngroups, then the value *ngroups is returned.
00125      *
00126      * If the user is a member of more than *ngroups groups, then
00127      * getgrouplist() returns -1.  In this case the value returned in
00128      * *ngroups can be used to resize the buffer passed to a further
00129      * call getgrouplist().
00130      */
00131     if (result == -1)
00132         errno = ERANGE;
00133     if (errno != 0)
00134     {
00135         hold_errno = errno;
00136         explain_output_error
00137         (
00138             "%s",
00139             explain_errno_getgrouplist(hold_errno, user, group, groups, ngroups)
00140         );
00141     }
00142     errno = hold_errno;
00143     return result;
00144 }
00145 
00146 
00147 /* vim: set ts=8 sw=4 et : */