Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2016 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 :
24 : #include "sbus/sssd_dbus.h"
25 : #include "providers/data_provider/dp_private.h"
26 : #include "providers/data_provider/dp_iface.h"
27 : #include "providers/backend.h"
28 : #include "util/util.h"
29 :
30 : #define FILTER_TYPE(str, type) {str "=", sizeof(str "=") - 1, type}
31 :
32 0 : static bool check_attr_type(uint32_t attr_type)
33 : {
34 0 : switch (attr_type) {
35 : case BE_ATTR_CORE:
36 : case BE_ATTR_MEM:
37 : case BE_ATTR_ALL:
38 0 : return true;
39 : default:
40 0 : return false;
41 : }
42 :
43 : return false;
44 : }
45 :
46 0 : static bool check_and_parse_filter(struct be_acct_req *data,
47 : const char *filter,
48 : const char *extra)
49 : {
50 : /* We will use sizeof() to determine the length of a string so we don't
51 : * call strlen over and over again with each request. Not a bottleneck,
52 : * but unnecessary and simple to avoid. */
53 : static struct {
54 : const char *name;
55 : size_t lenght;
56 : uint32_t type;
57 : } types[] = {FILTER_TYPE("name", BE_FILTER_NAME),
58 : FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
59 : FILTER_TYPE(DP_SEC_ID, BE_FILTER_SECID),
60 : FILTER_TYPE(DP_CERT, BE_FILTER_CERT),
61 : FILTER_TYPE(DP_WILDCARD, BE_FILTER_WILDCARD),
62 : {0, 0, 0}};
63 : int i;
64 :
65 0 : if (filter == NULL) {
66 0 : return false;
67 : }
68 :
69 0 : for (i = 0; types[i].name != NULL; i++) {
70 0 : if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
71 0 : data->filter_type = types[i].type;
72 0 : data->filter_value = &filter[types[i].lenght];
73 0 : data->extra_value = extra;
74 0 : return true;
75 : }
76 : }
77 :
78 0 : if (strcmp(filter, ENUM_INDICATOR) == 0) {
79 0 : data->filter_type = BE_FILTER_ENUM;
80 0 : data->filter_value = NULL;
81 0 : data->extra_value = NULL;
82 0 : return true;
83 : }
84 :
85 0 : return false;
86 : }
87 :
88 : struct dp_initgr_ctx {
89 : const char *username;
90 : const char *domain;
91 : uint32_t gnum;
92 : uint32_t *groups;
93 : };
94 :
95 0 : static struct dp_initgr_ctx *create_initgr_ctx(TALLOC_CTX *mem_ctx,
96 : const char *domain,
97 : struct ldb_result *res)
98 : {
99 : struct dp_initgr_ctx *ctx;
100 : const char *username;
101 : unsigned int i;
102 : errno_t ret;
103 :
104 0 : ctx = talloc_zero(mem_ctx, struct dp_initgr_ctx);
105 0 : if (ctx == NULL) {
106 0 : return NULL;
107 : }
108 :
109 0 : username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
110 0 : if (username == NULL) {
111 0 : ret = EINVAL;
112 0 : goto done;
113 : }
114 :
115 0 : ctx->username = talloc_strdup(ctx, username);
116 0 : if (ctx->username == NULL) {
117 0 : ret = ENOMEM;
118 0 : goto done;
119 : }
120 :
121 0 : ctx->domain = talloc_strdup(ctx, domain);
122 0 : if (ctx->domain == NULL) {
123 0 : ret = ENOMEM;
124 0 : goto done;
125 : }
126 :
127 0 : ctx->groups = talloc_array(mem_ctx, uint32_t, res->count);
128 0 : if (ctx->groups == NULL) {
129 0 : ret = ENOMEM;
130 0 : goto done;
131 : }
132 :
133 : /* The first GID is the primary so it might be duplicated
134 : * later in the list. */
135 0 : for (ctx->gnum = 0, i = 0; i < res->count; i++) {
136 0 : ctx->groups[ctx->gnum] = ldb_msg_find_attr_as_uint(res->msgs[i],
137 : SYSDB_GIDNUM, 0);
138 : /* If 0 it may be a non-posix group, so we skip it. */
139 0 : if (ctx->groups[ctx->gnum] != 0) {
140 0 : ctx->gnum++;
141 : }
142 : }
143 :
144 0 : ret = EOK;
145 :
146 : done:
147 0 : if (ret != EOK) {
148 0 : talloc_free(ctx);
149 0 : return NULL;
150 : }
151 :
152 0 : return ctx;
153 : }
154 :
155 0 : static void dp_req_initgr_pp(const char *req_name,
156 : struct data_provider *provider,
157 : struct dp_initgr_ctx *ctx,
158 : struct dp_reply_std *reply)
159 : {
160 : struct dp_client *dp_cli;
161 : DBusMessage *msg;
162 : dbus_bool_t dbret;
163 : int num;
164 :
165 0 : dp_cli = provider->clients[DPC_NSS];
166 0 : if (dp_cli == NULL) {
167 0 : return;
168 : }
169 :
170 0 : msg = dbus_message_new_method_call(NULL,
171 : DP_PATH,
172 : DATA_PROVIDER_REV_IFACE,
173 : DATA_PROVIDER_REV_IFACE_INITGRCHECK);
174 0 : if (msg == NULL) {
175 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
176 0 : return;
177 : }
178 :
179 0 : num = ctx->gnum;
180 0 : dbret = dbus_message_append_args(msg,
181 : DBUS_TYPE_STRING, &ctx->username,
182 : DBUS_TYPE_STRING, &ctx->domain,
183 : DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
184 : &ctx->groups, num,
185 : DBUS_TYPE_INVALID);
186 0 : if (!dbret) {
187 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
188 0 : dbus_message_unref(msg);
189 0 : return;
190 : }
191 :
192 0 : DEBUG(SSSDBG_TRACE_FUNC,
193 : "Ordering NSS responder to update memory cache\n");
194 :
195 0 : sbus_conn_send_reply(dp_client_conn(dp_cli), msg);
196 0 : dbus_message_unref(msg);
197 :
198 0 : return;
199 : }
200 :
201 0 : static errno_t dp_initgroups(struct sbus_request *sbus_req,
202 : struct dp_client *dp_cli,
203 : const char *key,
204 : uint32_t dp_flags,
205 : struct be_acct_req *data)
206 : {
207 : struct be_ctx *be_ctx;
208 : struct sss_domain_info *domain;
209 : struct dp_initgr_ctx *ctx;
210 : struct ldb_result *res;
211 : errno_t ret;
212 :
213 0 : be_ctx = dp_client_be(dp_cli);
214 :
215 0 : if (data->domain == NULL) {
216 0 : domain = be_ctx->domain;
217 : } else {
218 0 : domain = find_domain_by_name(be_ctx->domain, data->domain, true);
219 0 : if (domain == NULL) {
220 0 : return ERR_DOMAIN_NOT_FOUND;
221 : }
222 : }
223 :
224 0 : ret = sysdb_initgroups(sbus_req, domain, data->filter_value, &res);
225 0 : if (ret == ENOENT || (ret == EOK && res->count == 0)) {
226 : /* There is no point in concacting NSS responder. Proceed as usual. */
227 0 : return EAGAIN;
228 0 : } else if (ret != EOK) {
229 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get initgroups [%d]: %s\n",
230 : ret, sss_strerror(ret));
231 0 : goto done;
232 : }
233 :
234 0 : ctx = create_initgr_ctx(sbus_req, data->domain, res);
235 0 : if (ctx == NULL) {
236 0 : ret = ENOMEM;
237 0 : goto done;
238 : }
239 :
240 0 : dp_req_with_reply_pp(dp_cli, data->domain, "Initgroups", key,
241 : sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
242 : dp_req_initgr_pp, ctx, struct dp_initgr_ctx,
243 : dp_req_reply_std, struct dp_reply_std);
244 :
245 0 : ret = EOK;
246 :
247 : done:
248 0 : talloc_free(res);
249 0 : return ret;
250 : }
251 :
252 0 : errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
253 : void *dp_cli,
254 : uint32_t dp_flags,
255 : uint32_t entry_type,
256 : uint32_t attr_type,
257 : const char *filter,
258 : const char *domain,
259 : const char *extra)
260 : {
261 : struct be_acct_req *data;
262 : const char *key;
263 : errno_t ret;
264 :
265 0 : if (!check_attr_type(attr_type)) {
266 0 : return EINVAL;
267 : }
268 :
269 0 : data = talloc_zero(sbus_req, struct be_acct_req);
270 0 : if (data == NULL) {
271 0 : return ENOMEM;
272 : }
273 :
274 0 : data->entry_type = entry_type;
275 0 : data->attr_type = attr_type;
276 0 : data->domain = domain;
277 :
278 0 : if (!check_and_parse_filter(data, filter, extra)) {
279 0 : ret = EINVAL;
280 0 : goto done;
281 : }
282 :
283 0 : key = talloc_asprintf(data, "%u:%u:%s:%s:%s", data->entry_type,
284 : data->attr_type, extra, domain, filter);
285 0 : if (key == NULL) {
286 0 : ret = ENOMEM;
287 0 : goto done;
288 : }
289 :
290 0 : if ((data->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
291 0 : ret = dp_initgroups(sbus_req, dp_cli, key, dp_flags, data);
292 0 : if (ret != EAGAIN) {
293 0 : goto done;
294 : }
295 : }
296 :
297 0 : dp_req_with_reply(dp_cli, domain, "Account", key,
298 : sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
299 : dp_req_reply_std, struct dp_reply_std);
300 :
301 0 : ret = EOK;
302 :
303 : done:
304 0 : if (ret != EOK) {
305 0 : talloc_free(data);
306 : }
307 :
308 0 : return ret;
309 : }
|