Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Helper routines - external users and groups with s2n plugin
5 :
6 : Copyright (C) Sumit Bose <sbose@redhat.com> - 2011
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "util/util.h"
23 : #include "util/sss_nss.h"
24 : #include "util/strtonum.h"
25 : #include "util/crypto/sss_crypto.h"
26 : #include "providers/ldap/sdap_async_private.h"
27 : #include "providers/ldap/sdap_async_ad.h"
28 : #include "providers/ldap/ldap_common.h"
29 : #include "providers/ldap/sdap_idmap.h"
30 : #include "providers/ipa/ipa_id.h"
31 : #include "providers/ipa/ipa_subdomains.h"
32 : #include "providers/ad/ad_pac.h"
33 : #include "db/sysdb.h"
34 :
35 : enum input_types {
36 : INP_SID = 1,
37 : INP_NAME,
38 : INP_POSIX_UID,
39 : INP_POSIX_GID,
40 : INP_CERT
41 : };
42 :
43 : enum request_types {
44 : REQ_SIMPLE = 1,
45 : REQ_FULL,
46 : REQ_FULL_WITH_MEMBERS
47 : };
48 :
49 : enum response_types {
50 : RESP_SID = 1,
51 : RESP_NAME,
52 : RESP_USER,
53 : RESP_GROUP,
54 : RESP_USER_GROUPLIST,
55 : RESP_GROUP_MEMBERS
56 : };
57 :
58 : /* ==Sid2Name Extended Operation============================================= */
59 : struct ipa_s2n_exop_state {
60 : struct sdap_handle *sh;
61 :
62 : struct sdap_op *op;
63 :
64 : char *retoid;
65 : struct berval *retdata;
66 : };
67 :
68 : static void ipa_s2n_exop_done(struct sdap_op *op,
69 : struct sdap_msg *reply,
70 : int error, void *pvt);
71 :
72 0 : static struct tevent_req *ipa_s2n_exop_send(TALLOC_CTX *mem_ctx,
73 : struct tevent_context *ev,
74 : struct sdap_handle *sh,
75 : bool is_v1,
76 : int timeout,
77 : struct berval *bv)
78 : {
79 0 : struct tevent_req *req = NULL;
80 : struct ipa_s2n_exop_state *state;
81 : int ret;
82 : int msgid;
83 :
84 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_exop_state);
85 0 : if (!req) return NULL;
86 :
87 0 : state->sh = sh;
88 0 : state->retoid = NULL;
89 0 : state->retdata = NULL;
90 :
91 0 : DEBUG(SSSDBG_TRACE_FUNC, "Executing extended operation\n");
92 :
93 0 : ret = ldap_extended_operation(state->sh->ldap,
94 : is_v1 ? EXOP_SID2NAME_V1_OID : EXOP_SID2NAME_OID,
95 : bv, NULL, NULL, &msgid);
96 0 : if (ret == -1 || msgid == -1) {
97 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ldap_extended_operation failed\n");
98 0 : ret = ERR_NETWORK_IO;
99 0 : goto fail;
100 : }
101 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "ldap_extended_operation sent, msgid = %d\n",
102 : msgid);
103 :
104 0 : ret = sdap_op_add(state, ev, state->sh, msgid, ipa_s2n_exop_done, req,
105 0 : timeout, &state->op);
106 0 : if (ret) {
107 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
108 0 : ret = ERR_INTERNAL;
109 0 : goto fail;
110 : }
111 :
112 0 : return req;
113 :
114 : fail:
115 0 : tevent_req_error(req, ret);
116 0 : tevent_req_post(req, ev);
117 0 : return req;
118 : }
119 :
120 0 : static void ipa_s2n_exop_done(struct sdap_op *op,
121 : struct sdap_msg *reply,
122 : int error, void *pvt)
123 : {
124 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
125 0 : struct ipa_s2n_exop_state *state = tevent_req_data(req,
126 : struct ipa_s2n_exop_state);
127 : int ret;
128 0 : char *errmsg = NULL;
129 0 : char *retoid = NULL;
130 0 : struct berval *retdata = NULL;
131 : int result;
132 :
133 0 : if (error) {
134 0 : tevent_req_error(req, error);
135 0 : return;
136 : }
137 :
138 0 : ret = ldap_parse_result(state->sh->ldap, reply->msg,
139 : &result, NULL, &errmsg, NULL,
140 : NULL, 0);
141 0 : if (ret != LDAP_SUCCESS) {
142 0 : DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n",
143 : state->op->msgid);
144 0 : ret = ERR_NETWORK_IO;
145 0 : goto done;
146 : }
147 :
148 0 : DEBUG(result == LDAP_SUCCESS ? SSSDBG_TRACE_FUNC : SSSDBG_OP_FAILURE,
149 : "ldap_extended_operation result: %s(%d), %s.\n",
150 : sss_ldap_err2string(result), result, errmsg);
151 :
152 0 : if (result != LDAP_SUCCESS) {
153 0 : if (result == LDAP_NO_SUCH_OBJECT) {
154 0 : ret = ENOENT;
155 : } else {
156 0 : DEBUG(SSSDBG_OP_FAILURE, "ldap_extended_operation failed, server " \
157 : "logs might contain more details.\n");
158 0 : ret = ERR_NETWORK_IO;
159 : }
160 0 : goto done;
161 : }
162 :
163 0 : ret = ldap_parse_extended_result(state->sh->ldap, reply->msg,
164 : &retoid, &retdata, 0);
165 0 : if (ret != LDAP_SUCCESS) {
166 0 : DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_extendend_result failed (%d)\n",
167 : ret);
168 0 : ret = ERR_NETWORK_IO;
169 0 : goto done;
170 : }
171 0 : if (retdata == NULL) {
172 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing exop result data.\n");
173 0 : ret = EINVAL;
174 0 : goto done;
175 : }
176 :
177 0 : state->retoid = talloc_strdup(state, retoid);
178 0 : if (state->retoid == NULL) {
179 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
180 0 : ret = ENOMEM;
181 0 : goto done;
182 : }
183 :
184 0 : state->retdata = talloc(state, struct berval);
185 0 : if (state->retdata == NULL) {
186 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n");
187 0 : ret = ENOMEM;
188 0 : goto done;
189 : }
190 0 : state->retdata->bv_len = retdata->bv_len;
191 0 : state->retdata->bv_val = talloc_memdup(state->retdata, retdata->bv_val,
192 : retdata->bv_len);
193 0 : if (state->retdata->bv_val == NULL) {
194 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
195 0 : ret = ENOMEM;
196 0 : goto done;
197 : }
198 :
199 0 : ret = EOK;
200 :
201 : done:
202 0 : ldap_memfree(errmsg);
203 0 : ldap_memfree(retoid);
204 0 : ber_bvfree(retdata);
205 0 : if (ret == EOK) {
206 0 : tevent_req_done(req);
207 : } else {
208 0 : tevent_req_error(req, ret);
209 : }
210 : }
211 :
212 0 : static int ipa_s2n_exop_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
213 : char **retoid, struct berval **retdata)
214 : {
215 0 : struct ipa_s2n_exop_state *state = tevent_req_data(req,
216 : struct ipa_s2n_exop_state);
217 :
218 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
219 :
220 0 : *retoid = talloc_steal(mem_ctx, state->retoid);
221 0 : *retdata = talloc_steal(mem_ctx, state->retdata);
222 :
223 0 : return EOK;
224 : }
225 :
226 0 : static errno_t talloc_ber_flatten(TALLOC_CTX *mem_ctx, BerElement *ber,
227 : struct berval **_bv)
228 : {
229 : int ret;
230 0 : struct berval *bv = NULL;
231 0 : struct berval *tbv = NULL;
232 :
233 0 : ret = ber_flatten(ber, &bv);
234 0 : if (ret == -1) {
235 0 : ret = EFAULT;
236 0 : goto done;
237 : }
238 :
239 0 : tbv = talloc_zero(mem_ctx, struct berval);
240 0 : if (tbv == NULL) {
241 0 : ret = ENOMEM;
242 0 : goto done;
243 : }
244 :
245 0 : tbv->bv_len = bv->bv_len;
246 0 : tbv->bv_val = talloc_memdup(tbv, bv->bv_val, bv->bv_len);
247 0 : if (tbv->bv_val == NULL) {
248 0 : ret = ENOMEM;
249 0 : goto done;
250 : }
251 :
252 0 : ret = EOK;
253 :
254 : done:
255 0 : ber_bvfree(bv);
256 0 : if (ret == EOK) {
257 0 : *_bv = tbv;
258 : } else {
259 0 : talloc_free(tbv);
260 : }
261 :
262 0 : return ret;
263 : }
264 :
265 : /* The extended operation expect the following ASN.1 encoded request data:
266 : *
267 : * ExtdomRequestValue ::= SEQUENCE {
268 : * inputType ENUMERATED {
269 : * sid (1),
270 : * name (2),
271 : * posix uid (3),
272 : * posix gid (3)
273 : * },
274 : * requestType ENUMERATED {
275 : * simple (1),
276 : * full (2)
277 : * full_with_members (3)
278 : * },
279 : * data InputData
280 : * }
281 : *
282 : * InputData ::= CHOICE {
283 : * sid OCTET STRING,
284 : * name NameDomainData
285 : * uid PosixUid,
286 : * gid PosixGid
287 : * }
288 : *
289 : * NameDomainData ::= SEQUENCE {
290 : * domain_name OCTET STRING,
291 : * object_name OCTET STRING
292 : * }
293 : *
294 : * PosixUid ::= SEQUENCE {
295 : * domain_name OCTET STRING,
296 : * uid INTEGER
297 : * }
298 : *
299 : * PosixGid ::= SEQUENCE {
300 : * domain_name OCTET STRING,
301 : * gid INTEGER
302 : * }
303 : *
304 : */
305 :
306 0 : static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx,
307 : const char *domain_name,
308 : int entry_type,
309 : enum request_types request_type,
310 : struct req_input *req_input,
311 : struct berval **_bv)
312 : {
313 0 : BerElement *ber = NULL;
314 : int ret;
315 :
316 0 : ber = ber_alloc_t( LBER_USE_DER );
317 0 : if (ber == NULL) {
318 0 : return ENOMEM;
319 : }
320 :
321 0 : switch (entry_type) {
322 : case BE_REQ_USER:
323 : case BE_REQ_USER_AND_GROUP: /* the extdom exop does not care if the
324 : ID belongs to a user or a group */
325 0 : if (req_input->type == REQ_INP_NAME) {
326 0 : ret = ber_printf(ber, "{ee{ss}}", INP_NAME, request_type,
327 : domain_name,
328 : req_input->inp.name);
329 0 : } else if (req_input->type == REQ_INP_ID) {
330 0 : ret = ber_printf(ber, "{ee{si}}", INP_POSIX_UID, request_type,
331 : domain_name,
332 : req_input->inp.id);
333 : } else {
334 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
335 : req_input->type == REQ_INP_ID);
336 0 : ret = EINVAL;
337 0 : goto done;
338 : }
339 0 : break;
340 : case BE_REQ_GROUP:
341 0 : if (req_input->type == REQ_INP_NAME) {
342 0 : ret = ber_printf(ber, "{ee{ss}}", INP_NAME, request_type,
343 : domain_name,
344 : req_input->inp.name);
345 0 : } else if (req_input->type == REQ_INP_ID) {
346 0 : ret = ber_printf(ber, "{ee{si}}", INP_POSIX_GID, request_type,
347 : domain_name,
348 : req_input->inp.id);
349 : } else {
350 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
351 : req_input->type == REQ_INP_ID);
352 0 : ret = EINVAL;
353 0 : goto done;
354 : }
355 0 : break;
356 : case BE_REQ_BY_SECID:
357 0 : if (req_input->type == REQ_INP_SECID) {
358 0 : ret = ber_printf(ber, "{ees}", INP_SID, request_type,
359 : req_input->inp.secid);
360 : } else {
361 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
362 : req_input->type == REQ_INP_ID);
363 0 : ret = EINVAL;
364 0 : goto done;
365 : }
366 0 : break;
367 : case BE_REQ_BY_CERT:
368 0 : if (req_input->type == REQ_INP_CERT) {
369 0 : ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
370 : req_input->inp.cert);
371 : } else {
372 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
373 : req_input->type);
374 0 : ret = EINVAL;
375 0 : goto done;
376 : }
377 0 : break;
378 : default:
379 0 : ret = EINVAL;
380 0 : goto done;
381 : }
382 0 : if (ret == -1) {
383 0 : ret = EFAULT;
384 0 : goto done;
385 : }
386 :
387 0 : ret = talloc_ber_flatten(mem_ctx, ber, _bv);
388 0 : if (ret != EOK) {
389 0 : goto done;
390 : }
391 :
392 0 : ret = EOK;
393 :
394 : done:
395 0 : ber_free(ber, 1);
396 :
397 0 : return ret;
398 : }
399 :
400 : /* If the extendend operation is successful it returns the following ASN.1
401 : * encoded response:
402 : *
403 : * ExtdomResponseValue ::= SEQUENCE {
404 : * responseType ENUMERATED {
405 : * sid (1),
406 : * name (2),
407 : * posix_user (3),
408 : * posix_group (4),
409 : * posix_user_grouplist (5),
410 : * posix_group_members (6)
411 : * },
412 : * data OutputData
413 : * }
414 : *
415 : * OutputData ::= CHOICE {
416 : * sid OCTET STRING,
417 : * name NameDomainData,
418 : * user PosixUser,
419 : * group PosixGroup,
420 : * usergrouplist PosixUserGrouplist,
421 : * groupmembers PosixGroupMembers
422 : *
423 : * }
424 : *
425 : * NameDomainData ::= SEQUENCE {
426 : * domain_name OCTET STRING,
427 : * object_name OCTET STRING
428 : * }
429 : *
430 : * PosixUser ::= SEQUENCE {
431 : * domain_name OCTET STRING,
432 : * user_name OCTET STRING,
433 : * uid INTEGER
434 : * gid INTEGER
435 : * }
436 : *
437 : * PosixGroup ::= SEQUENCE {
438 : * domain_name OCTET STRING,
439 : * group_name OCTET STRING,
440 : * gid INTEGER
441 : * }
442 : *
443 : * PosixUserGrouplist ::= SEQUENCE {
444 : * domain_name OCTET STRING,
445 : * user_name OCTET STRING,
446 : * uid INTEGER,
447 : * gid INTEGER,
448 : * gecos OCTET STRING,
449 : * home_directory OCTET STRING,
450 : * shell OCTET STRING,
451 : * grouplist GroupNameList
452 : * }
453 : *
454 : * GroupNameList ::= SEQUENCE OF OCTET STRING
455 : *
456 : * PosixGroupMembers ::= SEQUENCE {
457 : * domain_name OCTET STRING,
458 : * group_name OCTET STRING,
459 : * gid INTEGER,
460 : * members GroupMemberList
461 : * }
462 : *
463 : * GroupMemberList ::= SEQUENCE OF OCTET STRING
464 : */
465 :
466 : struct resp_attrs {
467 : enum response_types response_type;
468 : char *domain_name;
469 : union {
470 : struct passwd user;
471 : struct group group;
472 : char *sid_str;
473 : char *name;
474 : } a;
475 : size_t ngroups;
476 : char **groups;
477 : struct sysdb_attrs *sysdb_attrs;
478 : };
479 :
480 0 : static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs)
481 : {
482 : ber_tag_t tag;
483 : ber_len_t ber_len;
484 : char *ber_cookie;
485 : char *name;
486 : struct berval **values;
487 : struct ldb_val v;
488 : int ret;
489 : size_t c;
490 :
491 0 : if (resp_attrs->sysdb_attrs == NULL) {
492 0 : resp_attrs->sysdb_attrs = sysdb_new_attrs(resp_attrs);
493 0 : if (resp_attrs->sysdb_attrs == NULL) {
494 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
495 0 : return ENOMEM;
496 : }
497 : }
498 :
499 0 : DEBUG(SSSDBG_TRACE_ALL, "Found new sequence.\n");
500 0 : for (tag = ber_first_element(ber, &ber_len, &ber_cookie);
501 : tag != LBER_DEFAULT;
502 0 : tag = ber_next_element(ber, &ber_len, ber_cookie)) {
503 :
504 0 : tag = ber_scanf(ber, "{a{V}}", &name, &values);
505 0 : if (tag == LBER_ERROR) {
506 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
507 0 : return EINVAL;
508 : }
509 0 : DEBUG(SSSDBG_TRACE_ALL, "Extra attribute [%s].\n", name);
510 :
511 0 : for (c = 0; values[c] != NULL; c++) {
512 :
513 0 : if (strcmp(name, SYSDB_USER_CERT) == 0) {
514 0 : if (values[c]->bv_val[values[c]->bv_len] != '\0') {
515 0 : DEBUG(SSSDBG_OP_FAILURE,
516 : "base64 encoded certificate not 0-terminated.\n");
517 0 : return EINVAL;
518 : }
519 :
520 0 : v.data = sss_base64_decode(NULL, values[c]->bv_val, &v.length);
521 0 : if (v.data == NULL) {
522 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
523 0 : return EINVAL;
524 : }
525 : } else {
526 0 : v.data = (uint8_t *)values[c]->bv_val;
527 0 : v.length = values[c]->bv_len;
528 : }
529 :
530 0 : ret = sysdb_attrs_add_val(resp_attrs->sysdb_attrs, name, &v);
531 0 : if (ret != EOK) {
532 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
533 0 : ldap_memfree(name);
534 0 : ber_bvecfree(values);
535 0 : return ret;
536 : }
537 : }
538 :
539 0 : ldap_memfree(name);
540 0 : ber_bvecfree(values);
541 : }
542 :
543 0 : return EOK;
544 : }
545 :
546 0 : static errno_t add_v1_user_data(BerElement *ber, struct resp_attrs *attrs)
547 : {
548 : ber_tag_t tag;
549 : ber_len_t ber_len;
550 : int ret;
551 0 : char *gecos = NULL;
552 0 : char *homedir = NULL;
553 0 : char *shell = NULL;
554 0 : char **list = NULL;
555 : size_t c;
556 :
557 0 : tag = ber_scanf(ber, "aaa", &gecos, &homedir, &shell);
558 0 : if (tag == LBER_ERROR) {
559 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
560 0 : ret = EINVAL;
561 0 : goto done;
562 : }
563 :
564 0 : if (gecos == NULL || *gecos == '\0') {
565 0 : attrs->a.user.pw_gecos = NULL;
566 : } else {
567 0 : attrs->a.user.pw_gecos = talloc_strdup(attrs, gecos);
568 0 : if (attrs->a.user.pw_gecos == NULL) {
569 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
570 0 : ret = ENOMEM;
571 0 : goto done;
572 : }
573 : }
574 :
575 0 : if (homedir == NULL || *homedir == '\0') {
576 0 : attrs->a.user.pw_dir = NULL;
577 : } else {
578 0 : attrs->a.user.pw_dir = talloc_strdup(attrs, homedir);
579 0 : if (attrs->a.user.pw_dir == NULL) {
580 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
581 0 : ret = ENOMEM;
582 0 : goto done;
583 : }
584 : }
585 :
586 0 : if (shell == NULL || *shell == '\0') {
587 0 : attrs->a.user.pw_shell = NULL;
588 : } else {
589 0 : attrs->a.user.pw_shell = talloc_strdup(attrs, shell);
590 0 : if (attrs->a.user.pw_shell == NULL) {
591 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
592 0 : ret = ENOMEM;
593 0 : goto done;
594 : }
595 : }
596 :
597 0 : tag = ber_scanf(ber, "{v}", &list);
598 0 : if (tag == LBER_ERROR) {
599 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
600 0 : ret = EINVAL;
601 0 : goto done;
602 : }
603 :
604 0 : for (attrs->ngroups = 0; list[attrs->ngroups] != NULL;
605 0 : attrs->ngroups++);
606 :
607 0 : if (attrs->ngroups > 0) {
608 0 : attrs->groups = talloc_zero_array(attrs, char *, attrs->ngroups + 1);
609 0 : if (attrs->groups == NULL) {
610 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
611 0 : ret = ENOMEM;
612 0 : goto done;
613 : }
614 :
615 0 : for (c = 0; c < attrs->ngroups; c++) {
616 0 : attrs->groups[c] = talloc_strdup(attrs->groups,
617 0 : list[c]);
618 0 : if (attrs->groups[c] == NULL) {
619 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
620 0 : ret = ENOMEM;
621 0 : goto done;
622 : }
623 : }
624 : }
625 :
626 0 : tag = ber_peek_tag(ber, &ber_len);
627 0 : DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
628 0 : if (tag == LBER_SEQUENCE) {
629 0 : ret = get_extra_attrs(ber, attrs);
630 0 : if (ret != EOK) {
631 0 : DEBUG(SSSDBG_OP_FAILURE, "get_extra_attrs failed.\n");
632 0 : goto done;
633 : }
634 : }
635 :
636 :
637 0 : ret = EOK;
638 :
639 : done:
640 0 : ber_memfree(gecos);
641 0 : ber_memfree(homedir);
642 0 : ber_memfree(shell);
643 0 : ber_memvfree((void **) list);
644 :
645 0 : return ret;
646 : }
647 :
648 0 : static errno_t add_v1_group_data(BerElement *ber, struct resp_attrs *attrs)
649 : {
650 : ber_tag_t tag;
651 : ber_len_t ber_len;
652 : int ret;
653 0 : char **list = NULL;
654 : size_t c;
655 :
656 0 : tag = ber_scanf(ber, "{v}", &list);
657 0 : if (tag == LBER_ERROR) {
658 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
659 0 : ret = EINVAL;
660 0 : goto done;
661 : }
662 :
663 0 : if (list != NULL) {
664 0 : for (attrs->ngroups = 0; list[attrs->ngroups] != NULL;
665 0 : attrs->ngroups++);
666 :
667 0 : if (attrs->ngroups > 0) {
668 0 : attrs->a.group.gr_mem = talloc_zero_array(attrs, char *,
669 : attrs->ngroups + 1);
670 0 : if (attrs->a.group.gr_mem == NULL) {
671 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
672 0 : ret = ENOMEM;
673 0 : goto done;
674 : }
675 :
676 0 : for (c = 0; c < attrs->ngroups; c++) {
677 0 : attrs->a.group.gr_mem[c] =
678 0 : talloc_strdup(attrs->a.group.gr_mem,
679 0 : list[c]);
680 0 : if (attrs->a.group.gr_mem[c] == NULL) {
681 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
682 0 : ret = ENOMEM;
683 0 : goto done;
684 : }
685 : }
686 : }
687 : } else {
688 0 : attrs->a.group.gr_mem = talloc_zero_array(attrs, char *, 1);
689 0 : if (attrs->a.group.gr_mem == NULL) {
690 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
691 0 : ret = ENOMEM;
692 0 : goto done;
693 : }
694 : }
695 :
696 0 : tag = ber_peek_tag(ber, &ber_len);
697 0 : DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
698 0 : if (tag == LBER_SEQUENCE) {
699 0 : ret = get_extra_attrs(ber, attrs);
700 0 : if (ret != EOK) {
701 0 : DEBUG(SSSDBG_OP_FAILURE, "get_extra_attrs failed.\n");
702 0 : goto done;
703 : }
704 : }
705 :
706 0 : ret = EOK;
707 :
708 : done:
709 0 : ber_memvfree((void **) list);
710 :
711 0 : return ret;
712 : }
713 :
714 : static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
715 : struct req_input *req_input,
716 : struct resp_attrs *attrs,
717 : struct resp_attrs *simple_attrs,
718 : const char *view_name,
719 : struct sysdb_attrs *override_attrs,
720 : bool update_initgr_timeout);
721 :
722 0 : static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
723 : char *retoid,
724 : struct berval *retdata,
725 : struct resp_attrs **resp_attrs)
726 : {
727 0 : BerElement *ber = NULL;
728 : ber_tag_t tag;
729 : int ret;
730 : enum response_types type;
731 0 : char *domain_name = NULL;
732 0 : char *name = NULL;
733 : uid_t uid;
734 : gid_t gid;
735 0 : struct resp_attrs *attrs = NULL;
736 : char *sid_str;
737 0 : bool is_v1 = false;
738 :
739 0 : if (retoid == NULL || retdata == NULL) {
740 0 : DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n");
741 0 : return EINVAL;
742 : }
743 :
744 0 : if (strcmp(retoid, EXOP_SID2NAME_V1_OID) == 0) {
745 0 : is_v1 = true;
746 0 : } else if (strcmp(retoid, EXOP_SID2NAME_OID) == 0) {
747 0 : is_v1 = false;
748 : } else {
749 0 : DEBUG(SSSDBG_OP_FAILURE,
750 : "Result has wrong OID, expected [%s] or [%s], got [%s].\n",
751 : EXOP_SID2NAME_OID, EXOP_SID2NAME_V1_OID, retoid);
752 0 : return EINVAL;
753 : }
754 :
755 0 : ber = ber_init(retdata);
756 0 : if (ber == NULL) {
757 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_init failed.\n");
758 0 : return EINVAL;
759 : }
760 :
761 0 : tag = ber_scanf(ber, "{e", &type);
762 0 : if (tag == LBER_ERROR) {
763 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
764 0 : ret = EINVAL;
765 0 : goto done;
766 : }
767 :
768 0 : attrs = talloc_zero(mem_ctx, struct resp_attrs);
769 0 : if (attrs == NULL) {
770 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
771 0 : ret = ENOMEM;
772 0 : goto done;
773 : }
774 :
775 0 : switch (type) {
776 : case RESP_USER:
777 : case RESP_USER_GROUPLIST:
778 0 : tag = ber_scanf(ber, "{aaii", &domain_name, &name, &uid, &gid);
779 0 : if (tag == LBER_ERROR) {
780 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
781 0 : ret = EINVAL;
782 0 : goto done;
783 : }
784 :
785 : /* Winbind is not consistent with the case of the returned user
786 : * name. In general all names should be lower case but there are
787 : * bug in some version of winbind which might lead to upper case
788 : * letters in the name. To be on the safe side we explicitly
789 : * lowercase the name. */
790 0 : attrs->a.user.pw_name = sss_tc_utf8_str_tolower(attrs, name);
791 0 : if (attrs->a.user.pw_name == NULL) {
792 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
793 0 : ret = ENOMEM;
794 0 : goto done;
795 : }
796 :
797 0 : attrs->a.user.pw_uid = uid;
798 0 : attrs->a.user.pw_gid = gid;
799 :
800 0 : if (is_v1 && type == RESP_USER_GROUPLIST) {
801 0 : ret = add_v1_user_data(ber, attrs);
802 0 : if (ret != EOK) {
803 0 : DEBUG(SSSDBG_OP_FAILURE, "add_v1_user_data failed.\n");
804 0 : goto done;
805 : }
806 : }
807 :
808 0 : tag = ber_scanf(ber, "}}");
809 0 : if (tag == LBER_ERROR) {
810 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
811 0 : ret = EINVAL;
812 0 : goto done;
813 : }
814 :
815 0 : break;
816 : case RESP_GROUP:
817 : case RESP_GROUP_MEMBERS:
818 0 : tag = ber_scanf(ber, "{aai", &domain_name, &name, &gid);
819 0 : if (tag == LBER_ERROR) {
820 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
821 0 : ret = EINVAL;
822 0 : goto done;
823 : }
824 :
825 : /* Winbind is not consistent with the case of the returned user
826 : * name. In general all names should be lower case but there are
827 : * bug in some version of winbind which might lead to upper case
828 : * letters in the name. To be on the safe side we explicitly
829 : * lowercase the name. */
830 0 : attrs->a.group.gr_name = sss_tc_utf8_str_tolower(attrs, name);
831 0 : if (attrs->a.group.gr_name == NULL) {
832 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
833 0 : ret = ENOMEM;
834 0 : goto done;
835 : }
836 :
837 0 : attrs->a.group.gr_gid = gid;
838 :
839 0 : if (is_v1 && type == RESP_GROUP_MEMBERS) {
840 0 : ret = add_v1_group_data(ber, attrs);
841 0 : if (ret != EOK) {
842 0 : DEBUG(SSSDBG_OP_FAILURE, "add_v1_group_data failed.\n");
843 0 : goto done;
844 : }
845 : }
846 :
847 0 : tag = ber_scanf(ber, "}}");
848 0 : if (tag == LBER_ERROR) {
849 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
850 0 : ret = EINVAL;
851 0 : goto done;
852 : }
853 :
854 0 : break;
855 : case RESP_SID:
856 0 : tag = ber_scanf(ber, "a}", &sid_str);
857 0 : if (tag == LBER_ERROR) {
858 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
859 0 : ret = EINVAL;
860 0 : goto done;
861 : }
862 :
863 0 : attrs->a.sid_str = talloc_strdup(attrs, sid_str);
864 0 : if (attrs->a.sid_str == NULL) {
865 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
866 0 : ret = ENOMEM;
867 0 : goto done;
868 : }
869 0 : break;
870 : case RESP_NAME:
871 0 : tag = ber_scanf(ber, "{aa}", &domain_name, &name);
872 0 : if (tag == LBER_ERROR) {
873 0 : DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
874 0 : ret = EINVAL;
875 0 : goto done;
876 : }
877 :
878 0 : attrs->a.name = sss_tc_utf8_str_tolower(attrs, name);
879 0 : if (attrs->a.name == NULL) {
880 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_tc_utf8_str_tolower failed.\n");
881 0 : ret = ENOMEM;
882 0 : goto done;
883 : }
884 0 : break;
885 : default:
886 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n",
887 : type);
888 0 : ret = EINVAL;
889 0 : goto done;
890 : }
891 :
892 0 : attrs->response_type = type;
893 0 : if (type != RESP_SID) {
894 0 : attrs->domain_name = talloc_strdup(attrs, domain_name);
895 0 : if (attrs->domain_name == NULL) {
896 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
897 0 : ret = ENOMEM;
898 0 : goto done;
899 : }
900 : }
901 :
902 0 : ret = EOK;
903 :
904 : done:
905 0 : ber_memfree(domain_name);
906 0 : ber_memfree(name);
907 0 : ber_free(ber, 1);
908 :
909 0 : if (ret == EOK) {
910 0 : *resp_attrs = attrs;
911 : } else {
912 0 : talloc_free(attrs);
913 : }
914 :
915 0 : return ret;
916 : }
917 :
918 : struct ipa_s2n_get_list_state {
919 : struct tevent_context *ev;
920 : struct ipa_id_ctx *ipa_ctx;
921 : struct sss_domain_info *dom;
922 : struct sdap_handle *sh;
923 : struct req_input req_input;
924 : char **list;
925 : size_t list_idx;
926 : int exop_timeout;
927 : int entry_type;
928 : enum request_types request_type;
929 : struct resp_attrs *attrs;
930 : struct sss_domain_info *obj_domain;
931 : struct sysdb_attrs *override_attrs;
932 : };
933 :
934 : static errno_t ipa_s2n_get_list_step(struct tevent_req *req);
935 : static void ipa_s2n_get_list_get_override_done(struct tevent_req *subreq);
936 : static void ipa_s2n_get_list_next(struct tevent_req *subreq);
937 : static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req);
938 :
939 0 : static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx,
940 : struct tevent_context *ev,
941 : struct ipa_id_ctx *ipa_ctx,
942 : struct sss_domain_info *dom,
943 : struct sdap_handle *sh,
944 : int exop_timeout,
945 : int entry_type,
946 : enum request_types request_type,
947 : enum req_input_type list_type,
948 : char **list)
949 : {
950 : int ret;
951 : struct ipa_s2n_get_list_state *state;
952 : struct tevent_req *req;
953 :
954 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_list_state);
955 0 : if (req == NULL) {
956 0 : return NULL;
957 : }
958 :
959 0 : if ((entry_type == BE_REQ_BY_SECID && list_type != REQ_INP_SECID)
960 0 : || (entry_type != BE_REQ_BY_SECID && list_type == REQ_INP_SECID)) {
961 0 : DEBUG(SSSDBG_OP_FAILURE, "Invalid parameter combination [%d][%d].\n",
962 : request_type, list_type);
963 0 : ret = EINVAL;
964 0 : goto done;
965 : }
966 :
967 0 : state->ev = ev;
968 0 : state->ipa_ctx = ipa_ctx;
969 0 : state->dom = dom;
970 0 : state->sh = sh;
971 0 : state->list = list;
972 0 : state->list_idx = 0;
973 0 : state->req_input.type = list_type;
974 0 : state->req_input.inp.name = NULL;
975 0 : state->exop_timeout = exop_timeout;
976 0 : state->entry_type = entry_type;
977 0 : state->request_type = request_type;
978 0 : state->attrs = NULL;
979 0 : state->override_attrs = NULL;
980 :
981 0 : ret = ipa_s2n_get_list_step(req);
982 0 : if (ret != EOK) {
983 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_step failed.\n");
984 0 : goto done;
985 : }
986 :
987 : done:
988 0 : if (ret != EOK) {
989 0 : tevent_req_error(req, ret);
990 0 : tevent_req_post(req, ev);
991 : }
992 :
993 0 : return req;
994 : }
995 :
996 0 : static errno_t ipa_s2n_get_list_step(struct tevent_req *req)
997 : {
998 : int ret;
999 0 : struct ipa_s2n_get_list_state *state = tevent_req_data(req,
1000 : struct ipa_s2n_get_list_state);
1001 : struct berval *bv_req;
1002 : struct tevent_req *subreq;
1003 : struct sss_domain_info *parent_domain;
1004 0 : char *short_name = NULL;
1005 0 : char *domain_name = NULL;
1006 : uint32_t id;
1007 : char *endptr;
1008 0 : bool need_v1 = false;
1009 :
1010 0 : parent_domain = get_domains_head(state->dom);
1011 0 : switch (state->req_input.type) {
1012 : case REQ_INP_NAME:
1013 :
1014 0 : ret = sss_parse_name(state, parent_domain->names,
1015 0 : state->list[state->list_idx],
1016 : &domain_name, &short_name);
1017 0 : if (ret != EOK) {
1018 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
1019 : state->list[state->list_idx],
1020 : ret, sss_strerror(ret));
1021 0 : return ret;
1022 : }
1023 :
1024 0 : if (domain_name) {
1025 0 : state->obj_domain = find_domain_by_name(parent_domain,
1026 : domain_name, true);
1027 0 : if (state->obj_domain == NULL) {
1028 0 : DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
1029 0 : return ENOMEM;
1030 : }
1031 : } else {
1032 0 : state->obj_domain = parent_domain;
1033 : }
1034 :
1035 0 : state->req_input.inp.name = short_name;
1036 :
1037 0 : break;
1038 : case REQ_INP_ID:
1039 0 : errno = 0;
1040 0 : id = strtouint32(state->list[state->list_idx], &endptr, 10);
1041 0 : if (errno != 0 || *endptr != '\0'
1042 0 : || (state->list[state->list_idx] == endptr)) {
1043 0 : DEBUG(SSSDBG_OP_FAILURE, "strtouint32 failed.\n");
1044 0 : return EINVAL;
1045 : }
1046 0 : state->req_input.inp.id = id;
1047 0 : state->obj_domain = state->dom;
1048 :
1049 0 : break;
1050 : case REQ_INP_SECID:
1051 0 : state->req_input.inp.secid = state->list[state->list_idx];
1052 0 : state->obj_domain = find_domain_by_sid(parent_domain,
1053 : state->req_input.inp.secid);
1054 0 : if (state->obj_domain == NULL) {
1055 0 : DEBUG(SSSDBG_OP_FAILURE,
1056 : "find_domain_by_sid failed for SID [%s].\n",
1057 : state->req_input.inp.secid);
1058 0 : return EINVAL;
1059 : }
1060 :
1061 0 : break;
1062 : default:
1063 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected inoput type [%d].\n",
1064 : state->req_input.type);
1065 0 : return EINVAL;
1066 : }
1067 :
1068 0 : ret = s2n_encode_request(state, state->obj_domain->name, state->entry_type,
1069 : state->request_type,
1070 : &state->req_input, &bv_req);
1071 0 : if (ret != EOK) {
1072 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n_encode_request failed.\n");
1073 0 : return ret;
1074 : }
1075 :
1076 0 : if (state->request_type == REQ_FULL_WITH_MEMBERS) {
1077 0 : need_v1 = true;
1078 : }
1079 :
1080 0 : subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1,
1081 : state->exop_timeout, bv_req);
1082 0 : if (subreq == NULL) {
1083 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
1084 0 : return ENOMEM;
1085 : }
1086 0 : tevent_req_set_callback(subreq, ipa_s2n_get_list_next, req);
1087 :
1088 0 : return EOK;
1089 : }
1090 :
1091 0 : static void ipa_s2n_get_list_next(struct tevent_req *subreq)
1092 : {
1093 : int ret;
1094 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1095 : struct tevent_req);
1096 0 : struct ipa_s2n_get_list_state *state = tevent_req_data(req,
1097 : struct ipa_s2n_get_list_state);
1098 0 : char *retoid = NULL;
1099 0 : struct berval *retdata = NULL;
1100 : const char *sid_str;
1101 : struct be_acct_req *ar;
1102 :
1103 0 : ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
1104 0 : talloc_zfree(subreq);
1105 0 : if (ret != EOK) {
1106 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n exop request failed.\n");
1107 0 : goto fail;
1108 : }
1109 :
1110 0 : talloc_zfree(state->attrs);
1111 0 : ret = s2n_response_to_attrs(state, retoid, retdata, &state->attrs);
1112 0 : if (ret != EOK) {
1113 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
1114 0 : goto fail;
1115 : }
1116 :
1117 0 : if (is_default_view(state->ipa_ctx->view_name)) {
1118 0 : ret = ipa_s2n_get_list_save_step(req);
1119 0 : if (ret == EOK) {
1120 0 : tevent_req_done(req);
1121 0 : } else if (ret != EAGAIN) {
1122 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_save_step failed.\n");
1123 0 : goto fail;
1124 : }
1125 :
1126 0 : return;
1127 : }
1128 :
1129 0 : ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
1130 : &sid_str);
1131 0 : if (ret != EOK) {
1132 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
1133 0 : goto fail;
1134 : }
1135 :
1136 0 : ret = get_be_acct_req_for_sid(state, sid_str, state->obj_domain->name, &ar);
1137 0 : if (ret != EOK) {
1138 0 : DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
1139 0 : goto fail;
1140 : }
1141 :
1142 0 : subreq = ipa_get_ad_override_send(state, state->ev,
1143 0 : state->ipa_ctx->sdap_id_ctx,
1144 0 : state->ipa_ctx->ipa_options,
1145 0 : dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
1146 : IPA_KRB5_REALM),
1147 0 : state->ipa_ctx->view_name,
1148 : ar);
1149 0 : if (subreq == NULL) {
1150 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
1151 0 : ret = ENOMEM;
1152 0 : goto fail;
1153 : }
1154 0 : tevent_req_set_callback(subreq, ipa_s2n_get_list_get_override_done, req);
1155 :
1156 0 : return;
1157 :
1158 : fail:
1159 0 : tevent_req_error(req,ret);
1160 0 : return;
1161 : }
1162 :
1163 0 : static void ipa_s2n_get_list_get_override_done(struct tevent_req *subreq)
1164 : {
1165 : int ret;
1166 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1167 : struct tevent_req);
1168 0 : struct ipa_s2n_get_list_state *state = tevent_req_data(req,
1169 : struct ipa_s2n_get_list_state);
1170 :
1171 0 : ret = ipa_get_ad_override_recv(subreq, NULL, state, &state->override_attrs);
1172 0 : talloc_zfree(subreq);
1173 0 : if (ret != EOK) {
1174 0 : DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
1175 0 : goto fail;
1176 : }
1177 :
1178 0 : ret = ipa_s2n_get_list_save_step(req);
1179 0 : if (ret == EOK) {
1180 0 : tevent_req_done(req);
1181 0 : } else if (ret != EAGAIN) {
1182 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_save_step failed.\n");
1183 0 : goto fail;
1184 : }
1185 :
1186 0 : return;
1187 :
1188 : fail:
1189 0 : tevent_req_error(req,ret);
1190 0 : return;
1191 : }
1192 :
1193 0 : static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req)
1194 : {
1195 : int ret;
1196 0 : struct ipa_s2n_get_list_state *state = tevent_req_data(req,
1197 : struct ipa_s2n_get_list_state);
1198 :
1199 0 : ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs,
1200 0 : NULL, state->ipa_ctx->view_name,
1201 : state->override_attrs, false);
1202 0 : if (ret != EOK) {
1203 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
1204 0 : return ret;
1205 : }
1206 :
1207 0 : state->list_idx++;
1208 0 : if (state->list[state->list_idx] == NULL) {
1209 0 : return EOK;
1210 : }
1211 :
1212 0 : ret = ipa_s2n_get_list_step(req);
1213 0 : if (ret != EOK) {
1214 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_step failed.\n");
1215 0 : return ret;
1216 : }
1217 :
1218 0 : return EAGAIN;
1219 : }
1220 :
1221 0 : static int ipa_s2n_get_list_recv(struct tevent_req *req)
1222 : {
1223 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1224 :
1225 0 : return EOK;
1226 : }
1227 :
1228 : struct ipa_s2n_get_user_state {
1229 : struct tevent_context *ev;
1230 : struct ipa_id_ctx *ipa_ctx;
1231 : struct sdap_options *opts;
1232 : struct sss_domain_info *dom;
1233 : struct sdap_handle *sh;
1234 : struct req_input *req_input;
1235 : int entry_type;
1236 : enum request_types request_type;
1237 : struct resp_attrs *attrs;
1238 : struct resp_attrs *simple_attrs;
1239 : struct sysdb_attrs *override_attrs;
1240 : int exop_timeout;
1241 : };
1242 :
1243 : static void ipa_s2n_get_user_done(struct tevent_req *subreq);
1244 :
1245 0 : struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
1246 : struct tevent_context *ev,
1247 : struct ipa_id_ctx *ipa_ctx,
1248 : struct sdap_options *opts,
1249 : struct sss_domain_info *dom,
1250 : struct sysdb_attrs *override_attrs,
1251 : struct sdap_handle *sh,
1252 : int entry_type,
1253 : struct req_input *req_input)
1254 : {
1255 : struct ipa_s2n_get_user_state *state;
1256 : struct tevent_req *req;
1257 : struct tevent_req *subreq;
1258 0 : struct berval *bv_req = NULL;
1259 0 : int ret = EFAULT;
1260 0 : bool is_v1 = false;
1261 :
1262 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_user_state);
1263 0 : if (req == NULL) {
1264 0 : return NULL;
1265 : }
1266 :
1267 0 : state->ev = ev;
1268 0 : state->ipa_ctx = ipa_ctx;
1269 0 : state->opts = opts;
1270 0 : state->dom = dom;
1271 0 : state->sh = sh;
1272 0 : state->req_input = req_input;
1273 0 : state->entry_type = entry_type;
1274 0 : state->attrs = NULL;
1275 0 : state->simple_attrs = NULL;
1276 0 : state->exop_timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
1277 0 : state->override_attrs = override_attrs;
1278 :
1279 0 : if (sdap_is_extension_supported(sh, EXOP_SID2NAME_V1_OID)) {
1280 0 : state->request_type = REQ_FULL_WITH_MEMBERS;
1281 0 : is_v1 = true;
1282 0 : } else if (sdap_is_extension_supported(sh, EXOP_SID2NAME_OID)) {
1283 0 : state->request_type = REQ_FULL;
1284 0 : is_v1 = false;
1285 : } else {
1286 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Extdom not supported on the server, "
1287 : "cannot resolve objects from trusted domains.\n");
1288 0 : ret = EIO;
1289 0 : goto fail;
1290 : }
1291 :
1292 0 : ret = s2n_encode_request(state, dom->name, entry_type, state->request_type,
1293 : req_input, &bv_req);
1294 0 : if (ret != EOK) {
1295 0 : goto fail;
1296 : }
1297 :
1298 0 : subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1,
1299 0 : state->exop_timeout, bv_req);
1300 0 : if (subreq == NULL) {
1301 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
1302 0 : ret = ENOMEM;
1303 0 : goto fail;
1304 : }
1305 0 : tevent_req_set_callback(subreq, ipa_s2n_get_user_done, req);
1306 :
1307 0 : return req;
1308 :
1309 : fail:
1310 0 : tevent_req_error(req, ret);
1311 0 : tevent_req_post(req, ev);
1312 :
1313 0 : return req;
1314 : }
1315 :
1316 0 : static errno_t process_members(struct sss_domain_info *domain,
1317 : struct sysdb_attrs *group_attrs,
1318 : char **members,
1319 : TALLOC_CTX *mem_ctx, char ***_missing_members)
1320 : {
1321 : int ret;
1322 : size_t c;
1323 : TALLOC_CTX *tmp_ctx;
1324 : struct ldb_message *msg;
1325 : const char *dn_str;
1326 : struct sss_domain_info *obj_domain;
1327 : struct sss_domain_info *parent_domain;
1328 0 : char **missing_members = NULL;
1329 0 : size_t miss_count = 0;
1330 :
1331 0 : if (members == NULL) {
1332 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n");
1333 0 : if (_missing_members != NULL) {
1334 0 : *_missing_members = NULL;
1335 : }
1336 0 : return EOK;
1337 : }
1338 :
1339 0 : tmp_ctx = talloc_new(NULL);
1340 0 : if (tmp_ctx == NULL) {
1341 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1342 0 : return ENOMEM;
1343 : }
1344 :
1345 0 : if (_missing_members != NULL && mem_ctx != NULL) {
1346 : /* count members */
1347 0 : for (c = 0; members[c] != NULL; c++);
1348 0 : missing_members = talloc_zero_array(tmp_ctx, char *, c + 1);
1349 0 : if (missing_members == NULL) {
1350 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array_zero failed.\n");
1351 0 : ret = ENOMEM;
1352 0 : goto done;
1353 : }
1354 : }
1355 :
1356 0 : parent_domain = get_domains_head(domain);
1357 :
1358 0 : for (c = 0; members[c] != NULL; c++) {
1359 0 : obj_domain = find_domain_by_object_name(parent_domain, members[c]);
1360 0 : if (obj_domain == NULL) {
1361 0 : DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
1362 0 : ret = ENOMEM;
1363 0 : goto done;
1364 : }
1365 :
1366 0 : ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL,
1367 : &msg);
1368 0 : if (ret == EOK) {
1369 0 : if (group_attrs != NULL) {
1370 0 : dn_str = ldb_dn_get_linearized(msg->dn);
1371 0 : if (dn_str == NULL) {
1372 0 : DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
1373 0 : ret = EINVAL;
1374 0 : goto done;
1375 : }
1376 :
1377 0 : DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
1378 : members[c], dn_str);
1379 :
1380 0 : ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER,
1381 : dn_str);
1382 0 : if (ret != EOK) {
1383 0 : DEBUG(SSSDBG_OP_FAILURE,
1384 : "sysdb_attrs_add_string_safe failed.\n");
1385 0 : goto done;
1386 : }
1387 : }
1388 0 : } else if (ret == ENOENT) {
1389 0 : if (group_attrs != NULL) {
1390 0 : DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n",
1391 : members[c]);
1392 :
1393 : /* There were cases where the server returned the same user
1394 : * multiple times */
1395 0 : ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST,
1396 0 : members[c]);
1397 0 : if (ret != EOK) {
1398 0 : DEBUG(SSSDBG_OP_FAILURE,
1399 : "sysdb_attrs_add_string failed.\n");
1400 0 : goto done;
1401 : }
1402 : }
1403 :
1404 0 : if (missing_members != NULL) {
1405 0 : missing_members[miss_count] = talloc_strdup(missing_members,
1406 0 : members[c]);
1407 0 : if (missing_members[miss_count] == NULL) {
1408 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1409 0 : ret = ENOMEM;
1410 0 : goto done;
1411 : }
1412 0 : miss_count++;
1413 : }
1414 : } else {
1415 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
1416 0 : goto done;
1417 : }
1418 : }
1419 :
1420 0 : if (_missing_members != NULL) {
1421 0 : if (miss_count == 0) {
1422 0 : *_missing_members = NULL;
1423 : } else {
1424 0 : if (mem_ctx != NULL) {
1425 0 : *_missing_members = talloc_steal(mem_ctx, missing_members);
1426 : } else {
1427 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1428 : "Missing memory context for missing members list.\n");
1429 0 : ret = EINVAL;
1430 0 : goto done;
1431 : }
1432 : }
1433 : }
1434 :
1435 0 : ret = EOK;
1436 : done:
1437 0 : talloc_free(tmp_ctx);
1438 :
1439 0 : return ret;
1440 : }
1441 :
1442 0 : static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx,
1443 : struct sss_domain_info *dom,
1444 : size_t ngroups, char **groups,
1445 : struct ldb_dn ***_dn_list,
1446 : char ***_missing_groups)
1447 : {
1448 : int ret;
1449 : size_t c;
1450 : TALLOC_CTX *tmp_ctx;
1451 0 : struct ldb_dn **dn_list = NULL;
1452 0 : char **missing_groups = NULL;
1453 0 : struct ldb_message *msg = NULL;
1454 0 : size_t n_dns = 0;
1455 0 : size_t n_missing = 0;
1456 : struct sss_domain_info *obj_domain;
1457 : struct sss_domain_info *parent_domain;
1458 :
1459 0 : tmp_ctx = talloc_new(NULL);
1460 0 : if (tmp_ctx == NULL) {
1461 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1462 0 : return ENOMEM;
1463 : }
1464 :
1465 0 : dn_list = talloc_zero_array(tmp_ctx, struct ldb_dn *, ngroups + 1);
1466 0 : missing_groups = talloc_zero_array(tmp_ctx, char *, ngroups + 1);
1467 0 : if (dn_list == NULL || missing_groups == NULL) {
1468 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array_zero failed.\n");
1469 0 : ret = ENOMEM;
1470 0 : goto done;
1471 : }
1472 :
1473 0 : parent_domain = (dom->parent == NULL) ? dom : dom->parent;
1474 :
1475 0 : for (c = 0; c < ngroups; c++) {
1476 0 : obj_domain = find_domain_by_object_name(parent_domain, groups[c]);
1477 0 : if (obj_domain == NULL) {
1478 0 : DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
1479 0 : ret = ENOMEM;
1480 0 : goto done;
1481 : }
1482 :
1483 0 : ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], NULL,
1484 : &msg);
1485 0 : if (ret == EOK) {
1486 0 : dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn);
1487 0 : if (dn_list[n_dns] == NULL) {
1488 0 : DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
1489 0 : ret = ENOMEM;
1490 0 : goto done;
1491 : }
1492 0 : n_dns++;
1493 0 : } else if (ret == ENOENT) {
1494 0 : missing_groups[n_missing] = talloc_strdup(missing_groups,
1495 0 : groups[c]);
1496 0 : if (missing_groups[n_missing] == NULL) {
1497 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1498 0 : ret = ENOMEM;
1499 0 : goto done;
1500 : }
1501 0 : n_missing++;
1502 : } else {
1503 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_group_by_name failed.\n");
1504 0 : goto done;
1505 : }
1506 : }
1507 :
1508 0 : if (n_missing != 0) {
1509 0 : *_missing_groups = talloc_steal(mem_ctx, missing_groups);
1510 : } else {
1511 0 : *_missing_groups = NULL;
1512 : }
1513 :
1514 0 : if (n_dns != 0) {
1515 0 : *_dn_list = talloc_steal(mem_ctx, dn_list);
1516 : } else {
1517 0 : *dn_list = NULL;
1518 : }
1519 :
1520 0 : ret = EOK;
1521 :
1522 : done:
1523 0 : talloc_free(tmp_ctx);
1524 :
1525 0 : return ret;
1526 : }
1527 :
1528 : static void ipa_s2n_get_list_done(struct tevent_req *subreq);
1529 : static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq);
1530 0 : static void ipa_s2n_get_user_done(struct tevent_req *subreq)
1531 : {
1532 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
1533 : struct tevent_req);
1534 0 : struct ipa_s2n_get_user_state *state = tevent_req_data(req,
1535 : struct ipa_s2n_get_user_state);
1536 : int ret;
1537 0 : char *retoid = NULL;
1538 0 : struct berval *retdata = NULL;
1539 0 : struct resp_attrs *attrs = NULL;
1540 0 : struct berval *bv_req = NULL;
1541 0 : char **missing_list = NULL;
1542 0 : struct ldb_dn **group_dn_list = NULL;
1543 : const char *sid_str;
1544 : struct be_acct_req *ar;
1545 :
1546 0 : ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
1547 0 : talloc_zfree(subreq);
1548 0 : if (ret != EOK) {
1549 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n exop request failed.\n");
1550 0 : if (state->req_input->type == REQ_INP_CERT) {
1551 0 : DEBUG(SSSDBG_OP_FAILURE,
1552 : "Maybe the server does not support lookups by "
1553 : "certificates.\n");
1554 : }
1555 0 : goto done;
1556 : }
1557 :
1558 0 : switch (state->request_type) {
1559 : case REQ_FULL_WITH_MEMBERS:
1560 : case REQ_FULL:
1561 0 : ret = s2n_response_to_attrs(state, retoid, retdata, &attrs);
1562 0 : if (ret != EOK) {
1563 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
1564 0 : goto done;
1565 : }
1566 :
1567 0 : if (!(strcasecmp(state->dom->name, attrs->domain_name) == 0 ||
1568 0 : (state->dom->flat_name != NULL &&
1569 0 : strcasecmp(state->dom->flat_name, attrs->domain_name) == 0))) {
1570 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected domain name returned, "
1571 : "expected [%s] or [%s], got [%s].\n",
1572 : state->dom->name,
1573 : state->dom->flat_name == NULL ? "" :
1574 : state->dom->flat_name,
1575 : attrs->domain_name);
1576 0 : ret = EINVAL;
1577 0 : goto done;
1578 : }
1579 :
1580 0 : state->attrs = attrs;
1581 :
1582 0 : if (attrs->response_type == RESP_USER_GROUPLIST) {
1583 0 : ret = get_group_dn_list(state, state->dom,
1584 0 : attrs->ngroups, attrs->groups,
1585 : &group_dn_list, &missing_list);
1586 0 : if (ret != EOK) {
1587 0 : DEBUG(SSSDBG_OP_FAILURE, "get_group_dn_list failed.\n");
1588 0 : goto done;
1589 : }
1590 :
1591 0 : if (missing_list != NULL) {
1592 0 : subreq = ipa_s2n_get_list_send(state, state->ev,
1593 : state->ipa_ctx, state->dom,
1594 : state->sh, state->exop_timeout,
1595 : BE_REQ_GROUP,
1596 : REQ_FULL_WITH_MEMBERS,
1597 : REQ_INP_NAME,
1598 : missing_list);
1599 0 : if (subreq == NULL) {
1600 0 : DEBUG(SSSDBG_OP_FAILURE,
1601 : "ipa_s2n_get_list_send failed.\n");
1602 0 : ret = ENOMEM;
1603 0 : goto done;
1604 : }
1605 0 : tevent_req_set_callback(subreq, ipa_s2n_get_list_done,
1606 : req);
1607 :
1608 0 : return;
1609 : }
1610 0 : break;
1611 0 : } else if (attrs->response_type == RESP_GROUP_MEMBERS) {
1612 0 : ret = process_members(state->dom, NULL, attrs->a.group.gr_mem,
1613 : state, &missing_list);
1614 0 : if (ret != EOK) {
1615 0 : DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
1616 0 : goto done;
1617 : }
1618 :
1619 0 : if (missing_list != NULL) {
1620 0 : subreq = ipa_s2n_get_list_send(state, state->ev,
1621 : state->ipa_ctx, state->dom,
1622 : state->sh, state->exop_timeout,
1623 : BE_REQ_USER,
1624 : REQ_FULL_WITH_MEMBERS,
1625 : REQ_INP_NAME,
1626 : missing_list);
1627 0 : if (subreq == NULL) {
1628 0 : DEBUG(SSSDBG_OP_FAILURE,
1629 : "ipa_s2n_get_list_send failed.\n");
1630 0 : ret = ENOMEM;
1631 0 : goto done;
1632 : }
1633 0 : tevent_req_set_callback(subreq, ipa_s2n_get_list_done,
1634 : req);
1635 :
1636 0 : return;
1637 : }
1638 0 : break;
1639 : }
1640 :
1641 0 : if (state->req_input->type == REQ_INP_SECID) {
1642 : /* We already know the SID, we do not have to read it. */
1643 0 : break;
1644 : }
1645 :
1646 0 : state->request_type = REQ_SIMPLE;
1647 :
1648 0 : ret = s2n_encode_request(state, state->dom->name, state->entry_type,
1649 : state->request_type, state->req_input,
1650 : &bv_req);
1651 0 : if (ret != EOK) {
1652 0 : goto done;
1653 : }
1654 :
1655 0 : subreq = ipa_s2n_exop_send(state, state->ev, state->sh, false,
1656 : state->exop_timeout, bv_req);
1657 0 : if (subreq == NULL) {
1658 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
1659 0 : ret = ENOMEM;
1660 0 : goto done;
1661 : }
1662 0 : tevent_req_set_callback(subreq, ipa_s2n_get_user_done, req);
1663 :
1664 0 : return;
1665 :
1666 : case REQ_SIMPLE:
1667 0 : ret = s2n_response_to_attrs(state, retoid, retdata,
1668 : &state->simple_attrs);
1669 0 : if (ret != EOK) {
1670 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
1671 0 : goto done;
1672 : }
1673 :
1674 0 : break;
1675 : default:
1676 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n");
1677 0 : ret = EINVAL;
1678 0 : goto done;
1679 : }
1680 :
1681 0 : if (state->attrs == NULL) {
1682 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing data of full request.\n");
1683 0 : ret = EINVAL;
1684 0 : goto done;
1685 : }
1686 :
1687 0 : if (state->simple_attrs != NULL
1688 0 : && state->simple_attrs->response_type == RESP_SID) {
1689 0 : sid_str = state->simple_attrs->a.sid_str;
1690 0 : ret = EOK;
1691 0 : } else if (state->attrs->sysdb_attrs != NULL) {
1692 0 : ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
1693 : &sid_str);
1694 0 : } else if (state->req_input->type == REQ_INP_SECID) {
1695 0 : sid_str = state->req_input->inp.secid;
1696 0 : ret = EOK;
1697 : } else {
1698 0 : DEBUG(SSSDBG_TRACE_FUNC, "No SID available.\n");
1699 0 : ret = ENOENT;
1700 : }
1701 :
1702 0 : if (ret == ENOENT || is_default_view(state->ipa_ctx->view_name)) {
1703 0 : ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
1704 : state->simple_attrs, NULL, NULL, true);
1705 0 : if (ret != EOK) {
1706 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
1707 0 : goto done;
1708 : }
1709 0 : } else if (ret == EOK) {
1710 0 : ret = get_be_acct_req_for_sid(state, sid_str, state->dom->name, &ar);
1711 0 : if (ret != EOK) {
1712 0 : DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
1713 0 : goto done;
1714 : }
1715 :
1716 0 : subreq = ipa_get_ad_override_send(state, state->ev,
1717 0 : state->ipa_ctx->sdap_id_ctx,
1718 0 : state->ipa_ctx->ipa_options,
1719 0 : dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
1720 : IPA_KRB5_REALM),
1721 0 : state->ipa_ctx->view_name,
1722 : ar);
1723 0 : if (subreq == NULL) {
1724 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
1725 0 : ret = ENOMEM;
1726 0 : goto done;
1727 : }
1728 0 : tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done,
1729 : req);
1730 :
1731 0 : return;
1732 : } else {
1733 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
1734 0 : goto done;
1735 : }
1736 :
1737 : done:
1738 0 : if (ret == EOK) {
1739 0 : tevent_req_done(req);
1740 : } else {
1741 0 : tevent_req_error(req, ret);
1742 : }
1743 0 : return;
1744 : }
1745 :
1746 0 : static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
1747 : char **name_list, char ***_dn_list)
1748 : {
1749 : int ret;
1750 : TALLOC_CTX *tmp_ctx;
1751 : int c;
1752 : struct sss_domain_info *root_domain;
1753 : char **dn_list;
1754 :
1755 0 : if (name_list == NULL) {
1756 0 : *_dn_list = NULL;
1757 0 : return EOK;
1758 : }
1759 :
1760 : /* To handle cross-domain memberships we have to check the domain for
1761 : * each group the member should be added or deleted. Since sub-domains
1762 : * use fully-qualified names by default any short name can only belong
1763 : * to the root/head domain. find_domain_by_object_name() will return
1764 : * the domain given in the first argument if the second argument is a
1765 : * a short name hence we always use root_domain as first argument. */
1766 0 : root_domain = get_domains_head(dom);
1767 0 : if (root_domain->fqnames) {
1768 0 : DEBUG(SSSDBG_TRACE_FUNC,
1769 : "Root domain uses fully-qualified names, " \
1770 : "objects might not be correctly added to groups with " \
1771 : "short names.\n");
1772 : }
1773 :
1774 0 : tmp_ctx = talloc_new(NULL);
1775 0 : if (tmp_ctx == NULL) {
1776 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1777 0 : return ENOMEM;
1778 : }
1779 :
1780 0 : for (c = 0; name_list[c] != NULL; c++);
1781 :
1782 0 : dn_list = talloc_zero_array(tmp_ctx, char *, c + 1);
1783 0 : if (dn_list == NULL) {
1784 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
1785 0 : ret = ENOMEM;
1786 0 : goto done;
1787 : }
1788 :
1789 0 : for (c = 0; name_list[c] != NULL; c++) {
1790 0 : dom = find_domain_by_object_name(root_domain, name_list[c]);
1791 0 : if (dom == NULL) {
1792 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1793 : "Cannot find domain for [%s].\n", name_list[c]);
1794 0 : ret = ENOENT;
1795 0 : goto done;
1796 : }
1797 :
1798 : /* This might fail if some unexpected cases are used. But current
1799 : * sysdb code which handles group membership constructs DNs this way
1800 : * as well, IPA names are lowercased and AD names by default will be
1801 : * lowercased as well. If there are really use-cases which cause an
1802 : * issue here, sysdb_group_strdn() has to be replaced by a proper
1803 : * search. */
1804 0 : dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]);
1805 0 : if (dn_list[c] == NULL) {
1806 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_group_strdn failed.\n");
1807 0 : ret = ENOMEM;
1808 0 : goto done;
1809 : }
1810 :
1811 0 : DEBUG(SSSDBG_TRACE_ALL, "Added [%s][%s].\n", name_list[c], dn_list[c]);
1812 : }
1813 :
1814 0 : *_dn_list = talloc_steal(mem_ctx, dn_list);
1815 0 : ret = EOK;
1816 :
1817 : done:
1818 0 : talloc_free(tmp_ctx);
1819 :
1820 0 : return ret;
1821 : }
1822 :
1823 0 : static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
1824 : struct req_input *req_input,
1825 : struct resp_attrs *attrs,
1826 : struct resp_attrs *simple_attrs,
1827 : const char *view_name,
1828 : struct sysdb_attrs *override_attrs,
1829 : bool update_initgr_timeout)
1830 : {
1831 : int ret;
1832 : time_t now;
1833 : struct sss_nss_homedir_ctx homedir_ctx;
1834 0 : char *name = NULL;
1835 : char *realm;
1836 0 : char *upn = NULL;
1837 : gid_t gid;
1838 0 : gid_t orig_gid = 0;
1839 : TALLOC_CTX *tmp_ctx;
1840 : const char *sid_str;
1841 : const char *tmp_str;
1842 : struct ldb_result *res;
1843 : enum sysdb_member_type type;
1844 : char **sysdb_grouplist;
1845 : char **add_groups;
1846 : char **add_groups_dns;
1847 : char **del_groups;
1848 : char **del_groups_dns;
1849 0 : bool in_transaction = false;
1850 : int tret;
1851 0 : struct sysdb_attrs *gid_override_attrs = NULL;
1852 : char ** exop_grouplist;
1853 : struct ldb_message *msg;
1854 0 : struct ldb_message_element *el = NULL;
1855 0 : const char *missing[] = {NULL, NULL};
1856 :
1857 0 : tmp_ctx = talloc_new(NULL);
1858 0 : if (tmp_ctx == NULL) {
1859 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1860 0 : return ENOMEM;
1861 : }
1862 :
1863 0 : now = time(NULL);
1864 :
1865 0 : if (attrs->sysdb_attrs == NULL) {
1866 0 : attrs->sysdb_attrs = sysdb_new_attrs(attrs);
1867 0 : if (attrs->sysdb_attrs == NULL) {
1868 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
1869 0 : ret = ENOMEM;
1870 0 : goto done;
1871 : }
1872 : }
1873 :
1874 0 : if (attrs->sysdb_attrs != NULL) {
1875 0 : ret = sysdb_attrs_get_string(attrs->sysdb_attrs,
1876 : ORIGINALAD_PREFIX SYSDB_NAME, &tmp_str);
1877 0 : if (ret == EOK) {
1878 0 : name = talloc_strdup(tmp_ctx, tmp_str);
1879 0 : if (name == NULL) {
1880 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1881 0 : ret = ENOMEM;
1882 0 : goto done;
1883 : }
1884 0 : DEBUG(SSSDBG_TRACE_ALL, "Found original AD name [%s].\n", name);
1885 0 : } else if (ret == ENOENT) {
1886 0 : name = NULL;
1887 : } else {
1888 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
1889 0 : goto done;
1890 : }
1891 :
1892 0 : ret = sysdb_attrs_get_string(attrs->sysdb_attrs,
1893 : SYSDB_DEFAULT_OVERRIDE_NAME, &tmp_str);
1894 0 : if (ret == EOK) {
1895 0 : ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs,
1896 : tmp_str);
1897 0 : if (ret != EOK) {
1898 0 : DEBUG(SSSDBG_OP_FAILURE,
1899 : "sysdb_attrs_add_lc_name_alias_safe failed.\n");
1900 0 : goto done;
1901 : }
1902 0 : } else if (ret != ENOENT) {
1903 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
1904 0 : goto done;
1905 : }
1906 :
1907 0 : ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_UPN, &tmp_str);
1908 0 : if (ret == EOK) {
1909 0 : upn = talloc_strdup(tmp_ctx, tmp_str);
1910 0 : if (upn == NULL) {
1911 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
1912 0 : ret = ENOMEM;
1913 0 : goto done;
1914 : }
1915 0 : DEBUG(SSSDBG_TRACE_ALL, "Found original AD upn [%s].\n", upn);
1916 0 : } else if (ret == ENOENT) {
1917 0 : upn = NULL;
1918 : } else {
1919 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
1920 0 : goto done;
1921 : }
1922 : }
1923 :
1924 0 : if (strcmp(dom->name, attrs->domain_name) != 0) {
1925 0 : dom = find_domain_by_name(get_domains_head(dom),
1926 0 : attrs->domain_name, true);
1927 0 : if (dom == NULL) {
1928 0 : DEBUG(SSSDBG_OP_FAILURE,
1929 : "Cannot find domain: [%s]\n", attrs->domain_name);
1930 0 : ret = EINVAL;
1931 0 : goto done;
1932 : }
1933 : }
1934 :
1935 0 : switch (attrs->response_type) {
1936 : case RESP_USER:
1937 : case RESP_USER_GROUPLIST:
1938 0 : type = SYSDB_MEMBER_USER;
1939 0 : if (dom->subdomain_homedir
1940 0 : && attrs->a.user.pw_dir == NULL) {
1941 0 : ZERO_STRUCT(homedir_ctx);
1942 0 : homedir_ctx.username = attrs->a.user.pw_name;
1943 0 : homedir_ctx.uid = attrs->a.user.pw_uid;
1944 0 : homedir_ctx.domain = dom->name;
1945 0 : homedir_ctx.flatname = dom->flat_name;
1946 0 : homedir_ctx.config_homedir_substr = dom->homedir_substr;
1947 :
1948 0 : attrs->a.user.pw_dir = expand_homedir_template(attrs,
1949 : dom->subdomain_homedir,
1950 : &homedir_ctx);
1951 0 : if (attrs->a.user.pw_dir == NULL) {
1952 0 : ret = ENOMEM;
1953 0 : goto done;
1954 : }
1955 : }
1956 :
1957 0 : if (name == NULL) {
1958 : /* we always use the fully qualified name for subdomain users */
1959 0 : name = sss_tc_fqname(tmp_ctx, dom->names, dom,
1960 0 : attrs->a.user.pw_name);
1961 0 : if (!name) {
1962 0 : DEBUG(SSSDBG_OP_FAILURE, "failed to format user name.\n");
1963 0 : ret = ENOMEM;
1964 0 : goto done;
1965 : }
1966 : }
1967 :
1968 0 : ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs, name);
1969 0 : if (ret != EOK) {
1970 0 : DEBUG(SSSDBG_OP_FAILURE,
1971 : "sysdb_attrs_add_lc_name_alias_safe failed.\n");
1972 0 : goto done;
1973 : }
1974 :
1975 0 : if (upn == NULL) {
1976 : /* We also have to store a fake UPN here, because otherwise the
1977 : * krb5 child later won't be able to properly construct one as
1978 : * the username is fully qualified but the child doesn't have
1979 : * access to the regex to deconstruct it */
1980 : /* FIXME: The real UPN is available from the PAC, we should get
1981 : * it from there. */
1982 0 : realm = get_uppercase_realm(tmp_ctx, dom->name);
1983 0 : if (!realm) {
1984 0 : DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n");
1985 0 : ret = ENOMEM;
1986 0 : goto done;
1987 : }
1988 0 : upn = talloc_asprintf(tmp_ctx, "%s@%s",
1989 : attrs->a.user.pw_name, realm);
1990 0 : if (!upn) {
1991 0 : DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
1992 0 : ret = ENOMEM;
1993 0 : goto done;
1994 : }
1995 :
1996 : /* We might already have the SID or the UPN from other sources
1997 : * hence sysdb_attrs_add_string_safe is used to avoid double
1998 : * entries. */
1999 0 : ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs, SYSDB_UPN,
2000 : upn);
2001 0 : if (ret != EOK) {
2002 0 : DEBUG(SSSDBG_OP_FAILURE,
2003 : "sysdb_attrs_add_string failed.\n");
2004 0 : goto done;
2005 : }
2006 : }
2007 :
2008 0 : if (req_input->type == REQ_INP_SECID) {
2009 0 : ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
2010 : SYSDB_SID_STR,
2011 : req_input->inp.secid);
2012 0 : if (ret != EOK) {
2013 0 : DEBUG(SSSDBG_OP_FAILURE,
2014 : "sysdb_attrs_add_string failed.\n");
2015 0 : goto done;
2016 : }
2017 : }
2018 :
2019 0 : if (simple_attrs != NULL
2020 0 : && simple_attrs->response_type == RESP_SID) {
2021 0 : ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
2022 : SYSDB_SID_STR,
2023 0 : simple_attrs->a.sid_str);
2024 0 : if (ret != EOK) {
2025 0 : DEBUG(SSSDBG_OP_FAILURE,
2026 : "sysdb_attrs_add_string failed.\n");
2027 0 : goto done;
2028 : }
2029 : }
2030 :
2031 0 : if (attrs->response_type == RESP_USER_GROUPLIST
2032 0 : && update_initgr_timeout) {
2033 : /* Since RESP_USER_GROUPLIST contains all group memberships it
2034 : * is effectively an initgroups request hence
2035 : * SYSDB_INITGR_EXPIRE will be set.*/
2036 0 : ret = sysdb_attrs_add_time_t(attrs->sysdb_attrs,
2037 : SYSDB_INITGR_EXPIRE,
2038 0 : time(NULL) + dom->user_timeout);
2039 0 : if (ret != EOK) {
2040 0 : DEBUG(SSSDBG_OP_FAILURE,
2041 : "sysdb_attrs_add_time_t failed.\n");
2042 0 : goto done;
2043 : }
2044 : }
2045 :
2046 0 : gid = 0;
2047 0 : if (dom->mpg == false) {
2048 0 : gid = attrs->a.user.pw_gid;
2049 : } else {
2050 : /* The extdom plugin always returns the objects with the
2051 : * default view applied. Since the GID is handled specially
2052 : * for MPG domains we have add any overridden GID separately.
2053 : */
2054 0 : ret = sysdb_attrs_get_uint32_t(attrs->sysdb_attrs,
2055 : ORIGINALAD_PREFIX SYSDB_GIDNUM,
2056 : &orig_gid);
2057 0 : if (ret == EOK || ret == ENOENT) {
2058 0 : if ((orig_gid != 0 && orig_gid != attrs->a.user.pw_gid)
2059 0 : || attrs->a.user.pw_uid != attrs->a.user.pw_gid) {
2060 :
2061 0 : gid_override_attrs = sysdb_new_attrs(tmp_ctx);
2062 0 : if (gid_override_attrs == NULL) {
2063 0 : DEBUG(SSSDBG_OP_FAILURE,
2064 : "sysdb_new_attrs failed.\n");
2065 0 : ret = ENOMEM;
2066 0 : goto done;
2067 : }
2068 :
2069 0 : ret = sysdb_attrs_add_uint32(gid_override_attrs,
2070 : SYSDB_GIDNUM,
2071 : attrs->a.user.pw_gid);
2072 0 : if (ret != EOK) {
2073 0 : DEBUG(SSSDBG_OP_FAILURE,
2074 : "sysdb_attrs_add_uint32 failed.\n");
2075 0 : goto done;
2076 : }
2077 : }
2078 : } else {
2079 0 : DEBUG(SSSDBG_OP_FAILURE,
2080 : "sysdb_attrs_get_uint32_t failed.\n");
2081 0 : goto done;
2082 : }
2083 : }
2084 :
2085 0 : ret = sysdb_attrs_get_el_ext(attrs->sysdb_attrs,
2086 : SYSDB_ORIG_MEMBEROF, false, &el);
2087 0 : if (ret == ENOENT) {
2088 0 : missing[0] = SYSDB_ORIG_MEMBEROF;
2089 : }
2090 :
2091 0 : ret = sysdb_transaction_start(dom->sysdb);
2092 0 : if (ret != EOK) {
2093 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
2094 0 : goto done;
2095 : }
2096 0 : in_transaction = true;
2097 :
2098 0 : ret = sysdb_store_user(dom, name, NULL,
2099 : attrs->a.user.pw_uid,
2100 0 : gid, attrs->a.user.pw_gecos,
2101 0 : attrs->a.user.pw_dir, attrs->a.user.pw_shell,
2102 : NULL, attrs->sysdb_attrs,
2103 0 : missing[0] == NULL ? NULL
2104 : : discard_const(missing),
2105 0 : dom->user_timeout, now);
2106 0 : if (ret == EEXIST && dom->mpg == true) {
2107 : /* This handles the case where getgrgid() was called for
2108 : * this user, so a group was created in the cache
2109 : */
2110 0 : ret = sysdb_search_group_by_name(tmp_ctx, dom, name, NULL, &msg);
2111 0 : if (ret != EOK) {
2112 : /* Fail even on ENOENT, the group must be around */
2113 0 : DEBUG(SSSDBG_OP_FAILURE,
2114 : "Could not delete MPG group [%d]: %s\n",
2115 : ret, sss_strerror(ret));
2116 0 : goto done;
2117 : }
2118 :
2119 0 : ret = sysdb_delete_group(dom, NULL, attrs->a.user.pw_uid);
2120 0 : if (ret != EOK) {
2121 0 : DEBUG(SSSDBG_OP_FAILURE,
2122 : "sysdb_delete_group failed for MPG group [%d]: %s\n",
2123 : ret, sss_strerror(ret));
2124 0 : goto done;
2125 : }
2126 :
2127 0 : ret = sysdb_store_user(dom, name, NULL,
2128 : attrs->a.user.pw_uid,
2129 0 : gid, attrs->a.user.pw_gecos,
2130 0 : attrs->a.user.pw_dir,
2131 0 : attrs->a.user.pw_shell,
2132 : NULL, attrs->sysdb_attrs, NULL,
2133 0 : dom->user_timeout, now);
2134 0 : if (ret != EOK) {
2135 0 : DEBUG(SSSDBG_OP_FAILURE,
2136 : "sysdb_store_user failed for MPG user [%d]: %s\n",
2137 : ret, sss_strerror(ret));
2138 0 : goto done;
2139 : }
2140 0 : } else if (ret != EOK) {
2141 0 : DEBUG(SSSDBG_OP_FAILURE,
2142 : "sysdb_store_user failed [%d]: %s\n",
2143 : ret, sss_strerror(ret));
2144 0 : goto done;
2145 : }
2146 :
2147 0 : if (gid_override_attrs != NULL) {
2148 0 : ret = sysdb_set_user_attr(dom, name, gid_override_attrs,
2149 : SYSDB_MOD_REP);
2150 0 : if (ret != EOK) {
2151 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n");
2152 0 : goto done;
2153 : }
2154 : }
2155 :
2156 0 : if (attrs->response_type == RESP_USER_GROUPLIST) {
2157 0 : ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name,
2158 : &sysdb_grouplist);
2159 0 : if (ret != EOK) {
2160 0 : DEBUG(SSSDBG_OP_FAILURE, "get_sysdb_grouplist failed.\n");
2161 0 : goto done;
2162 : }
2163 :
2164 : /* names returned by extdom exop will be all lower case, since
2165 : * we handle domain names case sensitve in the cache we have
2166 : * to make sure we use the right case. */
2167 0 : ret = fix_domain_in_name_list(tmp_ctx, dom, attrs->groups,
2168 : &exop_grouplist);
2169 0 : if (ret != EOK) {
2170 0 : DEBUG(SSSDBG_OP_FAILURE, "fix_domain_name failed.\n");
2171 0 : goto done;
2172 : }
2173 :
2174 0 : ret = diff_string_lists(tmp_ctx, exop_grouplist,
2175 : sysdb_grouplist, &add_groups,
2176 : &del_groups, NULL);
2177 0 : if (ret != EOK) {
2178 0 : DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n");
2179 0 : goto done;
2180 : }
2181 :
2182 0 : ret = get_groups_dns(tmp_ctx, dom, add_groups, &add_groups_dns);
2183 0 : if (ret != EOK) {
2184 0 : DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
2185 0 : goto done;
2186 : }
2187 :
2188 0 : ret = get_groups_dns(tmp_ctx, dom, del_groups, &del_groups_dns);
2189 0 : if (ret != EOK) {
2190 0 : DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
2191 0 : goto done;
2192 : }
2193 :
2194 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n",
2195 : name);
2196 0 : ret = sysdb_update_members_dn(dom, name, SYSDB_MEMBER_USER,
2197 : (const char *const *) add_groups_dns,
2198 : (const char *const *) del_groups_dns);
2199 0 : if (ret != EOK) {
2200 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Membership update failed [%d]: %s\n",
2201 : ret, sss_strerror(ret));
2202 0 : goto done;
2203 : }
2204 : }
2205 :
2206 0 : ret = sysdb_transaction_commit(dom->sysdb);
2207 0 : if (ret != EOK) {
2208 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
2209 0 : goto done;
2210 : }
2211 0 : in_transaction = false;
2212 :
2213 0 : break;
2214 : case RESP_GROUP:
2215 : case RESP_GROUP_MEMBERS:
2216 0 : type = SYSDB_MEMBER_GROUP;
2217 :
2218 0 : if (name == NULL) {
2219 0 : name = attrs->a.group.gr_name;
2220 : }
2221 :
2222 0 : if (IS_SUBDOMAIN(dom)) {
2223 : /* we always use the fully qualified name for subdomain users */
2224 0 : name = sss_get_domain_name(tmp_ctx, name, dom);
2225 0 : if (!name) {
2226 0 : DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
2227 0 : ret = ENOMEM;
2228 0 : goto done;
2229 : }
2230 : }
2231 0 : DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", name);
2232 :
2233 0 : ret = sysdb_attrs_add_lc_name_alias_safe(attrs->sysdb_attrs, name);
2234 0 : if (ret != EOK) {
2235 0 : DEBUG(SSSDBG_OP_FAILURE,
2236 : "sysdb_attrs_add_lc_name_alias_safe failed.\n");
2237 0 : goto done;
2238 : }
2239 :
2240 : /* We might already have the SID from other sources hence
2241 : * sysdb_attrs_add_string_safe is used to avoid double entries. */
2242 0 : if (req_input->type == REQ_INP_SECID) {
2243 0 : ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
2244 : SYSDB_SID_STR,
2245 : req_input->inp.secid);
2246 0 : if (ret != EOK) {
2247 0 : DEBUG(SSSDBG_OP_FAILURE,
2248 : "sysdb_attrs_add_string failed.\n");
2249 0 : goto done;
2250 : }
2251 : }
2252 :
2253 0 : if (simple_attrs != NULL
2254 0 : && simple_attrs->response_type == RESP_SID) {
2255 0 : ret = sysdb_attrs_add_string_safe(attrs->sysdb_attrs,
2256 : SYSDB_SID_STR,
2257 0 : simple_attrs->a.sid_str);
2258 0 : if (ret != EOK) {
2259 0 : DEBUG(SSSDBG_OP_FAILURE,
2260 : "sysdb_attrs_add_string failed.\n");
2261 0 : goto done;
2262 : }
2263 : }
2264 :
2265 0 : ret = process_members(dom, attrs->sysdb_attrs,
2266 : attrs->a.group.gr_mem, NULL, NULL);
2267 0 : if (ret != EOK) {
2268 0 : DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
2269 0 : goto done;
2270 : }
2271 :
2272 0 : ret = sysdb_store_group(dom, name, attrs->a.group.gr_gid,
2273 0 : attrs->sysdb_attrs, dom->group_timeout,
2274 : now);
2275 0 : if (ret != EOK) {
2276 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_group failed.\n");
2277 0 : goto done;
2278 : }
2279 0 : break;
2280 : default:
2281 0 : DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n",
2282 : attrs->response_type);
2283 0 : ret = EINVAL;
2284 0 : goto done;
2285 : }
2286 :
2287 0 : ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_SID_STR, &sid_str);
2288 0 : if (ret != EOK) {
2289 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2290 : "Cannot find SID of object with override.\n");
2291 0 : goto done;
2292 : }
2293 :
2294 0 : ret = sysdb_search_object_by_sid(tmp_ctx, dom, sid_str, NULL, &res);
2295 0 : if (ret != EOK) {
2296 0 : DEBUG(SSSDBG_CRIT_FAILURE,
2297 : "Cannot find object with override with SID [%s].\n", sid_str);
2298 0 : goto done;
2299 : }
2300 :
2301 0 : if (!is_default_view(view_name)) {
2302 : /* For the default view the data return by the extdom plugin already
2303 : * contains all needed data and it is not expected to have a separate
2304 : * override object. */
2305 0 : ret = sysdb_store_override(dom, view_name, type, override_attrs,
2306 0 : res->msgs[0]->dn);
2307 0 : if (ret != EOK) {
2308 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_override failed.\n");
2309 0 : goto done;
2310 : }
2311 : }
2312 :
2313 : done:
2314 0 : if (in_transaction) {
2315 0 : tret = sysdb_transaction_cancel(dom->sysdb);
2316 0 : if (tret != EOK) {
2317 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
2318 : }
2319 : }
2320 :
2321 0 : talloc_free(tmp_ctx);
2322 :
2323 0 : return ret;
2324 : }
2325 :
2326 0 : static void ipa_s2n_get_list_done(struct tevent_req *subreq)
2327 : {
2328 : int ret;
2329 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2330 : struct tevent_req);
2331 0 : struct ipa_s2n_get_user_state *state = tevent_req_data(req,
2332 : struct ipa_s2n_get_user_state);
2333 : const char *sid_str;
2334 : struct be_acct_req *ar;
2335 :
2336 0 : ret = ipa_s2n_get_list_recv(subreq);
2337 0 : talloc_zfree(subreq);
2338 0 : if (ret != EOK) {
2339 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n get_fqlist request failed.\n");
2340 0 : tevent_req_error(req, ret);
2341 0 : return;
2342 : }
2343 :
2344 0 : ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR,
2345 : &sid_str);
2346 0 : if (ret == ENOENT) {
2347 0 : ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
2348 : state->simple_attrs, NULL, NULL, true);
2349 0 : if (ret != EOK) {
2350 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
2351 0 : goto fail;
2352 : }
2353 0 : tevent_req_done(req);
2354 0 : return;
2355 0 : } else if (ret != EOK) {
2356 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
2357 0 : goto fail;
2358 : }
2359 :
2360 0 : ret = get_be_acct_req_for_sid(state, sid_str, state->dom->name, &ar);
2361 0 : if (ret != EOK) {
2362 0 : DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
2363 0 : goto fail;
2364 : }
2365 :
2366 0 : if (state->override_attrs == NULL
2367 0 : && !is_default_view(state->ipa_ctx->view_name)) {
2368 0 : subreq = ipa_get_ad_override_send(state, state->ev,
2369 0 : state->ipa_ctx->sdap_id_ctx,
2370 0 : state->ipa_ctx->ipa_options,
2371 0 : dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
2372 : IPA_KRB5_REALM),
2373 0 : state->ipa_ctx->view_name,
2374 : ar);
2375 0 : if (subreq == NULL) {
2376 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
2377 0 : ret = ENOMEM;
2378 0 : goto fail;
2379 : }
2380 0 : tevent_req_set_callback(subreq, ipa_s2n_get_user_get_override_done,
2381 : req);
2382 : } else {
2383 0 : ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
2384 : state->simple_attrs,
2385 0 : state->ipa_ctx->view_name,
2386 : state->override_attrs, true);
2387 0 : if (ret != EOK) {
2388 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
2389 0 : tevent_req_error(req, ret);
2390 0 : return;
2391 : }
2392 :
2393 0 : tevent_req_done(req);
2394 : }
2395 :
2396 0 : return;
2397 :
2398 : fail:
2399 0 : tevent_req_error(req, ret);
2400 0 : return;
2401 : }
2402 :
2403 0 : static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq)
2404 : {
2405 : int ret;
2406 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2407 : struct tevent_req);
2408 0 : struct ipa_s2n_get_user_state *state = tevent_req_data(req,
2409 : struct ipa_s2n_get_user_state);
2410 0 : struct sysdb_attrs *override_attrs = NULL;
2411 :
2412 0 : ret = ipa_get_ad_override_recv(subreq, NULL, state, &override_attrs);
2413 0 : talloc_zfree(subreq);
2414 0 : if (ret != EOK) {
2415 0 : DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
2416 0 : tevent_req_error(req, ret);
2417 0 : return;
2418 : }
2419 :
2420 0 : ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
2421 0 : state->simple_attrs, state->ipa_ctx->view_name,
2422 : override_attrs, true);
2423 0 : if (ret != EOK) {
2424 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
2425 0 : tevent_req_error(req, ret);
2426 0 : return;
2427 : }
2428 :
2429 0 : tevent_req_done(req);
2430 0 : return;
2431 : }
2432 :
2433 0 : int ipa_s2n_get_acct_info_recv(struct tevent_req *req)
2434 : {
2435 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2436 :
2437 0 : return EOK;
2438 : }
2439 :
2440 : struct ipa_get_subdom_acct_process_pac_state {
2441 : struct tevent_context *ev;
2442 : struct sdap_handle *sh;
2443 : struct sss_domain_info *dom;
2444 : char *username;
2445 :
2446 : size_t num_missing_sids;
2447 : char **missing_sids;
2448 : size_t num_cached_groups;
2449 : char **cached_groups;
2450 : };
2451 :
2452 : static void ipa_get_subdom_acct_process_pac_done(struct tevent_req *subreq);
2453 :
2454 0 : struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx,
2455 : struct tevent_context *ev,
2456 : struct sdap_handle *sh,
2457 : struct ipa_id_ctx *ipa_ctx,
2458 : struct sss_domain_info *dom,
2459 : struct ldb_message *user_msg)
2460 : {
2461 : int ret;
2462 : struct ipa_get_subdom_acct_process_pac_state *state;
2463 : struct tevent_req *req;
2464 : struct tevent_req *subreq;
2465 : char *user_sid;
2466 : char *primary_group_sid;
2467 : size_t num_sids;
2468 : char **group_sids;
2469 :
2470 0 : req = tevent_req_create(mem_ctx, &state,
2471 : struct ipa_get_subdom_acct_process_pac_state);
2472 0 : if (req == NULL) {
2473 0 : DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
2474 0 : return NULL;
2475 : }
2476 :
2477 0 : state->ev = ev;
2478 0 : state->sh = sh;
2479 0 : state->dom = dom;
2480 :
2481 0 : ret = ad_get_pac_data_from_user_entry(state, user_msg,
2482 0 : ipa_ctx->sdap_id_ctx->opts->idmap_ctx->map,
2483 0 : &state->username,
2484 : &user_sid, &primary_group_sid,
2485 : &num_sids, &group_sids);
2486 0 : if (ret != EOK) {
2487 0 : DEBUG(SSSDBG_OP_FAILURE, "ad_get_pac_data_from_user_entry failed.\n");
2488 0 : goto done;
2489 : }
2490 :
2491 0 : ret = sdap_ad_tokengroups_get_posix_members(state, state->dom,
2492 : num_sids, group_sids,
2493 0 : &state->num_missing_sids,
2494 0 : &state->missing_sids,
2495 0 : &state->num_cached_groups,
2496 0 : &state->cached_groups);
2497 0 : if (ret != EOK) {
2498 0 : DEBUG(SSSDBG_OP_FAILURE,
2499 : "sdap_ad_tokengroups_get_posix_members failed.\n");
2500 0 : goto done;
2501 : }
2502 :
2503 :
2504 0 : if (state->num_missing_sids == 0) {
2505 0 : ret = sdap_ad_tokengroups_update_members(state->username,
2506 0 : state->dom->sysdb,
2507 0 : state->dom,
2508 0 : state->cached_groups);
2509 0 : if (ret != EOK) {
2510 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Membership update failed [%d]: %s\n",
2511 : ret, strerror(ret));
2512 : }
2513 :
2514 0 : goto done;
2515 : }
2516 :
2517 :
2518 0 : subreq = ipa_s2n_get_list_send(state, state->ev, ipa_ctx, state->dom,
2519 0 : state->sh,
2520 0 : dp_opt_get_int(ipa_ctx->sdap_id_ctx->opts->basic,
2521 : SDAP_SEARCH_TIMEOUT),
2522 : BE_REQ_BY_SECID, REQ_FULL, REQ_INP_SECID,
2523 0 : state->missing_sids);
2524 0 : if (subreq == NULL) {
2525 0 : DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_send failed.\n");
2526 0 : ret = ENOMEM;
2527 0 : goto done;
2528 : }
2529 0 : tevent_req_set_callback(subreq, ipa_get_subdom_acct_process_pac_done, req);
2530 :
2531 0 : return req;
2532 :
2533 : done:
2534 0 : if (ret == EOK) {
2535 0 : tevent_req_done(req);
2536 : } else {
2537 0 : tevent_req_error(req, ret);
2538 : }
2539 0 : tevent_req_post(req, ev);
2540 :
2541 0 : return req;
2542 : }
2543 :
2544 0 : static void ipa_get_subdom_acct_process_pac_done(struct tevent_req *subreq)
2545 : {
2546 : int ret;
2547 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
2548 : struct tevent_req);
2549 0 : struct ipa_get_subdom_acct_process_pac_state *state = tevent_req_data(req,
2550 : struct ipa_get_subdom_acct_process_pac_state);
2551 : char **cached_groups;
2552 : size_t num_cached_groups;
2553 :
2554 0 : ret = ipa_s2n_get_list_recv(subreq);
2555 0 : talloc_zfree(subreq);
2556 0 : if (ret != EOK) {
2557 0 : DEBUG(SSSDBG_OP_FAILURE, "s2n get_fqlist request failed.\n");
2558 0 : tevent_req_error(req, ret);
2559 0 : return;
2560 : }
2561 :
2562 : /* from ad_pac.c */
2563 0 : ret = sdap_ad_tokengroups_get_posix_members(state, state->dom,
2564 : state->num_missing_sids,
2565 : state->missing_sids,
2566 : NULL, NULL,
2567 : &num_cached_groups,
2568 : &cached_groups);
2569 0 : if (ret != EOK){
2570 0 : DEBUG(SSSDBG_MINOR_FAILURE,
2571 : "sdap_ad_tokengroups_get_posix_members failed [%d]: %s\n",
2572 : ret, strerror(ret));
2573 0 : goto done;
2574 : }
2575 :
2576 0 : state->cached_groups = concatenate_string_array(state,
2577 : state->cached_groups,
2578 : state->num_cached_groups,
2579 : cached_groups,
2580 : num_cached_groups);
2581 0 : if (state->cached_groups == NULL) {
2582 0 : ret = ENOMEM;
2583 0 : goto done;
2584 : }
2585 :
2586 : /* update membership of existing groups */
2587 0 : ret = sdap_ad_tokengroups_update_members(state->username,
2588 0 : state->dom->sysdb,
2589 : state->dom,
2590 : state->cached_groups);
2591 0 : if (ret != EOK) {
2592 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Membership update failed [%d]: %s\n",
2593 : ret, strerror(ret));
2594 0 : goto done;
2595 : }
2596 :
2597 0 : ret = EOK;
2598 :
2599 : done:
2600 0 : if (ret == EOK) {
2601 0 : tevent_req_done(req);
2602 : } else {
2603 0 : tevent_req_error(req, ret);
2604 : }
2605 :
2606 0 : return;
2607 : }
2608 :
2609 0 : errno_t ipa_get_subdom_acct_process_pac_recv(struct tevent_req *req)
2610 : {
2611 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
2612 :
2613 0 : return EOK;
2614 : }
|