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