1 /*
2 (C) 2013, 2016 Percona LLC and/or its affiliates
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18 #include <pwd.h>
19 #include <grp.h>
20 #include <errno.h>
21 #include <my_sys.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 static int gr_buf_size= 0;
27
28 /** Groups iterator. It's not exposed outsude */
29 struct groups_iter {
30 char *buf;
31 gid_t *groups;
32 int current_group;
33 int ngroups;
34 int buf_size;
35 };
36
37 /** Create iterator through user groups.
38 Initially iterator set to position before first
39 group. On success non-NULL pointer returned, otherwise NULL */
groups_iter_new(const char * user_name)40 struct groups_iter *groups_iter_new(const char *user_name)
41 {
42 struct passwd pwd, *pwd_result;
43 int error;
44 struct groups_iter *it;
45
46 if (gr_buf_size <= 0)
47 {
48 long gr_size_max, pw_size_max;
49 gr_size_max= sysconf(_SC_GETGR_R_SIZE_MAX);
50 pw_size_max= sysconf(_SC_GETPW_R_SIZE_MAX);
51 gr_buf_size= gr_size_max > pw_size_max ? gr_size_max : pw_size_max;
52 }
53
54 it= (struct groups_iter *) my_malloc(sizeof(struct groups_iter),
55 MYF(MY_FAE | MY_ZEROFILL));
56
57 it->buf_size= gr_buf_size;
58 if (it->buf_size <= 0)
59 it->buf_size= 1024;
60
61 it->buf= (char *) my_malloc(it->buf_size, MYF(MY_FAE));
62
63 while ((error= getpwnam_r(user_name, &pwd, it->buf, it->buf_size,
64 &pwd_result)) == ERANGE)
65 {
66 it->buf_size= it->buf_size * 2;
67 it->buf= (char *) my_realloc(it->buf, it->buf_size, MYF(MY_FAE));
68 }
69 if (error != 0 || pwd_result == NULL)
70 {
71 fprintf(stderr, "auth_pam: Unable to obtain the passwd entry for the user "
72 "'%s'.", user_name);
73 my_free(it->buf);
74 my_free(it);
75 return NULL;
76 }
77
78 gr_buf_size= it->buf_size;
79
80 it->ngroups= 1024;
81 it->groups= (gid_t *) my_malloc(it->ngroups * sizeof(gid_t), MYF(MY_FAE));
82 error= getgrouplist(user_name, pwd_result->pw_gid, it->groups, &it->ngroups);
83 if (error == -1)
84 {
85 it->groups= (gid_t *) my_realloc(it->groups, it->ngroups * sizeof(gid_t),
86 MYF(MY_FAE));
87 error= getgrouplist(user_name, pwd_result->pw_gid, it->groups,
88 &it->ngroups);
89 if (error == -1)
90 {
91 fprintf(stderr, "auth_pam: Unable to obtain the group access list for "
92 "the user '%s'.", user_name);
93 my_free(it->buf);
94 my_free(it->groups);
95 my_free(it);
96 return NULL;
97 }
98 }
99
100 return it;
101 }
102
103 /** Move iterator to next group.
104 On success group name is returned,
105 otherwise NULL */
groups_iter_next(struct groups_iter * it)106 const char *groups_iter_next(struct groups_iter *it)
107 {
108 struct group grp, *grp_result;
109 int error;
110
111 if (it->current_group >= it->ngroups)
112 return NULL;
113
114 while ((error= getgrgid_r(it->groups[it->current_group], &grp, it->buf,
115 it->buf_size, &grp_result)) == ERANGE)
116 {
117 it->buf_size= it->buf_size * 2;
118 it->buf= (char *) my_realloc(it->buf, it->buf_size, MYF(MY_FAE));
119 }
120 if (error != 0 || grp_result == NULL)
121 {
122 fprintf(stderr, "auth_pam: Unable to obtain the group record for the group "
123 "id %d.", (int) it->groups[it->current_group]);
124 return NULL;
125 }
126 ++it->current_group;
127
128 return grp_result->gr_name;
129 }
130
131 /** Make iterator to point to the beginning again */
groups_iter_reset(struct groups_iter * it)132 void groups_iter_reset(struct groups_iter *it)
133 {
134 it->current_group= 0;
135 }
136
137 /** Finish iteration and release iterator */
groups_iter_free(struct groups_iter * it)138 void groups_iter_free(struct groups_iter *it)
139 {
140 my_free(it->buf);
141 my_free(it->groups);
142 my_free(it);
143 }
144
145