LCOV - code coverage report
Current view: top level - db - sysdb_ops.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 1222 1831 66.7 %
Date: 2015-10-19 Functions: 66 68 97.1 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    System Database
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com>   2008
       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 "db/sysdb_private.h"
      24             : #include "db/sysdb_services.h"
      25             : #include "db/sysdb_autofs.h"
      26             : #include "util/crypto/sss_crypto.h"
      27             : #include "util/cert.h"
      28             : #include <time.h>
      29             : 
      30        1452 : int add_string(struct ldb_message *msg, int flags,
      31             :                const char *attr, const char *value)
      32             : {
      33             :     int ret;
      34             : 
      35        1452 :     ret = ldb_msg_add_empty(msg, attr, flags, NULL);
      36        1452 :     if (ret == LDB_SUCCESS) {
      37        1452 :         ret = ldb_msg_add_string(msg, attr, value);
      38        1452 :         if (ret == LDB_SUCCESS) return EOK;
      39             :     }
      40           0 :     return ENOMEM;
      41             : }
      42             : 
      43         931 : int add_ulong(struct ldb_message *msg, int flags,
      44             :               const char *attr, unsigned long value)
      45             : {
      46             :     int ret;
      47             : 
      48         931 :     ret = ldb_msg_add_empty(msg, attr, flags, NULL);
      49         931 :     if (ret == LDB_SUCCESS) {
      50         931 :         ret = ldb_msg_add_fmt(msg, attr, "%lu", value);
      51         931 :         if (ret == LDB_SUCCESS) return EOK;
      52             :     }
      53           0 :     return ENOMEM;
      54             : }
      55             : 
      56          24 : static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr)
      57             : {
      58          24 :     const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr);
      59             :     long long int l;
      60             : 
      61          24 :     if (!v || !v->data) {
      62           0 :         return 0;
      63             :     }
      64             : 
      65          24 :     errno = 0;
      66          24 :     l = strtoll((const char *)v->data, NULL, 10);
      67          24 :     if (errno) {
      68           0 :         return (uint32_t)-1;
      69             :     }
      70             : 
      71          24 :     if (l < 0 || l > ((uint32_t)(-1))) {
      72           0 :         return (uint32_t)-1;
      73             :     }
      74             : 
      75          24 :     return l;
      76             : }
      77             : 
      78             : /*
      79             :  * The wrapper around ldb_modify that uses LDB_CONTROL_PERMISSIVE_MODIFY_OID
      80             :  * so that on adds entries that already exist are skipped and similarly
      81             :  * entries that are missing are ignored on deletes
      82             :  *
      83             :  * Please note this function returns LDB error codes, not sysdb error
      84             :  * codes on purpose, see usage in callers!
      85             :  */
      86          35 : int sss_ldb_modify_permissive(struct ldb_context *ldb,
      87             :                               struct ldb_message *msg)
      88             : {
      89             :     struct ldb_request *req;
      90          35 :     int ret = EOK;
      91             : 
      92          35 :     ret = ldb_build_mod_req(&req, ldb, ldb,
      93             :                             msg,
      94             :                             NULL,
      95             :                             NULL,
      96             :                             ldb_op_default_callback,
      97             :                             NULL);
      98             : 
      99          35 :     if (ret != LDB_SUCCESS) return ret;
     100             : 
     101          35 :     ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID,
     102             :                                   false, NULL);
     103          35 :     if (ret != LDB_SUCCESS) {
     104           0 :         talloc_free(req);
     105           0 :         return ret;
     106             :     }
     107             : 
     108          35 :     ret = ldb_request(ldb, req);
     109          35 :     if (ret == LDB_SUCCESS) {
     110          35 :         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     111             :     }
     112             : 
     113          35 :     talloc_free(req);
     114             : 
     115             :     /* Please note this function returns LDB error codes, not sysdb error
     116             :      * codes on purpose, see usage in callers!
     117             :      */
     118          35 :     return ret;
     119             : }
     120             : 
     121             : #define ERROR_OUT(v, r, l) do { v = r; goto l; } while(0)
     122             : 
     123             : 
     124             : /* =Remove-Entry-From-Sysdb=============================================== */
     125             : 
     126         299 : int sysdb_delete_entry(struct sysdb_ctx *sysdb,
     127             :                        struct ldb_dn *dn,
     128             :                        bool ignore_not_found)
     129             : {
     130             :     int ret;
     131             : 
     132         299 :     ret = ldb_delete(sysdb->ldb, dn);
     133         299 :     switch (ret) {
     134             :     case LDB_SUCCESS:
     135         299 :         return EOK;
     136             :     case LDB_ERR_NO_SUCH_OBJECT:
     137           0 :         if (ignore_not_found) {
     138           0 :             return EOK;
     139             :         }
     140             :         /* fall through */
     141             :     default:
     142           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n",
     143             :                   ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
     144           0 :         return sysdb_error_to_errno(ret);
     145             :     }
     146             : }
     147             : 
     148             : /* =Remove-Subentries-From-Sysdb=========================================== */
     149             : 
     150           6 : int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
     151             :                            struct ldb_dn *dn,
     152             :                            bool ignore_not_found)
     153             : {
     154           6 :     const char *no_attrs[] = { NULL };
     155             :     struct ldb_message **msgs;
     156             :     size_t msgs_count;
     157             :     int ret;
     158             :     int i;
     159             :     TALLOC_CTX *tmp_ctx;
     160             : 
     161           6 :     tmp_ctx = talloc_new(NULL);
     162           6 :     if (!tmp_ctx) {
     163           0 :         return ENOMEM;
     164             :     }
     165             : 
     166           6 :     ret = ldb_transaction_start(sysdb->ldb);
     167           6 :     if (ret) {
     168           0 :         ret = sysdb_error_to_errno(ret);
     169           0 :         goto done;
     170             :     }
     171             : 
     172           6 :     ret = sysdb_search_entry(tmp_ctx, sysdb, dn,
     173             :                              LDB_SCOPE_SUBTREE, "(distinguishedName=*)",
     174             :                              no_attrs, &msgs_count, &msgs);
     175           6 :     if (ret) {
     176           0 :         if (ignore_not_found && ret == ENOENT) {
     177           0 :             ret = EOK;
     178             :         }
     179           0 :         if (ret) {
     180           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Search error: %d (%s)\n",
     181             :                                      ret, strerror(ret));
     182             :         }
     183           0 :         goto done;
     184             :     }
     185             : 
     186           6 :     DEBUG(SSSDBG_TRACE_ALL, "Found [%zu] items to delete.\n", msgs_count);
     187             : 
     188           6 :     qsort(msgs, msgs_count,
     189             :           sizeof(struct ldb_message *), compare_ldb_dn_comp_num);
     190             : 
     191          30 :     for (i = 0; i < msgs_count; i++) {
     192          24 :         DEBUG(SSSDBG_TRACE_ALL, "Trying to delete [%s].\n",
     193             :                   ldb_dn_get_linearized(msgs[i]->dn));
     194             : 
     195          24 :         ret = sysdb_delete_entry(sysdb, msgs[i]->dn, false);
     196          24 :         if (ret) {
     197           0 :             goto done;
     198             :         }
     199             :     }
     200             : 
     201             : done:
     202           6 :     if (ret == EOK) {
     203           6 :         ret = ldb_transaction_commit(sysdb->ldb);
     204           6 :         ret = sysdb_error_to_errno(ret);
     205             :     } else {
     206           0 :         ldb_transaction_cancel(sysdb->ldb);
     207             :     }
     208           6 :     talloc_free(tmp_ctx);
     209           6 :     return ret;
     210             : }
     211             : 
     212             : 
     213             : /* =Search-Entry========================================================== */
     214             : 
     215        2038 : int sysdb_search_entry(TALLOC_CTX *mem_ctx,
     216             :                        struct sysdb_ctx *sysdb,
     217             :                        struct ldb_dn *base_dn,
     218             :                        enum ldb_scope scope,
     219             :                        const char *filter,
     220             :                        const char **attrs,
     221             :                        size_t *_msgs_count,
     222             :                        struct ldb_message ***_msgs)
     223             : {
     224             :     TALLOC_CTX *tmp_ctx;
     225             :     struct ldb_result *res;
     226             :     int ret;
     227             : 
     228        2038 :     tmp_ctx = talloc_new(NULL);
     229        2038 :     if (tmp_ctx == NULL) {
     230           0 :         ret = ENOMEM;
     231           0 :         goto done;
     232             :     }
     233             : 
     234        2038 :     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
     235             :                      base_dn, scope, attrs,
     236             :                      filter?"%s":NULL, filter);
     237        2038 :     if (ret != EOK) {
     238           0 :         ret = sysdb_error_to_errno(ret);
     239           0 :         goto done;
     240             :     }
     241             : 
     242        2038 :     *_msgs_count = res->count;
     243        2038 :     *_msgs = talloc_steal(mem_ctx, res->msgs);
     244             : 
     245        2038 :     if (res->count == 0) {
     246         970 :         ret = ENOENT;
     247         970 :         goto done;
     248             :     }
     249             : 
     250             : done:
     251        2038 :     talloc_zfree(tmp_ctx);
     252        2038 :     return ret;
     253             : }
     254             : 
     255             : /* =Search-Entry-by-SID-string============================================ */
     256             : 
     257           8 : int sysdb_search_entry_by_sid_str(TALLOC_CTX *mem_ctx,
     258             :                                   struct sss_domain_info *domain,
     259             :                                   const char *search_base,
     260             :                                   const char *filter_str,
     261             :                                   const char *sid_str,
     262             :                                   const char **attrs,
     263             :                                   struct ldb_message **msg)
     264             : {
     265             :     TALLOC_CTX *tmp_ctx;
     266           8 :     const char *def_attrs[] = { SYSDB_NAME, SYSDB_SID_STR, NULL };
     267           8 :     struct ldb_message **msgs = NULL;
     268             :     struct ldb_dn *basedn;
     269           8 :     size_t msgs_count = 0;
     270             :     char *filter;
     271             :     int ret;
     272             : 
     273           8 :     tmp_ctx = talloc_new(NULL);
     274           8 :     if (!tmp_ctx) {
     275           0 :         return ENOMEM;
     276             :     }
     277             : 
     278           8 :     basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
     279             :                             search_base, domain->name);
     280           8 :     if (!basedn) {
     281           0 :         ret = ENOMEM;
     282           0 :         goto done;
     283             :     }
     284             : 
     285           8 :     filter = talloc_asprintf(tmp_ctx, filter_str, sid_str);
     286           8 :     if (!filter) {
     287           0 :         ret = ENOMEM;
     288           0 :         goto done;
     289             :     }
     290             : 
     291           8 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
     292             :                              filter, attrs?attrs:def_attrs, &msgs_count,
     293             :                              &msgs);
     294           8 :     if (ret) {
     295           5 :         goto done;
     296             :     }
     297             : 
     298           3 :     *msg = talloc_steal(mem_ctx, msgs[0]);
     299             : 
     300             : done:
     301           8 :     if (ret == ENOENT) {
     302           5 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     303             :     }
     304           3 :     else if (ret) {
     305           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     306             :     }
     307             : 
     308           8 :     talloc_zfree(tmp_ctx);
     309           8 :     return ret;
     310             : }
     311             : 
     312             : /* =Search-User-by-[UID/SID/NAME]============================================= */
     313             : 
     314             : enum sysdb_obj_type {
     315             :     SYSDB_UNKNOWN = 0,
     316             :     SYSDB_USER,
     317             :     SYSDB_GROUP
     318             : };
     319             : 
     320         575 : static int sysdb_search_by_name(TALLOC_CTX *mem_ctx,
     321             :                                 struct sss_domain_info *domain,
     322             :                                 const char *name,
     323             :                                 enum sysdb_obj_type type,
     324             :                                 const char **attrs,
     325             :                                 struct ldb_message **msg)
     326             : {
     327             :     TALLOC_CTX *tmp_ctx;
     328         575 :     const char *def_attrs[] = { SYSDB_NAME, NULL, NULL };
     329         575 :     const char *base_tmpl = NULL;
     330         575 :     const char *filter_tmpl = NULL;
     331         575 :     struct ldb_message **msgs = NULL;
     332             :     struct ldb_dn *basedn;
     333         575 :     size_t msgs_count = 0;
     334             :     char *sanitized_name;
     335             :     char *lc_sanitized_name;
     336             :     char *filter;
     337             :     int ret;
     338             : 
     339         575 :     switch (type) {
     340             :     case SYSDB_USER:
     341         352 :         def_attrs[1] = SYSDB_UIDNUM;
     342         352 :         base_tmpl = SYSDB_TMPL_USER_BASE;
     343         352 :         filter_tmpl = SYSDB_PWNAM_FILTER;
     344         352 :         break;
     345             :     case SYSDB_GROUP:
     346         223 :         def_attrs[1] = SYSDB_GIDNUM;
     347         223 :         base_tmpl = SYSDB_TMPL_GROUP_BASE;
     348         223 :         filter_tmpl = SYSDB_GRNAM_FILTER;
     349         223 :         break;
     350             :     default:
     351           0 :         return EINVAL;
     352             :     }
     353             : 
     354         575 :     tmp_ctx = talloc_new(NULL);
     355         575 :     if (!tmp_ctx) {
     356           0 :         return ENOMEM;
     357             :     }
     358             : 
     359         575 :     basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
     360             :                             base_tmpl, domain->name);
     361         575 :     if (!basedn) {
     362           0 :         ret = ENOMEM;
     363           0 :         goto done;
     364             :     }
     365             : 
     366         575 :     ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name,
     367             :                                       &lc_sanitized_name);
     368         575 :     if (ret != EOK) {
     369           0 :         goto done;
     370             :     }
     371             : 
     372         575 :     filter = talloc_asprintf(tmp_ctx, filter_tmpl, lc_sanitized_name,
     373             :                              sanitized_name, sanitized_name);
     374         575 :     if (!filter) {
     375           0 :         ret = ENOMEM;
     376           0 :         goto done;
     377             :     }
     378             : 
     379         575 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
     380             :                              filter, attrs?attrs:def_attrs,
     381             :                              &msgs_count, &msgs);
     382         575 :     if (ret) {
     383         382 :         goto done;
     384             :     }
     385             : 
     386         193 :     *msg = talloc_steal(mem_ctx, msgs[0]);
     387             : 
     388             : done:
     389         575 :     if (ret == ENOENT) {
     390         382 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     391             :     }
     392         193 :     else if (ret) {
     393           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     394             :     }
     395         575 :     talloc_zfree(tmp_ctx);
     396         575 :     return ret;
     397             : }
     398             : 
     399         352 : int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx,
     400             :                               struct sss_domain_info *domain,
     401             :                               const char *name,
     402             :                               const char **attrs,
     403             :                               struct ldb_message **msg)
     404             : {
     405         352 :     return sysdb_search_by_name(mem_ctx, domain, name, SYSDB_USER, attrs, msg);
     406             : }
     407             : 
     408         192 : int sysdb_search_user_by_uid(TALLOC_CTX *mem_ctx,
     409             :                              struct sss_domain_info *domain,
     410             :                              uid_t uid,
     411             :                              const char **attrs,
     412             :                              struct ldb_message **msg)
     413             : {
     414             :     TALLOC_CTX *tmp_ctx;
     415         192 :     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL };
     416         192 :     struct ldb_message **msgs = NULL;
     417             :     struct ldb_dn *basedn;
     418         192 :     size_t msgs_count = 0;
     419             :     char *filter;
     420             :     int ret;
     421             : 
     422         192 :     tmp_ctx = talloc_new(NULL);
     423         192 :     if (!tmp_ctx) {
     424           0 :         return ENOMEM;
     425             :     }
     426             : 
     427         192 :     basedn = sysdb_user_base_dn(tmp_ctx, domain);
     428         192 :     if (!basedn) {
     429           0 :         ret = ENOMEM;
     430           0 :         goto done;
     431             :     }
     432             : 
     433         192 :     filter = talloc_asprintf(tmp_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid);
     434         192 :     if (!filter) {
     435           0 :         ret = ENOMEM;
     436           0 :         goto done;
     437             :     }
     438             : 
     439             :     /* Use SUBTREE scope here, not ONELEVEL
     440             :      * There is a bug in LDB that makes ONELEVEL searches extremely
     441             :      * slow (it ignores indexing)
     442             :      */
     443         192 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn,
     444             :                              LDB_SCOPE_SUBTREE, filter,
     445             :                              attrs?attrs:def_attrs, &msgs_count, &msgs);
     446         192 :     if (ret) {
     447         169 :         goto done;
     448             :     }
     449             : 
     450          23 :     *msg = talloc_steal(mem_ctx, msgs[0]);
     451             : 
     452             : done:
     453         192 :     if (ret == ENOENT) {
     454         169 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     455             :     }
     456          23 :     else if (ret) {
     457           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     458             :     }
     459             : 
     460         192 :     talloc_zfree(tmp_ctx);
     461         192 :     return ret;
     462             : }
     463             : 
     464           5 : int sysdb_search_user_by_sid_str(TALLOC_CTX *mem_ctx,
     465             :                                  struct sss_domain_info *domain,
     466             :                                  const char *sid_str,
     467             :                                  const char **attrs,
     468             :                                  struct ldb_message **msg)
     469             : {
     470             : 
     471           5 :    return sysdb_search_entry_by_sid_str(mem_ctx, domain,
     472             :                                         SYSDB_TMPL_USER_BASE,
     473             :                                         SYSDB_PWSID_FILTER,
     474             :                                         sid_str, attrs, msg);
     475             : }
     476             : 
     477          40 : int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx,
     478             :                                  struct sss_domain_info *domain,
     479             :                                  const char *upn,
     480             :                                  const char **attrs,
     481             :                                  struct ldb_result **out_res)
     482             : {
     483             :     TALLOC_CTX *tmp_ctx;
     484             :     struct ldb_result *res;
     485             :     struct ldb_dn *base_dn;
     486             :     int ret;
     487          40 :     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN,
     488             :                                 NULL };
     489             : 
     490          40 :     tmp_ctx = talloc_new(NULL);
     491          40 :     if (tmp_ctx == NULL) {
     492           0 :         ret = ENOMEM;
     493           0 :         goto done;
     494             :     }
     495             : 
     496          40 :     base_dn = sysdb_base_dn(domain->sysdb, tmp_ctx);
     497          40 :     if (base_dn == NULL) {
     498           0 :         ret = ENOMEM;
     499           0 :         goto done;
     500             :     }
     501             : 
     502          40 :     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
     503             :                      base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs,
     504             :                      SYSDB_PWUPN_FILTER, upn, upn);
     505          40 :     if (ret != EOK) {
     506           0 :         ret = sysdb_error_to_errno(ret);
     507           0 :         goto done;
     508             :     }
     509             : 
     510          40 :     if (res->count == 0) {
     511             :         /* set result anyway */
     512          25 :         *out_res = talloc_steal(mem_ctx, res);
     513          25 :         ret = ENOENT;
     514          25 :         goto done;
     515          15 :     } else if (res->count > 1) {
     516           1 :         DEBUG(SSSDBG_OP_FAILURE,
     517             :               "Search for upn [%s] returns more than one result.\n", upn);
     518           1 :         ret = EINVAL;
     519           1 :         goto done;
     520             :     }
     521             : 
     522          14 :     *out_res = talloc_steal(mem_ctx, res);
     523          14 :     ret = EOK;
     524             : 
     525             : done:
     526          40 :     talloc_zfree(tmp_ctx);
     527          40 :     return ret;
     528             : }
     529             : 
     530          17 : int sysdb_search_user_by_upn(TALLOC_CTX *mem_ctx,
     531             :                              struct sss_domain_info *domain,
     532             :                              const char *upn,
     533             :                              const char **attrs,
     534             :                              struct ldb_message **msg)
     535             : {
     536             :     TALLOC_CTX *tmp_ctx;
     537             :     struct ldb_result *res;
     538             :     errno_t ret;
     539             : 
     540          17 :     tmp_ctx = talloc_new(NULL);
     541          17 :     if (tmp_ctx == NULL) {
     542           0 :         ret = ENOMEM;
     543           0 :         goto done;
     544             :     }
     545             : 
     546          17 :     ret = sysdb_search_user_by_upn_res(tmp_ctx, domain, upn, attrs, &res);
     547          17 :     if (ret == ENOENT) {
     548           8 :         DEBUG(SSSDBG_TRACE_FUNC, "No entry with upn [%s] found.\n", upn);
     549           8 :         goto done;
     550           9 :     } else if (ret != EOK) {
     551           1 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     552           1 :         goto done;
     553             :     }
     554             : 
     555           8 :     *msg = talloc_steal(mem_ctx, res->msgs[0]);
     556             : 
     557           8 :     ret = EOK;
     558             : 
     559             : done:
     560          17 :     talloc_zfree(tmp_ctx);
     561          17 :     return ret;
     562             : }
     563             : 
     564             : /* =Search-Group-by-[GID/SID/NAME]============================================ */
     565             : 
     566         223 : int sysdb_search_group_by_name(TALLOC_CTX *mem_ctx,
     567             :                                struct sss_domain_info *domain,
     568             :                                const char *name,
     569             :                                const char **attrs,
     570             :                                struct ldb_message **msg)
     571             : {
     572         223 :     return sysdb_search_by_name(mem_ctx, domain, name, SYSDB_GROUP, attrs, msg);
     573             : }
     574             : 
     575         843 : int sysdb_search_group_by_gid(TALLOC_CTX *mem_ctx,
     576             :                               struct sss_domain_info *domain,
     577             :                               gid_t gid,
     578             :                               const char **attrs,
     579             :                               struct ldb_message **msg)
     580             : {
     581             :     TALLOC_CTX *tmp_ctx;
     582         843 :     const char *def_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL };
     583         843 :     struct ldb_message **msgs = NULL;
     584             :     struct ldb_dn *basedn;
     585         843 :     size_t msgs_count = 0;
     586             :     char *filter;
     587             :     int ret;
     588             : 
     589         843 :     tmp_ctx = talloc_new(NULL);
     590         843 :     if (!tmp_ctx) {
     591           0 :         return ENOMEM;
     592             :     }
     593             : 
     594         843 :     basedn = sysdb_group_base_dn(tmp_ctx, domain);
     595         843 :     if (!basedn) {
     596           0 :         ret = ENOMEM;
     597           0 :         goto done;
     598             :     }
     599             : 
     600         843 :     filter = talloc_asprintf(tmp_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid);
     601         843 :     if (!filter) {
     602           0 :         ret = ENOMEM;
     603           0 :         goto done;
     604             :     }
     605             : 
     606             :     /* Use SUBTREE scope here, not ONELEVEL
     607             :      * There is a bug in LDB that makes ONELEVEL searches extremely
     608             :      * slow (it ignores indexing)
     609             :      */
     610         843 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_SUBTREE,
     611             :                              filter, attrs?attrs:def_attrs,
     612             :                              &msgs_count, &msgs);
     613         843 :     if (ret) {
     614         149 :         goto done;
     615             :     }
     616             : 
     617         694 :     *msg = talloc_steal(mem_ctx, msgs[0]);
     618             : 
     619             : done:
     620         843 :     if (ret == ENOENT) {
     621         149 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     622             :     }
     623         694 :     else if (ret) {
     624           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     625             :     }
     626             : 
     627         843 :     talloc_zfree(tmp_ctx);
     628         843 :     return ret;
     629             : }
     630             : 
     631           3 : int sysdb_search_group_by_sid_str(TALLOC_CTX *mem_ctx,
     632             :                                   struct sss_domain_info *domain,
     633             :                                   const char *sid_str,
     634             :                                   const char **attrs,
     635             :                                   struct ldb_message **msg)
     636             : {
     637             : 
     638           3 :    return sysdb_search_entry_by_sid_str(mem_ctx, domain,
     639             :                                         SYSDB_TMPL_GROUP_BASE,
     640             :                                         SYSDB_GRSID_FILTER,
     641             :                                         sid_str, attrs, msg);
     642             : }
     643             : 
     644             : /* =Search-Group-by-Name============================================ */
     645             : 
     646          16 : int sysdb_search_netgroup_by_name(TALLOC_CTX *mem_ctx,
     647             :                                   struct sss_domain_info *domain,
     648             :                                   const char *name,
     649             :                                   const char **attrs,
     650             :                                   struct ldb_message **msg)
     651             : {
     652             :     TALLOC_CTX *tmp_ctx;
     653             :     static const char *def_attrs[] = { SYSDB_NAME, NULL };
     654          16 :     struct ldb_message **msgs = NULL;
     655             :     struct ldb_dn *basedn;
     656          16 :     size_t msgs_count = 0;
     657             :     int ret;
     658             : 
     659          16 :     tmp_ctx = talloc_new(NULL);
     660          16 :     if (!tmp_ctx) {
     661           0 :         return ENOMEM;
     662             :     }
     663             : 
     664          16 :     basedn = sysdb_netgroup_dn(tmp_ctx, domain, name);
     665          16 :     if (!basedn) {
     666           0 :         ret = ENOMEM;
     667           0 :         goto done;
     668             :     }
     669             : 
     670          16 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn, LDB_SCOPE_BASE,
     671             :                              NULL, attrs?attrs:def_attrs, &msgs_count,
     672             :                              &msgs);
     673          16 :     if (ret) {
     674           1 :         goto done;
     675             :     }
     676             : 
     677          15 :     *msg = talloc_steal(mem_ctx, msgs[0]);
     678             : 
     679             : done:
     680          16 :     if (ret == ENOENT) {
     681           1 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     682             :     }
     683          15 :     else if (ret) {
     684           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     685             :     }
     686          16 :     talloc_zfree(tmp_ctx);
     687          16 :     return ret;
     688             : }
     689             : 
     690             : /* =Replace-Attributes-On-Entry=========================================== */
     691             : 
     692         506 : int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
     693             :                          struct ldb_dn *entry_dn,
     694             :                          struct sysdb_attrs *attrs,
     695             :                          int mod_op)
     696             : {
     697             :     struct ldb_message *msg;
     698             :     int i, ret;
     699             :     int lret;
     700             :     TALLOC_CTX *tmp_ctx;
     701             : 
     702         506 :     tmp_ctx = talloc_new(NULL);
     703         506 :     if (!tmp_ctx) {
     704           0 :         return ENOMEM;
     705             :     }
     706             : 
     707         506 :     if (!entry_dn || attrs->num == 0) {
     708           0 :         ret = EINVAL;
     709           0 :         goto done;
     710             :     }
     711             : 
     712         506 :     msg = ldb_msg_new(tmp_ctx);
     713         506 :     if (!msg) {
     714           0 :         ret = ENOMEM;
     715           0 :         goto done;
     716             :     }
     717             : 
     718         506 :     msg->dn = entry_dn;
     719             : 
     720         506 :     msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num);
     721         506 :     if (!msg->elements) {
     722           0 :         ret = ENOMEM;
     723           0 :         goto done;
     724             :     }
     725             : 
     726        1952 :     for (i = 0; i < attrs->num; i++) {
     727        1446 :         msg->elements[i] = attrs->a[i];
     728        1446 :         msg->elements[i].flags = mod_op;
     729             :     }
     730             : 
     731         506 :     msg->num_elements = attrs->num;
     732             : 
     733         506 :     lret = ldb_modify(sysdb->ldb, msg);
     734         506 :     if (lret != LDB_SUCCESS) {
     735           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     736             :               "ldb_modify failed: [%s](%d)[%s]\n",
     737             :               ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb));
     738             :     }
     739             : 
     740         506 :     ret = sysdb_error_to_errno(lret);
     741             : 
     742             : done:
     743         506 :     if (ret == ENOENT) {
     744           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
     745             :     }
     746         506 :     else if (ret) {
     747           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
     748             :     }
     749         506 :     talloc_zfree(tmp_ctx);
     750         506 :     return ret;
     751             : }
     752             : 
     753             : 
     754             : /* =Replace-Attributes-On-User============================================ */
     755             : 
     756         268 : int sysdb_set_user_attr(struct sss_domain_info *domain,
     757             :                         const char *name,
     758             :                         struct sysdb_attrs *attrs,
     759             :                         int mod_op)
     760             : {
     761             :     struct ldb_dn *dn;
     762             :     TALLOC_CTX *tmp_ctx;
     763             :     errno_t ret;
     764             : 
     765         268 :     tmp_ctx = talloc_new(NULL);
     766         268 :     if (!tmp_ctx) {
     767           0 :         return ENOMEM;
     768             :     }
     769             : 
     770         268 :     dn = sysdb_user_dn(tmp_ctx, domain, name);
     771         268 :     if (!dn) {
     772           0 :         ret = ENOMEM;
     773           0 :         goto done;
     774             :     }
     775             : 
     776         268 :     ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
     777         268 :     if (ret != EOK) {
     778           0 :         goto done;
     779             :     }
     780             : 
     781         268 :     ret = EOK;
     782             : done:
     783         268 :     talloc_zfree(tmp_ctx);
     784         268 :     return ret;
     785             : }
     786             : 
     787             : 
     788             : /* =Replace-Attributes-On-Group=========================================== */
     789             : 
     790         223 : int sysdb_set_group_attr(struct sss_domain_info *domain,
     791             :                          const char *name,
     792             :                          struct sysdb_attrs *attrs,
     793             :                          int mod_op)
     794             : {
     795             :     struct ldb_dn *dn;
     796             :     TALLOC_CTX *tmp_ctx;
     797             :     errno_t ret;
     798             : 
     799         223 :     tmp_ctx = talloc_new(NULL);
     800         223 :     if (!tmp_ctx) {
     801           0 :         ret = ENOMEM;
     802           0 :         goto done;
     803             :     }
     804             : 
     805         223 :     dn = sysdb_group_dn(tmp_ctx, domain, name);
     806         223 :     if (!dn) {
     807           0 :         ret = ENOMEM;
     808           0 :         goto done;
     809             :     }
     810             : 
     811         223 :     ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
     812         223 :     if (ret) {
     813           0 :         goto done;
     814             :     }
     815             : 
     816         223 :     ret = EOK;
     817             : done:
     818         223 :     talloc_free(tmp_ctx);
     819         223 :     return ret;
     820             : }
     821             : 
     822             : /* =Replace-Attributes-On-Netgroup=========================================== */
     823             : 
     824          11 : int sysdb_set_netgroup_attr(struct sss_domain_info *domain,
     825             :                             const char *name,
     826             :                             struct sysdb_attrs *attrs,
     827             :                             int mod_op)
     828             : {
     829             :     errno_t ret;
     830             :     struct ldb_dn *dn;
     831             :     TALLOC_CTX *tmp_ctx;
     832             : 
     833          11 :     tmp_ctx = talloc_new(NULL);
     834          11 :     if (!tmp_ctx) {
     835           0 :         return ENOMEM;
     836             :     }
     837             : 
     838          11 :     dn = sysdb_netgroup_dn(tmp_ctx, domain, name);
     839          11 :     if (!dn) {
     840           0 :         ret = ENOMEM;
     841           0 :         goto done;
     842             :     }
     843             : 
     844          11 :     ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
     845             : 
     846             : done:
     847          11 :     talloc_free(tmp_ctx);
     848          11 :     return ret;
     849             : }
     850             : 
     851             : /* =Get-New-ID============================================================ */
     852             : 
     853          26 : int sysdb_get_new_id(struct sss_domain_info *domain,
     854             :                      uint32_t *_id)
     855             : {
     856             :     TALLOC_CTX *tmp_ctx;
     857          26 :     const char *attrs_1[] = { SYSDB_NEXTID, NULL };
     858          26 :     const char *attrs_2[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL };
     859             :     struct ldb_dn *base_dn;
     860             :     char *filter;
     861          26 :     uint32_t new_id = 0;
     862             :     struct ldb_message **msgs;
     863             :     size_t count;
     864             :     struct ldb_message *msg;
     865             :     uint32_t id;
     866             :     int ret;
     867             :     int i;
     868             : 
     869          26 :     tmp_ctx = talloc_new(NULL);
     870          26 :     if (!tmp_ctx) {
     871           0 :         return ENOMEM;
     872             :     }
     873             : 
     874          26 :     base_dn = sysdb_domain_dn(tmp_ctx, domain);
     875          26 :     if (!base_dn) {
     876           0 :         talloc_zfree(tmp_ctx);
     877           0 :         return ENOMEM;
     878             :     }
     879             : 
     880          26 :     ret = ldb_transaction_start(domain->sysdb->ldb);
     881          26 :     if (ret) {
     882           0 :         talloc_zfree(tmp_ctx);
     883           0 :         ret = sysdb_error_to_errno(ret);
     884           0 :         return ret;
     885             :     }
     886             : 
     887          26 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn, LDB_SCOPE_BASE,
     888             :                              SYSDB_NEXTID_FILTER, attrs_1, &count, &msgs);
     889          26 :     switch (ret) {
     890             :     case EOK:
     891          24 :         new_id = get_attr_as_uint32(msgs[0], SYSDB_NEXTID);
     892          24 :         if (new_id == (uint32_t)(-1)) {
     893           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     894             :                   "Invalid Next ID in domain %s\n", domain->name);
     895           0 :             ret = ERANGE;
     896           0 :             goto done;
     897             :         }
     898             : 
     899          24 :         if (new_id < domain->id_min) {
     900           0 :             new_id = domain->id_min;
     901             :         }
     902             : 
     903          24 :         if ((domain->id_max != 0) && (new_id > domain->id_max)) {
     904           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     905             :                   "Failed to allocate new id, out of range (%u/%u)\n",
     906             :                       new_id, domain->id_max);
     907           0 :             ret = ERANGE;
     908           0 :             goto done;
     909             :         }
     910          24 :         break;
     911             : 
     912             :     case ENOENT:
     913             :         /* looks like the domain is not initialized yet, use min_id */
     914           2 :         new_id = domain->id_min;
     915           2 :         break;
     916             : 
     917             :     default:
     918           0 :         goto done;
     919             :     }
     920          26 :     talloc_zfree(msgs);
     921          26 :     count = 0;
     922             : 
     923             :     /* verify the id is actually really free.
     924             :      * search all entries with id >= new_id and < max_id */
     925          26 :     if (domain->id_max) {
     926           0 :         filter = talloc_asprintf(tmp_ctx,
     927             :                                  "(|(&(%s>=%u)(%s<=%u))(&(%s>=%u)(%s<=%u)))",
     928             :                                  SYSDB_UIDNUM, new_id,
     929             :                                  SYSDB_UIDNUM, domain->id_max,
     930             :                                  SYSDB_GIDNUM, new_id,
     931             :                                  SYSDB_GIDNUM, domain->id_max);
     932             :     }
     933             :     else {
     934          26 :         filter = talloc_asprintf(tmp_ctx,
     935             :                                  "(|(%s>=%u)(%s>=%u))",
     936             :                                  SYSDB_UIDNUM, new_id,
     937             :                                  SYSDB_GIDNUM, new_id);
     938             :     }
     939          26 :     if (!filter) {
     940           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: Out of memory\n");
     941           0 :         ret = ENOMEM;
     942           0 :         goto done;
     943             :     }
     944             : 
     945          26 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn, LDB_SCOPE_SUBTREE,
     946             :                              filter, attrs_2, &count, &msgs);
     947          26 :     switch (ret) {
     948             :     /* if anything was found, find the maximum and increment past it */
     949             :     case EOK:
     950           0 :         for (i = 0; i < count; i++) {
     951           0 :             id = get_attr_as_uint32(msgs[i], SYSDB_UIDNUM);
     952           0 :             if (id != (uint32_t)(-1)) {
     953           0 :                 if (id > new_id) new_id = id;
     954             :             }
     955           0 :             id = get_attr_as_uint32(msgs[i], SYSDB_GIDNUM);
     956           0 :             if (id != (uint32_t)(-1)) {
     957           0 :                 if (id > new_id) new_id = id;
     958             :             }
     959             :         }
     960             : 
     961           0 :         new_id++;
     962             : 
     963             :         /* check again we are not falling out of range */
     964           0 :         if ((domain->id_max != 0) && (new_id > domain->id_max)) {
     965           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     966             :                   "Failed to allocate new id, out of range (%u/%u)\n",
     967             :                       new_id, domain->id_max);
     968           0 :             ret = ERANGE;
     969           0 :             goto done;
     970             :         }
     971           0 :         break;
     972             : 
     973             :     case ENOENT:
     974          26 :         break;
     975             : 
     976             :     default:
     977           0 :         goto done;
     978             :     }
     979             : 
     980          26 :     talloc_zfree(msgs);
     981          26 :     count = 0;
     982             : 
     983             :     /* finally store the new next id */
     984          26 :     msg = ldb_msg_new(tmp_ctx);
     985          26 :     if (!msg) {
     986           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: Out of memory\n");
     987           0 :         ret = ENOMEM;
     988           0 :         goto done;
     989             :     }
     990          26 :     msg->dn = base_dn;
     991             : 
     992          26 :     ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE,
     993          26 :                     SYSDB_NEXTID, new_id + 1);
     994          26 :     if (ret) {
     995           0 :         goto done;
     996             :     }
     997             : 
     998          26 :     ret = ldb_modify(domain->sysdb->ldb, msg);
     999          26 :     if (ret != LDB_SUCCESS) {
    1000           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1001             :               "ldb_modify failed: [%s](%d)[%s]\n",
    1002             :               ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
    1003             :     }
    1004          26 :     ret = sysdb_error_to_errno(ret);
    1005             : 
    1006          26 :     *_id = new_id;
    1007             : 
    1008             : done:
    1009          26 :     if (ret == EOK) {
    1010          26 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    1011          26 :         ret = sysdb_error_to_errno(ret);
    1012             :     } else {
    1013           0 :         ldb_transaction_cancel(domain->sysdb->ldb);
    1014             :     }
    1015          26 :     if (ret) {
    1016           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1017             :     }
    1018          26 :     talloc_zfree(tmp_ctx);
    1019          26 :     return ret;
    1020             : }
    1021             : 
    1022             : 
    1023             : /* =Add-Basic-User-NO-CHECKS============================================== */
    1024             : 
    1025         181 : int sysdb_add_basic_user(struct sss_domain_info *domain,
    1026             :                          const char *name,
    1027             :                          uid_t uid, gid_t gid,
    1028             :                          const char *gecos,
    1029             :                          const char *homedir,
    1030             :                          const char *shell)
    1031             : {
    1032             :     struct ldb_message *msg;
    1033             :     int ret;
    1034             :     TALLOC_CTX *tmp_ctx;
    1035             : 
    1036         181 :     tmp_ctx = talloc_new(NULL);
    1037         181 :     if (!tmp_ctx) {
    1038           0 :         return ENOMEM;
    1039             :     }
    1040             : 
    1041         181 :     msg = ldb_msg_new(tmp_ctx);
    1042         181 :     if (!msg) {
    1043           0 :         ret = ENOMEM;
    1044           0 :         goto done;
    1045             :     }
    1046             : 
    1047             :     /* user dn */
    1048         181 :     msg->dn = sysdb_user_dn(msg, domain, name);
    1049         181 :     if (!msg->dn) {
    1050           0 :         ERROR_OUT(ret, ENOMEM, done);
    1051             :     }
    1052             : 
    1053         181 :     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
    1054         181 :     if (ret) goto done;
    1055             : 
    1056         181 :     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
    1057         181 :     if (ret) goto done;
    1058             : 
    1059         181 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_UIDNUM, (unsigned long)uid);
    1060         181 :     if (ret) goto done;
    1061             : 
    1062         181 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid);
    1063         181 :     if (ret) goto done;
    1064             : 
    1065             :     /* We set gecos to be the same as fullname on user creation,
    1066             :      * But we will not enforce coherency after that, it's up to
    1067             :      * admins to decide if they want to keep it in sync if they change
    1068             :      * one of the 2 */
    1069         181 :     if (gecos && *gecos) {
    1070         160 :         ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_FULLNAME, gecos);
    1071         160 :         if (ret) goto done;
    1072         160 :         ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_GECOS, gecos);
    1073         160 :         if (ret) goto done;
    1074             :     }
    1075             : 
    1076         181 :     if (homedir && *homedir) {
    1077         158 :         ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_HOMEDIR, homedir);
    1078         158 :         if (ret) goto done;
    1079             :     }
    1080             : 
    1081         181 :     if (shell && *shell) {
    1082         158 :         ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_SHELL, shell);
    1083         158 :         if (ret) goto done;
    1084             :     }
    1085             : 
    1086             :     /* creation time */
    1087         181 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
    1088         181 :                     (unsigned long)time(NULL));
    1089         181 :     if (ret) goto done;
    1090             : 
    1091         181 :     ret = ldb_add(domain->sysdb->ldb, msg);
    1092         181 :     ret = sysdb_error_to_errno(ret);
    1093             : 
    1094             : done:
    1095         181 :     if (ret) {
    1096           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1097             :     }
    1098         181 :     talloc_zfree(tmp_ctx);
    1099         181 :     return ret;
    1100             : }
    1101             : 
    1102             : static errno_t
    1103          35 : sysdb_remove_ghost_from_group(struct sss_domain_info *dom,
    1104             :                               struct ldb_message *group,
    1105             :                               struct ldb_message_element *alias_el,
    1106             :                               const char *name,
    1107             :                               const char *orig_dn,
    1108             :                               const char *userdn)
    1109             : {
    1110             :     TALLOC_CTX *tmp_ctx;
    1111             :     struct ldb_message *msg;
    1112             :     struct ldb_message_element *orig_members;
    1113          35 :     bool add_member = false;
    1114          35 :     errno_t ret = EOK;
    1115             :     int i;
    1116             : 
    1117          35 :     tmp_ctx = talloc_new(NULL);
    1118          35 :     if (!tmp_ctx) {
    1119           0 :         return ENOENT;
    1120             :     }
    1121             : 
    1122          35 :     msg = ldb_msg_new(tmp_ctx);
    1123          35 :     if (!msg) {
    1124           0 :         ERROR_OUT(ret, ENOMEM, done);
    1125             :     }
    1126             : 
    1127          35 :     msg->dn = group->dn;
    1128             : 
    1129          35 :     if (orig_dn == NULL) {
    1130             :         /* We have no way of telling which groups this user belongs to.
    1131             :          * Add it to all that reference it in the ghost attribute */
    1132          35 :         add_member = true;
    1133             :     } else {
    1134           0 :         add_member = false;
    1135           0 :         orig_members = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
    1136           0 :         if (orig_members) {
    1137           0 :             for (i = 0; i < orig_members->num_values; i++) {
    1138           0 :                 if (strcmp((const char *) orig_members->values[i].data,
    1139             :                             orig_dn) == 0) {
    1140             :                     /* This is a direct member. Add the member attribute */
    1141           0 :                     add_member = true;
    1142             :                 }
    1143             :             }
    1144             :         } else {
    1145             :             /* Nothing to compare the originalDN with. Let's rely on the
    1146             :              * memberof plugin to do the right thing during initgroups..
    1147             :              */
    1148           0 :             add_member = true;
    1149             :         }
    1150             :     }
    1151             : 
    1152          35 :     if (add_member) {
    1153          35 :         ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_MEMBER, userdn);
    1154          35 :         if (ret) goto done;
    1155             :     }
    1156             : 
    1157          35 :     ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_GHOST, name);
    1158          35 :     if (ret) goto done;
    1159             : 
    1160             :     /* Delete aliases from the ghost attribute as well */
    1161          35 :     for (i = 0; i < alias_el->num_values; i++) {
    1162           0 :         if (strcmp((const char *)alias_el->values[i].data, name) == 0) {
    1163           0 :             continue;
    1164             :         }
    1165           0 :         ret = ldb_msg_add_string(msg, SYSDB_GHOST,
    1166           0 :                 (char *) alias_el->values[i].data);
    1167           0 :         if (ret != LDB_SUCCESS) {
    1168           0 :             ERROR_OUT(ret, EINVAL, done);
    1169             :         }
    1170             :     }
    1171             : 
    1172             : 
    1173          35 :     ret = sss_ldb_modify_permissive(dom->sysdb->ldb, msg);
    1174          35 :     if (ret != LDB_SUCCESS) {
    1175           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1176             :               "sss_ldb_modify_permissive failed: [%s](%d)[%s]\n",
    1177             :               ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb));
    1178             :     }
    1179             : 
    1180          35 :     ret = sysdb_error_to_errno(ret);
    1181          35 :     if (ret != EOK) {
    1182           0 :         goto done;
    1183             :     }
    1184             : 
    1185          35 :     talloc_zfree(msg);
    1186             : 
    1187             : 
    1188             : done:
    1189          35 :     talloc_free(tmp_ctx);
    1190          35 :     return ret;
    1191             : }
    1192             : 
    1193             : static errno_t
    1194         156 : sysdb_remove_ghostattr_from_groups(struct sss_domain_info *domain,
    1195             :                                    const char *orig_dn,
    1196             :                                    struct sysdb_attrs *attrs,
    1197             :                                    const char *name)
    1198             : {
    1199             :     TALLOC_CTX *tmp_ctx;
    1200             :     struct ldb_message **groups;
    1201             :     struct ldb_message_element *alias_el;
    1202             :     struct ldb_dn *tmpdn;
    1203         156 :     const char *group_attrs[] = {SYSDB_NAME, SYSDB_GHOST, SYSDB_ORIG_MEMBER, NULL};
    1204             :     const char *userdn;
    1205             :     char *sanitized_name;
    1206             :     char *filter;
    1207         156 :     errno_t ret = EOK;
    1208         156 :     size_t group_count = 0;
    1209             :     int i;
    1210             : 
    1211         156 :     tmp_ctx = talloc_new(NULL);
    1212         156 :     if (!tmp_ctx) {
    1213           0 :         return ENOENT;
    1214             :     }
    1215             : 
    1216         156 :     ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
    1217         156 :     if (ret != EOK) {
    1218           0 :         goto done;
    1219             :     }
    1220             : 
    1221         156 :     filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)",
    1222             :                                       SYSDB_GHOST, sanitized_name);
    1223         156 :     if (!filter) {
    1224           0 :         ret = ENOMEM;
    1225           0 :         goto done;
    1226             :     }
    1227         156 :     ret = sysdb_attrs_get_el(attrs, SYSDB_NAME_ALIAS, &alias_el);
    1228         156 :     if (ret != EOK) {
    1229           0 :         goto done;
    1230             :     }
    1231             : 
    1232         158 :     for (i = 0; i < alias_el->num_values; i++) {
    1233           2 :         if (strcmp((const char *)alias_el->values[i].data, name) == 0) {
    1234           0 :             continue;
    1235             :         }
    1236           2 :         filter = talloc_asprintf_append(filter, "(%s=%s)",
    1237           2 :                                         SYSDB_GHOST, alias_el->values[i].data);
    1238           2 :         if (filter == NULL) {
    1239           0 :             ret = ENOMEM;
    1240           0 :             goto done;
    1241             :         }
    1242             :     }
    1243             : 
    1244         156 :     filter = talloc_asprintf_append(filter, ")");
    1245         156 :     if (filter == NULL) {
    1246           0 :         ret = ENOMEM;
    1247           0 :         goto done;
    1248             :     }
    1249             : 
    1250         156 :     tmpdn = sysdb_user_dn(tmp_ctx, domain, name);
    1251         156 :     if (!tmpdn) {
    1252           0 :         ERROR_OUT(ret, ENOMEM, done);
    1253             :     }
    1254             : 
    1255         156 :     userdn = ldb_dn_get_linearized(tmpdn);
    1256         156 :     if (!userdn) {
    1257           0 :         ERROR_OUT(ret, EINVAL, done);
    1258             :     }
    1259             : 
    1260             :     /* To cover cross-domain group-membership we must search in all
    1261             :      * sub-domains. */
    1262         156 :     tmpdn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
    1263         156 :     if (!tmpdn) {
    1264           0 :         ret = ENOMEM;
    1265           0 :         goto done;
    1266             :     }
    1267             : 
    1268             :     /* We need to find all groups that contain this object as a ghost user
    1269             :      * and replace the ghost user by actual member record in direct parents.
    1270             :      * Note that this object can be referred to either by its name or any
    1271             :      * of its aliases
    1272             :      */
    1273         156 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, tmpdn, LDB_SCOPE_SUBTREE,
    1274             :                              filter, group_attrs, &group_count, &groups);
    1275         156 :     if (ret != EOK && ret != ENOENT) {
    1276           0 :         goto done;
    1277             :     }
    1278             : 
    1279         191 :     for (i = 0; i < group_count; i++) {
    1280          35 :         sysdb_remove_ghost_from_group(domain, groups[i], alias_el, name,
    1281             :                                       orig_dn, userdn);
    1282             :     }
    1283             : 
    1284         156 :     ret = EOK;
    1285             : 
    1286             : done:
    1287         156 :     talloc_free(tmp_ctx);
    1288         156 :     return ret;
    1289             : }
    1290             : 
    1291             : /* =Add-User-Function===================================================== */
    1292             : 
    1293         184 : int sysdb_add_user(struct sss_domain_info *domain,
    1294             :                    const char *name,
    1295             :                    uid_t uid, gid_t gid,
    1296             :                    const char *gecos,
    1297             :                    const char *homedir,
    1298             :                    const char *shell,
    1299             :                    const char *orig_dn,
    1300             :                    struct sysdb_attrs *attrs,
    1301             :                    int cache_timeout,
    1302             :                    time_t now)
    1303             : {
    1304             :     TALLOC_CTX *tmp_ctx;
    1305             :     struct ldb_message *msg;
    1306             :     struct sysdb_attrs *id_attrs;
    1307             :     uint32_t id;
    1308             :     int ret;
    1309             : 
    1310         184 :     if (domain->mpg) {
    1311          61 :         if (gid != 0) {
    1312           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
    1313             :                   "Cannot add user with arbitrary GID in MPG domain!\n");
    1314           0 :             return EINVAL;
    1315             :         }
    1316          61 :         gid = uid;
    1317             :     }
    1318             : 
    1319         190 :     if (domain->id_max != 0 && uid != 0 &&
    1320          12 :         (uid < domain->id_min || uid > domain->id_max)) {
    1321           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1322             :               "Supplied uid [%"SPRIuid"] is not in the allowed range "
    1323             :                "[%d-%d].\n", uid, domain->id_min, domain->id_max);
    1324           0 :         return ERANGE;
    1325             :     }
    1326             : 
    1327         186 :     if (domain->id_max != 0 && gid != 0 &&
    1328           4 :         (gid < domain->id_min || gid > domain->id_max)) {
    1329           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1330             :               "Supplied gid [%"SPRIgid"] is not in the allowed range "
    1331             :                "[%d-%d].\n", gid, domain->id_min, domain->id_max);
    1332           0 :         return ERANGE;
    1333             :     }
    1334             : 
    1335         184 :     tmp_ctx = talloc_new(NULL);
    1336         184 :     if (!tmp_ctx) {
    1337           0 :         return ENOMEM;
    1338             :     }
    1339             : 
    1340         184 :     ret = ldb_transaction_start(domain->sysdb->ldb);
    1341         184 :     if (ret) {
    1342           0 :         ret = sysdb_error_to_errno(ret);
    1343           0 :         talloc_free(tmp_ctx);
    1344           0 :         return ret;
    1345             :     }
    1346             : 
    1347         184 :     if (domain->mpg) {
    1348             :         /* In MPG domains you can't have groups with the same name as users,
    1349             :          * search if a group with the same name exists.
    1350             :          * Don't worry about users, if we try to add a user with the same
    1351             :          * name the operation will fail */
    1352             : 
    1353          61 :         ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg);
    1354          61 :         if (ret != ENOENT) {
    1355           0 :             if (ret == EOK) ret = EEXIST;
    1356           0 :             goto done;
    1357             :         }
    1358             :     }
    1359             : 
    1360             :     /* check no other user with the same uid exist */
    1361         184 :     if (uid != 0) {
    1362         171 :         ret = sysdb_search_user_by_uid(tmp_ctx, domain, uid, NULL, &msg);
    1363         171 :         if (ret != ENOENT) {
    1364           4 :             if (ret == EOK) ret = EEXIST;
    1365           4 :             goto done;
    1366             :         }
    1367             :     }
    1368             : 
    1369             :     /* try to add the user */
    1370         180 :     ret = sysdb_add_basic_user(domain, name, uid, gid, gecos, homedir, shell);
    1371         180 :     if (ret) goto done;
    1372             : 
    1373         180 :     if (uid == 0) {
    1374          13 :         ret = sysdb_get_new_id(domain, &id);
    1375          13 :         if (ret) goto done;
    1376             : 
    1377          13 :         id_attrs = sysdb_new_attrs(tmp_ctx);
    1378          13 :         if (!id_attrs) {
    1379           0 :             ret = ENOMEM;
    1380           0 :             goto done;
    1381             :         }
    1382          13 :         ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_UIDNUM, id);
    1383          13 :         if (ret) goto done;
    1384             : 
    1385          13 :         if (domain->mpg) {
    1386          13 :             ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id);
    1387          13 :             if (ret) goto done;
    1388             :         }
    1389             : 
    1390          13 :         ret = sysdb_set_user_attr(domain, name, id_attrs, SYSDB_MOD_REP);
    1391             :         /* continue on success, to commit additional attrs */
    1392          13 :         if (ret) goto done;
    1393             :     }
    1394             : 
    1395         180 :     if (!attrs) {
    1396          87 :         attrs = sysdb_new_attrs(tmp_ctx);
    1397          87 :         if (!attrs) {
    1398           0 :             ret = ENOMEM;
    1399           0 :             goto done;
    1400             :         }
    1401             :     }
    1402             : 
    1403         180 :     if (!now) {
    1404          98 :         now = time(NULL);
    1405             :     }
    1406             : 
    1407         180 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    1408         180 :     if (ret) goto done;
    1409             : 
    1410         341 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    1411             :                                  ((cache_timeout) ?
    1412         161 :                                   (now + cache_timeout) : 0));
    1413         180 :     if (ret) goto done;
    1414             : 
    1415         180 :     ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
    1416         180 :     if (ret) goto done;
    1417             : 
    1418         180 :     if (domain->enumerate == false) {
    1419             :         /* If we're not enumerating, previous getgr{nam,gid} calls might
    1420             :          * have stored ghost users into the cache, so we need to link them
    1421             :          * with the newly-created user entry
    1422             :          */
    1423         156 :         ret = sysdb_remove_ghostattr_from_groups(domain, orig_dn, attrs,
    1424             :                                                  name);
    1425         156 :         if (ret) goto done;
    1426             :     }
    1427             : 
    1428         180 :     ret = EOK;
    1429             : 
    1430             : done:
    1431         184 :     if (ret == EOK) {
    1432         180 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    1433         180 :         ret = sysdb_error_to_errno(ret);
    1434             :     } else {
    1435           4 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1436           4 :         ldb_transaction_cancel(domain->sysdb->ldb);
    1437             :     }
    1438         184 :     talloc_zfree(tmp_ctx);
    1439         184 :     return ret;
    1440             : }
    1441             : 
    1442             : /* =Add-Basic-Group-NO-CHECKS============================================= */
    1443             : 
    1444         170 : int sysdb_add_basic_group(struct sss_domain_info *domain,
    1445             :                           const char *name, gid_t gid)
    1446             : {
    1447             :     struct ldb_message *msg;
    1448             :     int ret;
    1449             :     TALLOC_CTX *tmp_ctx;
    1450             : 
    1451         170 :     tmp_ctx = talloc_new(NULL);
    1452         170 :     if (!tmp_ctx) {
    1453           0 :         return ENOMEM;
    1454             :     }
    1455             : 
    1456         170 :     msg = ldb_msg_new(tmp_ctx);
    1457         170 :     if (!msg) {
    1458           0 :         ret = ENOMEM;
    1459           0 :         goto done;
    1460             :     }
    1461             : 
    1462             :     /* group dn */
    1463         170 :     msg->dn = sysdb_group_dn(msg, domain, name);
    1464         170 :     if (!msg->dn) {
    1465           0 :         ERROR_OUT(ret, ENOMEM, done);
    1466             :     }
    1467             : 
    1468         170 :     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS);
    1469         170 :     if (ret) goto done;
    1470             : 
    1471         170 :     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
    1472         170 :     if (ret) goto done;
    1473             : 
    1474         170 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid);
    1475         170 :     if (ret) goto done;
    1476             : 
    1477             :     /* creation time */
    1478         170 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
    1479         170 :                     (unsigned long)time(NULL));
    1480         170 :     if (ret) goto done;
    1481             : 
    1482         170 :     ret = ldb_add(domain->sysdb->ldb, msg);
    1483         170 :     ret = sysdb_error_to_errno(ret);
    1484             : 
    1485             : done:
    1486         170 :     if (ret) {
    1487           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1488             :     }
    1489         170 :     talloc_zfree(tmp_ctx);
    1490         170 :     return ret;
    1491             : }
    1492             : 
    1493             : 
    1494             : /* =Add-Group-Function==================================================== */
    1495             : 
    1496         157 : int sysdb_add_group(struct sss_domain_info *domain,
    1497             :                     const char *name, gid_t gid,
    1498             :                     struct sysdb_attrs *attrs,
    1499             :                     int cache_timeout,
    1500             :                     time_t now)
    1501             : {
    1502             :     TALLOC_CTX *tmp_ctx;
    1503             :     struct ldb_message *msg;
    1504             :     uint32_t id;
    1505             :     int ret;
    1506             :     bool posix;
    1507             : 
    1508         159 :     if (domain->id_max != 0 && gid != 0 &&
    1509           4 :         (gid < domain->id_min || gid > domain->id_max)) {
    1510           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1511             :               "Supplied gid [%"SPRIgid"] is not in the allowed range "
    1512             :                "[%d-%d].\n", gid, domain->id_min, domain->id_max);
    1513           0 :         return ERANGE;
    1514             :     }
    1515             : 
    1516         157 :     tmp_ctx = talloc_new(NULL);
    1517         157 :     if (!tmp_ctx) {
    1518           0 :         return ENOMEM;
    1519             :     }
    1520             : 
    1521         157 :     ret = ldb_transaction_start(domain->sysdb->ldb);
    1522         157 :     if (ret) {
    1523           0 :         ret = sysdb_error_to_errno(ret);
    1524           0 :         talloc_free(tmp_ctx);
    1525           0 :         return ret;
    1526             :     }
    1527             : 
    1528         157 :     if (domain->mpg) {
    1529             :         /* In MPG domains you can't have groups with the same name as users,
    1530             :          * search if a group with the same name exists.
    1531             :          * Don't worry about users, if we try to add a user with the same
    1532             :          * name the operation will fail */
    1533             : 
    1534         116 :         ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
    1535         116 :         if (ret != ENOENT) {
    1536           0 :             if (ret == EOK) {
    1537           0 :                 DEBUG(SSSDBG_TRACE_LIBS, "MPG domain contains a user "
    1538             :                       "with the same name - %s.\n", name);
    1539           0 :                 ret = EEXIST;
    1540             :             } else {
    1541           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
    1542             :                       "sysdb_search_user_by_name failed for user %s.\n", name);
    1543             :             }
    1544           0 :             goto done;
    1545             :         }
    1546             :     }
    1547             : 
    1548             :     /* check no other groups with the same gid exist */
    1549         157 :     if (gid != 0) {
    1550         145 :         ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, NULL, &msg);
    1551         145 :         if (ret != ENOENT) {
    1552           2 :             if (ret == EOK) {
    1553           2 :                 DEBUG(SSSDBG_TRACE_LIBS,
    1554             :                       "Group with the same gid exists: [%"SPRIgid"].\n", gid);
    1555           2 :                 ret = EEXIST;
    1556             :             } else {
    1557           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
    1558             :                       "sysdb_search_group_by_gid failed for gid: "
    1559             :                       "[%"SPRIgid"].\n", gid);
    1560             :             }
    1561           2 :             goto done;
    1562             :         }
    1563             :     }
    1564             : 
    1565             :     /* try to add the group */
    1566         155 :     ret = sysdb_add_basic_group(domain, name, gid);
    1567         155 :     if (ret) {
    1568           0 :         DEBUG(SSSDBG_TRACE_LIBS,
    1569             :               "sysdb_add_basic_group failed for: %s with gid: "
    1570             :               "[%"SPRIgid"].\n", name, gid);
    1571           0 :         goto done;
    1572             :     }
    1573             : 
    1574         155 :     if (!attrs) {
    1575          34 :         attrs = sysdb_new_attrs(tmp_ctx);
    1576          34 :         if (!attrs) {
    1577           0 :             DEBUG(SSSDBG_TRACE_LIBS, "sysdb_new_attrs failed.\n");
    1578           0 :             ret = ENOMEM;
    1579           0 :             goto done;
    1580             :         }
    1581             :     }
    1582             : 
    1583         155 :     ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix);
    1584         155 :     if (ret == ENOENT) {
    1585         155 :         posix = true;
    1586         155 :         ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, true);
    1587         155 :         if (ret) {
    1588           0 :             DEBUG(SSSDBG_TRACE_LIBS, "Failed to add posix attribute.\n");
    1589           0 :             goto done;
    1590             :         }
    1591           0 :     } else if (ret != EOK) {
    1592           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Failed to get posix attribute.\n");
    1593           0 :         goto done;
    1594             :     }
    1595             : 
    1596         155 :     if (posix && gid == 0) {
    1597          12 :         ret = sysdb_get_new_id(domain, &id);
    1598          12 :         if (ret) {
    1599           0 :             DEBUG(SSSDBG_TRACE_LIBS, "sysdb_get_new_id failed.\n");
    1600           0 :             goto done;
    1601             :         }
    1602             : 
    1603          12 :         ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, id);
    1604          12 :         if (ret) {
    1605           0 :             DEBUG(SSSDBG_TRACE_LIBS, "Failed to add new gid.\n");
    1606           0 :             goto done;
    1607             :         }
    1608             :     }
    1609             : 
    1610         155 :     if (!now) {
    1611          34 :         now = time(NULL);
    1612             :     }
    1613             : 
    1614         155 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    1615         155 :     if (ret) {
    1616           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-last-update.\n");
    1617           0 :         goto done;
    1618             :     }
    1619             : 
    1620         286 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    1621             :                                  ((cache_timeout) ?
    1622         131 :                                   (now + cache_timeout) : 0));
    1623         155 :     if (ret) {
    1624           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-cache-expire.\n");
    1625           0 :         goto done;
    1626             :     }
    1627             : 
    1628         155 :     ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
    1629         155 :     if (ret) {
    1630           0 :         DEBUG(SSSDBG_TRACE_LIBS, "sysdb_set_group_attr failed.\n");
    1631           0 :         goto done;
    1632             :     }
    1633             : 
    1634             : done:
    1635         157 :     if (ret == EOK) {
    1636         155 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    1637         155 :         ret = sysdb_error_to_errno(ret);
    1638             :     } else {
    1639           2 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1640           2 :         ldb_transaction_cancel(domain->sysdb->ldb);
    1641             :     }
    1642         157 :     talloc_zfree(tmp_ctx);
    1643         157 :     return ret;
    1644             : }
    1645             : 
    1646          15 : int sysdb_add_incomplete_group(struct sss_domain_info *domain,
    1647             :                                const char *name,
    1648             :                                gid_t gid,
    1649             :                                const char *original_dn,
    1650             :                                const char *sid_str,
    1651             :                                const char *uuid,
    1652             :                                bool posix,
    1653             :                                time_t now)
    1654             : {
    1655             :     TALLOC_CTX *tmp_ctx;
    1656             :     int ret;
    1657             :     struct sysdb_attrs *attrs;
    1658             : 
    1659          15 :     tmp_ctx = talloc_new(NULL);
    1660          15 :     if (!tmp_ctx) {
    1661           0 :         return ENOMEM;
    1662             :     }
    1663             : 
    1664             :     /* try to add the group */
    1665          15 :     ret = sysdb_add_basic_group(domain, name, gid);
    1666          15 :     if (ret) goto done;
    1667             : 
    1668          15 :     attrs = sysdb_new_attrs(tmp_ctx);
    1669          15 :     if (!attrs) {
    1670           0 :         ret = ENOMEM;
    1671           0 :         goto done;
    1672             :     }
    1673             : 
    1674          15 :     if (!now) {
    1675          15 :         now = time(NULL);
    1676             :     }
    1677             : 
    1678          15 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    1679          15 :     if (ret) goto done;
    1680             : 
    1681          15 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    1682             :                                  now-1);
    1683          15 :     if (ret) goto done;
    1684             : 
    1685          15 :     ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, posix);
    1686          15 :     if (ret) goto done;
    1687             : 
    1688          15 :     if (original_dn) {
    1689           3 :         ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, original_dn);
    1690           3 :         if (ret) goto done;
    1691             :     }
    1692             : 
    1693          15 :     if (sid_str) {
    1694           1 :         ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, sid_str);
    1695           1 :         if (ret) goto done;
    1696             :     }
    1697             : 
    1698          15 :     if (uuid) {
    1699           0 :         ret = sysdb_attrs_add_string(attrs, SYSDB_UUID, uuid);
    1700           0 :         if (ret) goto done;
    1701             :     }
    1702             : 
    1703          15 :     ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
    1704             : 
    1705             : done:
    1706          15 :     if (ret != EOK) {
    1707           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1708             :     }
    1709          15 :     talloc_zfree(tmp_ctx);
    1710          15 :     return ret;
    1711             : }
    1712             : 
    1713             : /* =Add-Or-Remove-Group-Memeber=========================================== */
    1714             : 
    1715             : /* mod_op must be either SYSDB_MOD_ADD or SYSDB_MOD_DEL */
    1716          78 : int sysdb_mod_group_member(struct sss_domain_info *domain,
    1717             :                            struct ldb_dn *member_dn,
    1718             :                            struct ldb_dn *group_dn,
    1719             :                            int mod_op)
    1720             : {
    1721             :     struct ldb_message *msg;
    1722             :     const char *dn;
    1723             :     int ret;
    1724             : 
    1725          78 :     msg = ldb_msg_new(NULL);
    1726          78 :     if (!msg) {
    1727           0 :         ERROR_OUT(ret, ENOMEM, fail);
    1728             :     }
    1729             : 
    1730          78 :     msg->dn = group_dn;
    1731          78 :     ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, mod_op, NULL);
    1732          78 :     if (ret != LDB_SUCCESS) {
    1733           0 :         ERROR_OUT(ret, ENOMEM, fail);
    1734             :     }
    1735             : 
    1736          78 :     dn = ldb_dn_get_linearized(member_dn);
    1737          78 :     if (!dn) {
    1738           0 :         ERROR_OUT(ret, EINVAL, fail);
    1739             :     }
    1740             : 
    1741          78 :     ret = ldb_msg_add_string(msg, SYSDB_MEMBER, dn);
    1742          78 :     if (ret != LDB_SUCCESS) {
    1743           0 :         ERROR_OUT(ret, EINVAL, fail);
    1744             :     }
    1745             : 
    1746          78 :     ret = ldb_modify(domain->sysdb->ldb, msg);
    1747          78 :     if (ret != LDB_SUCCESS) {
    1748           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1749             :               "ldb_modify failed: [%s](%d)[%s]\n",
    1750             :               ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
    1751             :     }
    1752          78 :     ret = sysdb_error_to_errno(ret);
    1753             : 
    1754             : fail:
    1755          78 :     if (ret) {
    1756           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1757             :     }
    1758          78 :     talloc_zfree(msg);
    1759          78 :     return ret;
    1760             : }
    1761             : 
    1762             : /* =Add-Basic-Netgroup-NO-CHECKS============================================= */
    1763             : 
    1764          11 : int sysdb_add_basic_netgroup(struct sss_domain_info *domain,
    1765             :                              const char *name, const char *description)
    1766             : {
    1767             :     struct ldb_message *msg;
    1768             :     int ret;
    1769             : 
    1770          11 :     msg = ldb_msg_new(NULL);
    1771          11 :     if (!msg) {
    1772           0 :         return ENOMEM;
    1773             :     }
    1774             : 
    1775             :     /* netgroup dn */
    1776          11 :     msg->dn = sysdb_netgroup_dn(msg, domain, name);
    1777          11 :     if (!msg->dn) {
    1778           0 :         ERROR_OUT(ret, ENOMEM, done);
    1779             :     }
    1780             : 
    1781          11 :     ret = add_string(msg, LDB_FLAG_MOD_ADD,
    1782             :                      SYSDB_OBJECTCLASS, SYSDB_NETGROUP_CLASS);
    1783          11 :     if (ret) goto done;
    1784             : 
    1785          11 :     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name);
    1786          11 :     if (ret) goto done;
    1787             : 
    1788          11 :     if (description && *description) {
    1789          11 :         ret = add_string(msg, LDB_FLAG_MOD_ADD,
    1790             :                          SYSDB_DESCRIPTION, description);
    1791          11 :         if (ret) goto done;
    1792             :     }
    1793             : 
    1794             :     /* creation time */
    1795          11 :     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,
    1796          11 :                     (unsigned long) time(NULL));
    1797          11 :     if (ret) goto done;
    1798             : 
    1799          11 :     ret = ldb_add(domain->sysdb->ldb, msg);
    1800          11 :     ret = sysdb_error_to_errno(ret);
    1801             : 
    1802             : done:
    1803          11 :     if (ret) {
    1804           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1805             :     }
    1806          11 :     talloc_zfree(msg);
    1807          11 :     return ret;
    1808             : }
    1809             : 
    1810             : 
    1811             : /* =Add-Netgroup-Function==================================================== */
    1812             : 
    1813           1 : int sysdb_add_netgroup(struct sss_domain_info *domain,
    1814             :                        const char *name,
    1815             :                        const char *description,
    1816             :                        struct sysdb_attrs *attrs,
    1817             :                        char **missing,
    1818             :                        int cache_timeout,
    1819             :                        time_t now)
    1820             : {
    1821             :     TALLOC_CTX *tmp_ctx;
    1822             :     int ret;
    1823             : 
    1824           1 :     tmp_ctx = talloc_new(NULL);
    1825           1 :     if (!tmp_ctx) {
    1826           0 :         return ENOMEM;
    1827             :     }
    1828             : 
    1829           1 :     ret = ldb_transaction_start(domain->sysdb->ldb);
    1830           1 :     if (ret) {
    1831           0 :         ret = sysdb_error_to_errno(ret);
    1832           0 :         talloc_free(tmp_ctx);
    1833           0 :         return ret;
    1834             :     }
    1835             : 
    1836             :     /* try to add the netgroup */
    1837           1 :     ret = sysdb_add_basic_netgroup(domain, name, description);
    1838           1 :     if (ret && ret != EEXIST) goto done;
    1839             : 
    1840           1 :     if (!attrs) {
    1841           1 :         attrs = sysdb_new_attrs(tmp_ctx);
    1842           1 :         if (!attrs) {
    1843           0 :             ret = ENOMEM;
    1844           0 :             goto done;
    1845             :         }
    1846             :     }
    1847             : 
    1848           1 :     if (!now) {
    1849           1 :         now = time(NULL);
    1850             :     }
    1851             : 
    1852           1 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    1853           1 :     if (ret) goto done;
    1854             : 
    1855           2 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    1856             :                                  ((cache_timeout) ?
    1857           1 :                                   (now + cache_timeout) : 0));
    1858           1 :     if (ret) goto done;
    1859             : 
    1860           1 :     ret = sysdb_set_netgroup_attr(domain, name, attrs, SYSDB_MOD_REP);
    1861             : 
    1862           1 :     if (missing) {
    1863           0 :         ret = sysdb_remove_attrs(domain, name,
    1864             :                                  SYSDB_MEMBER_NETGROUP,
    1865             :                                  missing);
    1866           0 :         if (ret != EOK) {
    1867           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove missing attributes\n");
    1868             :         }
    1869             :     }
    1870             : 
    1871             : done:
    1872           1 :     if (ret == EOK) {
    1873           1 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    1874           1 :         ret = sysdb_error_to_errno(ret);
    1875             :     }
    1876             : 
    1877           1 :     if (ret != EOK) {
    1878           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    1879           0 :         ldb_transaction_cancel(domain->sysdb->ldb);
    1880             :     }
    1881           1 :     talloc_zfree(tmp_ctx);
    1882           1 :     return ret;
    1883             : }
    1884             : 
    1885             : /* =Store-Users-(Native/Legacy)-(replaces-existing-data)================== */
    1886             : 
    1887             : /* if one of the basic attributes is empty ("") as opposed to NULL,
    1888             :  * this will just remove it */
    1889             : 
    1890         104 : int sysdb_store_user(struct sss_domain_info *domain,
    1891             :                      const char *name,
    1892             :                      const char *pwd,
    1893             :                      uid_t uid, gid_t gid,
    1894             :                      const char *gecos,
    1895             :                      const char *homedir,
    1896             :                      const char *shell,
    1897             :                      const char *orig_dn,
    1898             :                      struct sysdb_attrs *attrs,
    1899             :                      char **remove_attrs,
    1900             :                      uint64_t cache_timeout,
    1901             :                      time_t now)
    1902             : {
    1903             :     TALLOC_CTX *tmp_ctx;
    1904             :     struct ldb_message *msg;
    1905             :     int ret;
    1906         104 :     errno_t sret = EOK;
    1907         104 :     bool in_transaction = false;
    1908             : 
    1909         104 :     tmp_ctx = talloc_new(NULL);
    1910         104 :     if (!tmp_ctx) {
    1911           0 :         return ENOMEM;
    1912             :     }
    1913             : 
    1914         104 :     if (!attrs) {
    1915          83 :         attrs = sysdb_new_attrs(tmp_ctx);
    1916          83 :         if (!attrs) {
    1917           0 :             ret = ENOMEM;
    1918           0 :             goto fail;
    1919             :         }
    1920             :     }
    1921             : 
    1922         104 :     if (pwd && (domain->legacy_passwords || !*pwd)) {
    1923           0 :         ret = sysdb_attrs_add_string(attrs, SYSDB_PWD, pwd);
    1924           0 :         if (ret) goto fail;
    1925             :     }
    1926             : 
    1927         104 :     ret = sysdb_transaction_start(domain->sysdb);
    1928         104 :     if (ret != EOK) {
    1929           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    1930           0 :         goto fail;
    1931             :     }
    1932             : 
    1933         104 :     in_transaction = true;
    1934             : 
    1935         104 :     ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
    1936         104 :     if (ret && ret != ENOENT) {
    1937           0 :         goto fail;
    1938             :     }
    1939             : 
    1940             :     /* get transaction timestamp */
    1941         104 :     if (!now) {
    1942          73 :         now = time(NULL);
    1943             :     }
    1944             : 
    1945         104 :     if (ret == ENOENT) {
    1946             :         /* users doesn't exist, turn into adding a user */
    1947          79 :         ret = sysdb_add_user(domain, name, uid, gid, gecos, homedir,
    1948             :                              shell, orig_dn, attrs, cache_timeout, now);
    1949          79 :         if (ret == EEXIST) {
    1950             :             /* This may be a user rename. If there is a user with the
    1951             :              * same UID, remove it and try to add the basic user again
    1952             :              */
    1953           3 :             ret = sysdb_delete_user(domain, NULL, uid);
    1954           3 :             if (ret == ENOENT) {
    1955             :                 /* Not found by UID, return the original EEXIST,
    1956             :                  * this may be a conflict in MPG domain or something
    1957             :                  * else */
    1958           0 :                 ret = EEXIST;
    1959           0 :                 goto fail;
    1960           3 :             } else if (ret != EOK) {
    1961           0 :                 goto fail;
    1962             :             }
    1963           3 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1964             :                   "A user with the same UID [%llu] was removed from the "
    1965             :                    "cache\n", (unsigned long long) uid);
    1966           3 :             ret = sysdb_add_user(domain, name, uid, gid, gecos, homedir,
    1967             :                                  shell, orig_dn, attrs, cache_timeout, now);
    1968             :         }
    1969             : 
    1970             :         /* Handle the result of sysdb_add_user */
    1971          79 :         if (ret == EOK) {
    1972          79 :             goto done;
    1973             :         } else {
    1974           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add user\n");
    1975           0 :             goto fail;
    1976             :         }
    1977             :     }
    1978             : 
    1979             :     /* the user exists, let's just replace attributes when set */
    1980          25 :     if (uid) {
    1981          25 :         ret = sysdb_attrs_add_uint32(attrs, SYSDB_UIDNUM, uid);
    1982          25 :         if (ret) goto fail;
    1983             :     }
    1984             : 
    1985          25 :     if (gid) {
    1986           5 :         ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
    1987           5 :         if (ret) goto fail;
    1988             :     }
    1989             : 
    1990          25 :     if (uid && !gid && domain->mpg) {
    1991          20 :         ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, uid);
    1992          20 :         if (ret) goto fail;
    1993             :     }
    1994             : 
    1995          25 :     if (gecos) {
    1996          25 :         ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, gecos);
    1997          25 :         if (ret) goto fail;
    1998             :     }
    1999             : 
    2000          25 :     if (homedir) {
    2001          25 :         ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, homedir);
    2002          25 :         if (ret) goto fail;
    2003             :     }
    2004             : 
    2005          25 :     if (shell) {
    2006          25 :         ret = sysdb_attrs_add_string(attrs, SYSDB_SHELL, shell);
    2007          25 :         if (ret) goto fail;
    2008             :     }
    2009             : 
    2010          25 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    2011          25 :     if (ret) goto fail;
    2012             : 
    2013          49 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    2014             :                                  ((cache_timeout) ?
    2015          24 :                                   (now + cache_timeout) : 0));
    2016          25 :     if (ret) goto fail;
    2017             : 
    2018          25 :     ret = sysdb_set_user_attr(domain, name, attrs, SYSDB_MOD_REP);
    2019          25 :     if (ret != EOK) goto fail;
    2020             : 
    2021          25 :     if (remove_attrs) {
    2022           0 :         ret = sysdb_remove_attrs(domain, name,
    2023             :                                  SYSDB_MEMBER_USER,
    2024             :                                  remove_attrs);
    2025           0 :         if (ret != EOK) {
    2026           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    2027             :                   "Could not remove missing attributes\n");
    2028             :         }
    2029             :     }
    2030             : 
    2031             : done:
    2032         104 :     ret = sysdb_transaction_commit(domain->sysdb);
    2033         104 :     if (ret != EOK) {
    2034           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
    2035           0 :         goto fail;
    2036             :     }
    2037             : 
    2038         104 :     in_transaction = false;
    2039             : 
    2040             : fail:
    2041         104 :     if (in_transaction) {
    2042           0 :         sret = sysdb_transaction_cancel(domain->sysdb);
    2043           0 :         if (sret != EOK) {
    2044           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
    2045             :         }
    2046             :     }
    2047             : 
    2048         104 :     if (ret) {
    2049           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2050             :     }
    2051         104 :     talloc_zfree(tmp_ctx);
    2052         104 :     return ret;
    2053             : }
    2054             : 
    2055             : /* =Store-Group-(Native/Legacy)-(replaces-existing-data)================== */
    2056             : 
    2057             : /* this function does not check that all user members are actually present */
    2058             : 
    2059         122 : int sysdb_store_group(struct sss_domain_info *domain,
    2060             :                       const char *name,
    2061             :                       gid_t gid,
    2062             :                       struct sysdb_attrs *attrs,
    2063             :                       uint64_t cache_timeout,
    2064             :                       time_t now)
    2065             : {
    2066             :     TALLOC_CTX *tmp_ctx;
    2067             :     static const char *src_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM,
    2068             :                                        SYSDB_ORIG_MODSTAMP, NULL };
    2069             :     struct ldb_message *msg;
    2070         122 :     bool new_group = false;
    2071             :     int ret;
    2072             : 
    2073         122 :     tmp_ctx = talloc_new(NULL);
    2074         122 :     if (!tmp_ctx) {
    2075           0 :         return ENOMEM;
    2076             :     }
    2077             : 
    2078         122 :     ret = sysdb_search_group_by_name(tmp_ctx, domain, name, src_attrs, &msg);
    2079         122 :     if (ret && ret != ENOENT) {
    2080           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2081             :               "sysdb_search_group_by_name failed for %s with: [%d][%s].\n",
    2082             :               name, ret, strerror(ret));
    2083           0 :         goto done;
    2084             :     }
    2085         122 :     if (ret == ENOENT) {
    2086         121 :         DEBUG(SSSDBG_TRACE_LIBS, "Group %s does not exist.\n", name);
    2087         121 :         new_group = true;
    2088             :     }
    2089             : 
    2090         122 :     if (!attrs) {
    2091          40 :         attrs = sysdb_new_attrs(tmp_ctx);
    2092          40 :         if (!attrs) {
    2093           0 :             ret = ENOMEM;
    2094           0 :             goto done;
    2095             :         }
    2096             :     }
    2097             : 
    2098             :     /* get transaction timestamp */
    2099         122 :     if (!now) {
    2100          98 :         now = time(NULL);
    2101             :     }
    2102             : 
    2103             :     /* FIXME: use the remote modification timestamp to know if the
    2104             :      * group needs any update */
    2105             : 
    2106         122 :     if (new_group) {
    2107             :         /* group doesn't exist, turn into adding a group */
    2108         121 :         ret = sysdb_add_group(domain, name, gid, attrs, cache_timeout,
    2109             :                               now);
    2110         121 :         if (ret == EEXIST) {
    2111             :             /* This may be a group rename. If there is a group with the
    2112             :              * same GID, remove it and try to add the basic group again
    2113             :              */
    2114           1 :             DEBUG(SSSDBG_TRACE_LIBS, "sysdb_add_group failed: [EEXIST].\n");
    2115           1 :             ret = sysdb_delete_group(domain, NULL, gid);
    2116           1 :             if (ret == ENOENT) {
    2117             :                 /* Not found by GID, return the original EEXIST,
    2118             :                  * this may be a conflict in MPG domain or something
    2119             :                  * else */
    2120           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
    2121             :                       "sysdb_delete_group failed (while renaming group). Not "
    2122             :                       "found by gid: [%"SPRIgid"].\n", gid);
    2123           0 :                 return EEXIST;
    2124           1 :             } else if (ret != EOK) {
    2125           0 :                 DEBUG(SSSDBG_TRACE_LIBS, "sysdb_add_group failed.\n");
    2126           0 :                 goto done;
    2127             :             }
    2128           1 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2129             :                   "A group with the same GID [%"SPRIgid"] was removed from "
    2130             :                   "the cache\n", gid);
    2131           1 :             ret = sysdb_add_group(domain, name, gid, attrs, cache_timeout,
    2132             :                                   now);
    2133           1 :             if (ret) {
    2134           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    2135             :                       "sysdb_add_group failed (while renaming group) for: "
    2136             :                       "%s [%"SPRIgid"].\n", name, gid);
    2137             :             }
    2138             :         }
    2139         121 :         goto done;
    2140             :     }
    2141             : 
    2142             :     /* the group exists, let's just replace attributes when set */
    2143           1 :     if (gid) {
    2144           1 :         ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
    2145           1 :         if (ret) {
    2146           0 :             DEBUG(SSSDBG_TRACE_LIBS, "Failed to add GID.\n");
    2147           0 :             goto done;
    2148             :         }
    2149             :     }
    2150             : 
    2151           1 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
    2152           1 :     if (ret) {
    2153           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-last-update.\n");
    2154           0 :         goto done;
    2155             :     }
    2156             : 
    2157           2 :     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
    2158             :                                  ((cache_timeout) ?
    2159           1 :                                   (now + cache_timeout) : 0));
    2160           1 :     if (ret) {
    2161           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Failed to add sysdb-cache-expire.\n");
    2162           0 :         goto done;
    2163             :     }
    2164             : 
    2165           1 :     ret = sysdb_set_group_attr(domain, name, attrs, SYSDB_MOD_REP);
    2166           1 :     if (ret) {
    2167           0 :         DEBUG(SSSDBG_TRACE_LIBS, "sysdb_set_group_attr failed.\n");
    2168           0 :         goto done;
    2169             :     }
    2170             : 
    2171             : done:
    2172         122 :     if (ret) {
    2173           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2174             :     }
    2175         122 :     talloc_zfree(tmp_ctx);
    2176         122 :     return ret;
    2177             : }
    2178             : 
    2179             : 
    2180             : /* =Add-User-to-Group(Native/Legacy)====================================== */
    2181             : static int
    2182          78 : sysdb_group_membership_mod(struct sss_domain_info *domain,
    2183             :                            const char *group,
    2184             :                            const char *member,
    2185             :                            enum sysdb_member_type type,
    2186             :                            int modify_op,
    2187             :                            bool is_dn)
    2188             : {
    2189             :     struct ldb_dn *group_dn;
    2190             :     struct ldb_dn *member_dn;
    2191             :     int ret;
    2192          78 :     TALLOC_CTX *tmp_ctx = talloc_new(NULL);
    2193          78 :     if (!tmp_ctx) {
    2194           0 :         return ENOMEM;
    2195             :     }
    2196             : 
    2197          78 :     if (type == SYSDB_MEMBER_USER) {
    2198          78 :         member_dn = sysdb_user_dn(tmp_ctx, domain, member);
    2199           0 :     } else if (type == SYSDB_MEMBER_GROUP) {
    2200           0 :         member_dn = sysdb_group_dn(tmp_ctx, domain, member);
    2201             :     } else {
    2202           0 :         ret = EINVAL;
    2203           0 :         goto done;
    2204             :     }
    2205             : 
    2206          78 :     if (!member_dn) {
    2207           0 :         ret = ENOMEM;
    2208           0 :         goto done;
    2209             :     }
    2210             : 
    2211          78 :     if (!is_dn) {
    2212          76 :         group_dn = sysdb_group_dn(tmp_ctx, domain, group);
    2213             :     } else {
    2214           2 :         group_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, group);
    2215             :     }
    2216             : 
    2217          78 :     if (!group_dn) {
    2218           0 :         ret = ENOMEM;
    2219           0 :         goto done;
    2220             :     }
    2221             : 
    2222          78 :     ret = sysdb_mod_group_member(domain, member_dn, group_dn, modify_op);
    2223             : 
    2224             : done:
    2225          78 :     talloc_free(tmp_ctx);
    2226          78 :     return ret;
    2227             : }
    2228             : 
    2229          65 : int sysdb_add_group_member(struct sss_domain_info *domain,
    2230             :                            const char *group,
    2231             :                            const char *member,
    2232             :                            enum sysdb_member_type type,
    2233             :                            bool is_dn)
    2234             : {
    2235          65 :     return sysdb_group_membership_mod(domain, group, member, type,
    2236             :                                       SYSDB_MOD_ADD, is_dn);
    2237             : }
    2238             : 
    2239             : /* =Remove-member-from-Group(Native/Legacy)=============================== */
    2240             : 
    2241             : 
    2242          13 : int sysdb_remove_group_member(struct sss_domain_info *domain,
    2243             :                               const char *group,
    2244             :                               const char *member,
    2245             :                               enum sysdb_member_type type,
    2246             :                               bool is_dn)
    2247             : {
    2248          13 :     return sysdb_group_membership_mod(domain, group, member, type,
    2249             :                                       SYSDB_MOD_DEL, is_dn);
    2250             : }
    2251             : 
    2252             : 
    2253             : /* =Password-Caching====================================================== */
    2254             : 
    2255          13 : int sysdb_cache_password_ex(struct sss_domain_info *domain,
    2256             :                             const char *username,
    2257             :                             const char *password,
    2258             :                             enum sss_authtok_type authtok_type,
    2259             :                             size_t second_factor_len)
    2260             : {
    2261             :     TALLOC_CTX *tmp_ctx;
    2262             :     struct sysdb_attrs *attrs;
    2263          13 :     char *hash = NULL;
    2264             :     char *salt;
    2265             :     int ret;
    2266             : 
    2267          13 :     tmp_ctx = talloc_new(NULL);
    2268          13 :     if (!tmp_ctx) {
    2269           0 :         return ENOMEM;
    2270             :     }
    2271             : 
    2272          13 :     ret = s3crypt_gen_salt(tmp_ctx, &salt);
    2273          13 :     if (ret) {
    2274           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Failed to generate random salt.\n");
    2275           0 :         goto fail;
    2276             :     }
    2277             : 
    2278          13 :     ret = s3crypt_sha512(tmp_ctx, password, salt, &hash);
    2279          13 :     if (ret) {
    2280           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
    2281           0 :         goto fail;
    2282             :     }
    2283             : 
    2284          13 :     attrs = sysdb_new_attrs(tmp_ctx);
    2285          13 :     if (!attrs) {
    2286           0 :         ERROR_OUT(ret, ENOMEM, fail);
    2287             :     }
    2288             : 
    2289          13 :     ret = sysdb_attrs_add_string(attrs, SYSDB_CACHEDPWD, hash);
    2290          13 :     if (ret) goto fail;
    2291             : 
    2292          13 :     ret = sysdb_attrs_add_long(attrs, SYSDB_CACHEDPWD_TYPE, authtok_type);
    2293          13 :     if (ret) goto fail;
    2294             : 
    2295          13 :     if (authtok_type == SSS_AUTHTOK_TYPE_2FA && second_factor_len > 0) {
    2296           8 :         ret = sysdb_attrs_add_long(attrs, SYSDB_CACHEDPWD_FA2_LEN,
    2297             :                                    second_factor_len);
    2298           8 :         if (ret) goto fail;
    2299             :     }
    2300             : 
    2301             :     /* FIXME: should we use a different attribute for chache passwords ?? */
    2302          13 :     ret = sysdb_attrs_add_long(attrs, "lastCachedPasswordChange",
    2303          13 :                                (long)time(NULL));
    2304          13 :     if (ret) goto fail;
    2305             : 
    2306          13 :     ret = sysdb_attrs_add_uint32(attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0U);
    2307          13 :     if (ret) goto fail;
    2308             : 
    2309             : 
    2310          13 :     ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
    2311          13 :     if (ret) {
    2312           0 :         goto fail;
    2313             :     }
    2314          13 :     talloc_zfree(tmp_ctx);
    2315          13 :     return EOK;
    2316             : 
    2317             : fail:
    2318           0 :     if (ret) {
    2319           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2320             :     }
    2321           0 :     talloc_zfree(tmp_ctx);
    2322           0 :     return ret;
    2323             : }
    2324             : 
    2325           5 : int sysdb_cache_password(struct sss_domain_info *domain,
    2326             :                          const char *username,
    2327             :                          const char *password)
    2328             : {
    2329           5 :     return sysdb_cache_password_ex(domain, username, password,
    2330             :                                    SSS_AUTHTOK_TYPE_PASSWORD, 0);
    2331             : }
    2332             : 
    2333             : /* =Custom Search================== */
    2334             : 
    2335          25 : int sysdb_search_custom(TALLOC_CTX *mem_ctx,
    2336             :                         struct sss_domain_info *domain,
    2337             :                         const char *filter,
    2338             :                         const char *subtree_name,
    2339             :                         const char **attrs,
    2340             :                         size_t *msgs_count,
    2341             :                         struct ldb_message ***msgs)
    2342             : {
    2343             :     TALLOC_CTX *tmp_ctx;
    2344          25 :     struct ldb_dn *basedn = NULL;
    2345             :     int ret;
    2346             : 
    2347          25 :     tmp_ctx = talloc_new(NULL);
    2348          25 :     if (tmp_ctx == NULL) {
    2349           0 :         ret = ENOMEM;
    2350           0 :         goto done;
    2351             :     }
    2352             : 
    2353          25 :     if (filter == NULL || subtree_name == NULL) {
    2354           0 :         ret = EINVAL;
    2355           0 :         goto done;
    2356             :     }
    2357             : 
    2358          25 :     basedn = sysdb_custom_subtree_dn(tmp_ctx, domain, subtree_name);
    2359          25 :     if (basedn == NULL) {
    2360           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_subtree_dn failed.\n");
    2361           0 :         ret = ENOMEM;
    2362           0 :         goto done;
    2363             :     }
    2364          25 :     if (!ldb_dn_validate(basedn)) {
    2365           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n");
    2366           0 :         ret = EINVAL;
    2367           0 :         goto done;
    2368             :     }
    2369             : 
    2370          25 :     ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
    2371             :                              LDB_SCOPE_SUBTREE, filter, attrs,
    2372             :                              msgs_count, msgs);
    2373             : done:
    2374          25 :     talloc_free(tmp_ctx);
    2375          25 :     return ret;
    2376             : }
    2377             : 
    2378          26 : int sysdb_search_custom_by_name(TALLOC_CTX *mem_ctx,
    2379             :                                 struct sss_domain_info *domain,
    2380             :                                 const char *object_name,
    2381             :                                 const char *subtree_name,
    2382             :                                 const char **attrs,
    2383             :                                 size_t *_count,
    2384             :                                 struct ldb_message ***_msgs)
    2385             : {
    2386             :     TALLOC_CTX *tmp_ctx;
    2387             :     struct ldb_dn *basedn;
    2388             :     struct ldb_message **msgs;
    2389             :     size_t count;
    2390             :     int ret;
    2391             : 
    2392          26 :     if (object_name == NULL || subtree_name == NULL) {
    2393           0 :         return EINVAL;
    2394             :     }
    2395             : 
    2396          26 :     tmp_ctx = talloc_new(NULL);
    2397          26 :     if (!tmp_ctx) {
    2398           0 :         return ENOMEM;
    2399             :     }
    2400             : 
    2401          26 :     basedn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
    2402          26 :     if (basedn == NULL) {
    2403           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
    2404           0 :         ret = ENOMEM;
    2405           0 :         goto done;
    2406             :     }
    2407          26 :     if (!ldb_dn_validate(basedn)) {
    2408           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n");
    2409           0 :         ret = EINVAL;
    2410           0 :         goto done;
    2411             :     }
    2412             : 
    2413          26 :     ret = sysdb_search_entry(tmp_ctx, domain->sysdb, basedn,
    2414             :                              LDB_SCOPE_BASE, NULL, attrs, &count, &msgs);
    2415          26 :     if (ret) {
    2416          23 :         goto done;
    2417             :     }
    2418             : 
    2419           3 :     if (count > 1) {
    2420           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "More than one result found.\n");
    2421           0 :         ret = EFAULT;
    2422           0 :         goto done;
    2423             :     }
    2424             : 
    2425           3 :     *_count = count;
    2426           3 :     *_msgs = talloc_move(mem_ctx, &msgs);
    2427             : 
    2428             : done:
    2429          26 :     talloc_zfree(tmp_ctx);
    2430          26 :     return ret;
    2431             : }
    2432             : 
    2433             : 
    2434             : /* =Custom Store (replaces-existing-data)================== */
    2435             : 
    2436          23 : int sysdb_store_custom(struct sss_domain_info *domain,
    2437             :                        const char *object_name,
    2438             :                        const char *subtree_name,
    2439             :                        struct sysdb_attrs *attrs)
    2440             : {
    2441             :     TALLOC_CTX *tmp_ctx;
    2442          23 :     const char *search_attrs[] = { "*", NULL };
    2443          23 :     size_t resp_count = 0;
    2444             :     struct ldb_message **resp;
    2445             :     struct ldb_message *msg;
    2446             :     struct ldb_message_element *el;
    2447          23 :     bool add_object = false;
    2448             :     int ret;
    2449             :     int i;
    2450             : 
    2451          23 :     if (object_name == NULL || subtree_name == NULL) {
    2452           0 :         return EINVAL;
    2453             :     }
    2454             : 
    2455          23 :     ret = ldb_transaction_start(domain->sysdb->ldb);
    2456          23 :     if (ret) {
    2457           0 :         return sysdb_error_to_errno(ret);
    2458             :     }
    2459             : 
    2460          23 :     tmp_ctx = talloc_new(NULL);
    2461          23 :     if (!tmp_ctx) {
    2462           0 :         ret = ENOMEM;
    2463           0 :         goto done;
    2464             :     }
    2465             : 
    2466          23 :     ret = sysdb_search_custom_by_name(tmp_ctx, domain,
    2467             :                                       object_name, subtree_name,
    2468             :                                       search_attrs, &resp_count, &resp);
    2469          23 :     if (ret != EOK && ret != ENOENT) {
    2470           0 :         goto done;
    2471             :     }
    2472             : 
    2473          23 :     if (ret == ENOENT) {
    2474          22 :        add_object = true;
    2475             :     }
    2476             : 
    2477          23 :     msg = ldb_msg_new(tmp_ctx);
    2478          23 :     if (msg == NULL) {
    2479           0 :         ret = ENOMEM;
    2480           0 :         goto done;
    2481             :     }
    2482             : 
    2483          23 :     msg->dn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
    2484          23 :     if (!msg->dn) {
    2485           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
    2486           0 :         ret = ENOMEM;
    2487           0 :         goto done;
    2488             :     }
    2489             : 
    2490          23 :     msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num);
    2491          23 :     if (!msg->elements) {
    2492           0 :         ret = ENOMEM;
    2493           0 :         goto done;
    2494             :     }
    2495             : 
    2496          93 :     for (i = 0; i < attrs->num; i++) {
    2497          70 :         msg->elements[i] = attrs->a[i];
    2498          70 :         if (add_object) {
    2499          68 :             msg->elements[i].flags = LDB_FLAG_MOD_ADD;
    2500             :         } else {
    2501           2 :             el = ldb_msg_find_element(resp[0], attrs->a[i].name);
    2502           2 :             if (el == NULL) {
    2503           1 :                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
    2504             :             } else {
    2505           1 :                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    2506             :             }
    2507             :         }
    2508             :     }
    2509          23 :     msg->num_elements = attrs->num;
    2510             : 
    2511          23 :     if (add_object) {
    2512          22 :         ret = ldb_add(domain->sysdb->ldb, msg);
    2513             :     } else {
    2514           1 :         ret = ldb_modify(domain->sysdb->ldb, msg);
    2515             :     }
    2516          23 :     if (ret != LDB_SUCCESS) {
    2517           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to store custom entry: %s(%d)[%s]\n",
    2518             :                   ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
    2519           0 :         ret = sysdb_error_to_errno(ret);
    2520             :     }
    2521             : 
    2522             : done:
    2523          23 :     if (ret) {
    2524           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2525           0 :         ldb_transaction_cancel(domain->sysdb->ldb);
    2526             :     } else {
    2527          23 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    2528          23 :         ret = sysdb_error_to_errno(ret);
    2529             :     }
    2530          23 :     talloc_zfree(tmp_ctx);
    2531          23 :     return ret;
    2532             : }
    2533             : 
    2534             : /* = Custom Delete======================================= */
    2535             : 
    2536          13 : int sysdb_delete_custom(struct sss_domain_info *domain,
    2537             :                         const char *object_name,
    2538             :                         const char *subtree_name)
    2539             : {
    2540             :     TALLOC_CTX *tmp_ctx;
    2541             :     struct ldb_dn *dn;
    2542             :     int ret;
    2543             : 
    2544          13 :     if (object_name == NULL || subtree_name == NULL) {
    2545           0 :         return EINVAL;
    2546             :     }
    2547             : 
    2548          13 :     tmp_ctx = talloc_new(NULL);
    2549          13 :     if (!tmp_ctx) {
    2550           0 :         return ENOMEM;
    2551             :     }
    2552             : 
    2553          13 :     dn = sysdb_custom_dn(tmp_ctx, domain, object_name, subtree_name);
    2554          13 :     if (dn == NULL) {
    2555           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_custom_dn failed.\n");
    2556           0 :         ret = ENOMEM;
    2557           0 :         goto done;
    2558             :     }
    2559             : 
    2560          13 :     ret = ldb_delete(domain->sysdb->ldb, dn);
    2561             : 
    2562          13 :     switch (ret) {
    2563             :     case LDB_SUCCESS:
    2564             :     case LDB_ERR_NO_SUCH_OBJECT:
    2565          13 :         ret = EOK;
    2566          13 :         break;
    2567             : 
    2568             :     default:
    2569           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n",
    2570             :                   ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb));
    2571           0 :         ret = sysdb_error_to_errno(ret);
    2572           0 :         break;
    2573             :     }
    2574             : 
    2575             : done:
    2576          13 :     talloc_zfree(tmp_ctx);
    2577          13 :     return ret;
    2578             : }
    2579             : 
    2580             : /* = ASQ search request ======================================== */
    2581             : 
    2582          10 : int sysdb_asq_search(TALLOC_CTX *mem_ctx,
    2583             :                      struct sss_domain_info *domain,
    2584             :                      struct ldb_dn *base_dn,
    2585             :                      const char *expression,
    2586             :                      const char *asq_attribute,
    2587             :                      const char **attrs,
    2588             :                      size_t *msgs_count,
    2589             :                      struct ldb_message ***msgs)
    2590             : {
    2591             :     TALLOC_CTX *tmp_ctx;
    2592             :     struct ldb_request *ldb_req;
    2593             :     struct ldb_control **ctrl;
    2594             :     struct ldb_asq_control *asq_control;
    2595             :     struct ldb_result *res;
    2596             :     int ret;
    2597             : 
    2598          10 :     tmp_ctx = talloc_new(NULL);
    2599          10 :     if (!tmp_ctx) {
    2600           0 :         return ENOMEM;
    2601             :     }
    2602             : 
    2603          10 :     ctrl = talloc_array(tmp_ctx, struct ldb_control *, 2);
    2604          10 :     if (ctrl == NULL) {
    2605           0 :         ret = ENOMEM;
    2606           0 :         goto fail;
    2607             :     }
    2608             : 
    2609          10 :     ctrl[0] = talloc(ctrl, struct ldb_control);
    2610          10 :     if (ctrl[0] == NULL) {
    2611           0 :         ret = ENOMEM;
    2612           0 :         goto fail;
    2613             :     }
    2614          10 :     ctrl[1] = NULL;
    2615             : 
    2616          10 :     ctrl[0]->oid = LDB_CONTROL_ASQ_OID;
    2617          10 :     ctrl[0]->critical = 1;
    2618             : 
    2619          10 :     asq_control = talloc(ctrl[0], struct ldb_asq_control);
    2620          10 :     if (asq_control == NULL) {
    2621           0 :         ret = ENOMEM;
    2622           0 :         goto fail;
    2623             :     }
    2624             : 
    2625          10 :     asq_control->request = 1;
    2626          10 :     asq_control->source_attribute = talloc_strdup(asq_control, asq_attribute);
    2627          10 :     if (asq_control->source_attribute == NULL) {
    2628           0 :         ret = ENOMEM;
    2629           0 :         goto fail;
    2630             :     }
    2631          10 :     asq_control->src_attr_len = strlen(asq_control->source_attribute);
    2632          10 :     ctrl[0]->data = asq_control;
    2633             : 
    2634          10 :     res = talloc_zero(tmp_ctx, struct ldb_result);
    2635          10 :     if (!res) {
    2636           0 :         ret = ENOMEM;
    2637           0 :         goto fail;
    2638             :     }
    2639             : 
    2640          10 :     ret = ldb_build_search_req(&ldb_req, domain->sysdb->ldb, tmp_ctx,
    2641             :                                base_dn, LDB_SCOPE_BASE,
    2642             :                                expression, attrs, ctrl,
    2643             :                                res, ldb_search_default_callback, NULL);
    2644          10 :     if (ret != LDB_SUCCESS) {
    2645           0 :         ret = sysdb_error_to_errno(ret);
    2646           0 :         goto fail;
    2647             :     }
    2648             : 
    2649          10 :     ret = ldb_request(domain->sysdb->ldb, ldb_req);
    2650          10 :     if (ret == LDB_SUCCESS) {
    2651          10 :         ret = ldb_wait(ldb_req->handle, LDB_WAIT_ALL);
    2652             :     }
    2653          10 :     if (ret) {
    2654           1 :         ret = sysdb_error_to_errno(ret);
    2655           1 :         goto fail;
    2656             :     }
    2657             : 
    2658           9 :     *msgs_count = res->count;
    2659           9 :     *msgs = talloc_move(mem_ctx, &res->msgs);
    2660             : 
    2661           9 :     talloc_zfree(tmp_ctx);
    2662           9 :     return EOK;
    2663             : 
    2664             : fail:
    2665           1 :     if (ret == ENOENT) {
    2666           1 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
    2667             :     }
    2668           0 :     else if (ret) {
    2669           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    2670             :     }
    2671           1 :     talloc_zfree(tmp_ctx);
    2672           1 :     return ret;
    2673             : }
    2674             : 
    2675             : /* =Search-Users-with-Custom-Filter====================================== */
    2676             : 
    2677          31 : int sysdb_search_users(TALLOC_CTX *mem_ctx,
    2678             :                        struct sss_domain_info *domain,
    2679             :                        const char *sub_filter,
    2680             :                        const char **attrs,
    2681             :                        size_t *msgs_count,
    2682             :                        struct ldb_message ***msgs)
    2683             : {
    2684             :     TALLOC_CTX *tmp_ctx;
    2685             :     struct ldb_dn *basedn;
    2686             :     char *filter;
    2687             :     int ret;
    2688             : 
    2689          31 :     tmp_ctx = talloc_new(NULL);
    2690          31 :     if (!tmp_ctx) {
    2691           0 :         return ENOMEM;
    2692             :     }
    2693             : 
    2694          31 :     basedn = sysdb_user_base_dn(tmp_ctx, domain);
    2695          31 :     if (!basedn) {
    2696           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
    2697           0 :         ret = ENOMEM;
    2698           0 :         goto fail;
    2699             :     }
    2700             : 
    2701          31 :     filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_UC, sub_filter);
    2702          31 :     if (!filter) {
    2703           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
    2704           0 :         ret = ENOMEM;
    2705           0 :         goto fail;
    2706             :     }
    2707             : 
    2708          31 :     DEBUG(SSSDBG_TRACE_INTERNAL,
    2709             :           "Search users with filter: %s\n", filter);
    2710             : 
    2711          31 :     ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
    2712             :                              LDB_SCOPE_SUBTREE, filter, attrs,
    2713             :                              msgs_count, msgs);
    2714          31 :     if (ret) {
    2715          19 :         goto fail;
    2716             :     }
    2717             : 
    2718          12 :     talloc_zfree(tmp_ctx);
    2719          12 :     return EOK;
    2720             : 
    2721             : fail:
    2722          19 :     if (ret == ENOENT) {
    2723          19 :         DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n");
    2724             :     }
    2725           0 :     else if (ret) {
    2726           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    2727             :     }
    2728          19 :     talloc_zfree(tmp_ctx);
    2729          19 :     return ret;
    2730             : }
    2731             : 
    2732             : /* =Delete-User-by-Name-OR-uid============================================ */
    2733             : 
    2734         112 : int sysdb_delete_user(struct sss_domain_info *domain,
    2735             :                       const char *name, uid_t uid)
    2736             : {
    2737             :     TALLOC_CTX *tmp_ctx;
    2738         112 :     const char *attrs[] = {SYSDB_GHOST, NULL};
    2739             :     size_t msg_count;
    2740             :     char *filter;
    2741             :     struct ldb_message **msgs;
    2742             :     struct ldb_message *msg;
    2743             :     int ret;
    2744             :     int i;
    2745             :     char *sanitized_name;
    2746             : 
    2747         112 :     tmp_ctx = talloc_new(NULL);
    2748         112 :     if (!tmp_ctx) {
    2749           0 :         return ENOMEM;
    2750             :     }
    2751             : 
    2752         112 :     if (name) {
    2753          93 :         ret = sysdb_search_user_by_name(tmp_ctx, domain, name, NULL, &msg);
    2754             :     } else {
    2755          19 :         ret = sysdb_search_user_by_uid(tmp_ctx, domain, uid, NULL, &msg);
    2756             :     }
    2757         112 :     if (ret == EOK) {
    2758         110 :         if (name && uid) {
    2759             :             /* verify name/gid match */
    2760             :             const char *c_name;
    2761             :             uint64_t c_uid;
    2762             : 
    2763           3 :             c_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
    2764           3 :             c_uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
    2765           3 :             if (c_name == NULL || c_uid == 0) {
    2766           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    2767             :                       "Attribute is missing but this should never happen!\n");
    2768           0 :                 ret = EFAULT;
    2769           0 :                 goto fail;
    2770             :             }
    2771           3 :             if (strcmp(name, c_name) || uid != c_uid) {
    2772             :                 /* this is not the entry we are looking for */
    2773           0 :                 ret = EINVAL;
    2774           0 :                 goto fail;
    2775             :             }
    2776             :         }
    2777             : 
    2778         110 :         ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
    2779         110 :         if (ret) {
    2780           0 :             goto fail;
    2781             :         }
    2782           2 :     } else if (ret == ENOENT && name != NULL) {
    2783             :         /* Perhaps a ghost user? */
    2784           1 :         ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name);
    2785           1 :         if (ret != EOK) {
    2786           0 :             goto fail;
    2787             :         }
    2788             : 
    2789           1 :         filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
    2790             :                                           SYSDB_GHOST, sanitized_name);
    2791           1 :         if (filter == NULL) {
    2792           0 :             ret = ENOMEM;
    2793           0 :             goto fail;
    2794             :         }
    2795             : 
    2796           1 :         ret = sysdb_search_groups(tmp_ctx, domain, filter, attrs,
    2797             :                                   &msg_count, &msgs);
    2798           1 :         if (ret != EOK) {
    2799           1 :             goto fail;
    2800             :         }
    2801             : 
    2802           0 :         for (i = 0; i < msg_count; i++) {
    2803           0 :             msg = ldb_msg_new(tmp_ctx);
    2804           0 :             if (!msg) {
    2805           0 :                 ERROR_OUT(ret, ENOMEM, fail);
    2806             :             }
    2807             : 
    2808           0 :             msg->dn = msgs[i]->dn;
    2809             : 
    2810           0 :             ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_GHOST, name);
    2811           0 :             if (ret) goto fail;
    2812             : 
    2813           0 :             ret = ldb_modify(domain->sysdb->ldb, msg);
    2814           0 :             if (ret != LDB_SUCCESS) {
    2815           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
    2816             :                       "ldb_modify failed: [%s](%d)[%s]\n",
    2817             :                       ldb_strerror(ret), ret,
    2818             :                       ldb_errstring(domain->sysdb->ldb));
    2819             :             }
    2820           0 :             ret = sysdb_error_to_errno(ret);
    2821           0 :             if (ret != EOK) {
    2822           0 :                 goto fail;
    2823             :             }
    2824             : 
    2825           0 :             talloc_zfree(msg);
    2826             :         }
    2827             :     } else {
    2828             :         goto fail;
    2829             :     }
    2830             : 
    2831             : 
    2832         110 :     talloc_zfree(tmp_ctx);
    2833         110 :     return EOK;
    2834             : 
    2835             : fail:
    2836           2 :     DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2837           2 :     talloc_zfree(tmp_ctx);
    2838           2 :     return ret;
    2839             : }
    2840             : 
    2841             : 
    2842             : /* =Search-Groups-with-Custom-Filter===================================== */
    2843             : 
    2844          30 : int sysdb_search_groups(TALLOC_CTX *mem_ctx,
    2845             :                         struct sss_domain_info *domain,
    2846             :                         const char *sub_filter,
    2847             :                         const char **attrs,
    2848             :                         size_t *msgs_count,
    2849             :                         struct ldb_message ***msgs)
    2850             : {
    2851             :     TALLOC_CTX *tmp_ctx;
    2852             :     struct ldb_dn *basedn;
    2853             :     char *filter;
    2854             :     int ret;
    2855             : 
    2856          30 :     tmp_ctx = talloc_new(NULL);
    2857          30 :     if (!tmp_ctx) {
    2858           0 :         return ENOMEM;
    2859             :     }
    2860             : 
    2861          30 :     basedn = sysdb_group_base_dn(tmp_ctx, domain);
    2862          30 :     if (!basedn) {
    2863           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
    2864           0 :         ret = ENOMEM;
    2865           0 :         goto fail;
    2866             :     }
    2867             : 
    2868          30 :     filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_GC, sub_filter);
    2869          30 :     if (!filter) {
    2870           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
    2871           0 :         ret = ENOMEM;
    2872           0 :         goto fail;
    2873             :     }
    2874             : 
    2875          30 :     DEBUG(SSSDBG_TRACE_INTERNAL,
    2876             :           "Search groups with filter: %s\n", filter);
    2877             : 
    2878          30 :     ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
    2879             :                              LDB_SCOPE_SUBTREE, filter, attrs,
    2880             :                              msgs_count, msgs);
    2881          30 :     if (ret) {
    2882          19 :         goto fail;
    2883             :     }
    2884             : 
    2885          11 :     talloc_zfree(tmp_ctx);
    2886          11 :     return EOK;
    2887             : 
    2888             : fail:
    2889          19 :     if (ret == ENOENT) {
    2890          19 :         DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n");
    2891             :     }
    2892           0 :     else if (ret) {
    2893           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    2894             :     }
    2895          19 :     talloc_zfree(tmp_ctx);
    2896          19 :     return ret;
    2897             : }
    2898             : 
    2899             : /* =Delete-Group-by-Name-OR-gid=========================================== */
    2900             : 
    2901         132 : int sysdb_delete_group(struct sss_domain_info *domain,
    2902             :                        const char *name, gid_t gid)
    2903             : {
    2904             :     TALLOC_CTX *tmp_ctx;
    2905             :     struct ldb_message *msg;
    2906             :     int ret;
    2907             : 
    2908         132 :     tmp_ctx = talloc_new(NULL);
    2909         132 :     if (!tmp_ctx) {
    2910           0 :         return ENOMEM;
    2911             :     }
    2912             : 
    2913         132 :     if (name) {
    2914          28 :         ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg);
    2915             :     } else {
    2916         104 :         ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, NULL, &msg);
    2917             :     }
    2918         132 :     if (ret) {
    2919           3 :         goto fail;
    2920             :     }
    2921             : 
    2922         129 :     if (name && gid) {
    2923             :         /* verify name/gid match */
    2924             :         const char *c_name;
    2925             :         uint64_t c_gid;
    2926             : 
    2927           2 :         c_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
    2928           2 :         c_gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
    2929           2 :         if (c_name == NULL || c_gid == 0) {
    2930           0 :             DEBUG(SSSDBG_OP_FAILURE,
    2931             :                   "Attribute is missing but this should never happen!\n");
    2932           0 :             ret = EFAULT;
    2933           0 :             goto fail;
    2934             :         }
    2935           2 :         if (strcmp(name, c_name) || gid != c_gid) {
    2936             :             /* this is not the entry we are looking for */
    2937           0 :             ret = EINVAL;
    2938           0 :             goto fail;
    2939             :         }
    2940             :     }
    2941             : 
    2942         129 :     ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
    2943         129 :     if (ret) {
    2944           0 :         goto fail;
    2945             :     }
    2946             : 
    2947         129 :     talloc_zfree(tmp_ctx);
    2948         129 :     return EOK;
    2949             : 
    2950             : fail:
    2951           3 :     DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    2952           3 :     talloc_zfree(tmp_ctx);
    2953           3 :     return ret;
    2954             : }
    2955             : 
    2956             : /* =Search-Netgroups-with-Custom-Filter===================================== */
    2957             : 
    2958           1 : int sysdb_search_netgroups(TALLOC_CTX *mem_ctx,
    2959             :                            struct sss_domain_info *domain,
    2960             :                            const char *sub_filter,
    2961             :                            const char **attrs,
    2962             :                            size_t *msgs_count,
    2963             :                            struct ldb_message ***msgs)
    2964             : {
    2965             :     TALLOC_CTX *tmp_ctx;
    2966             :     struct ldb_dn *basedn;
    2967             :     char *filter;
    2968             :     int ret;
    2969             : 
    2970           1 :     tmp_ctx = talloc_new(NULL);
    2971           1 :     if (!tmp_ctx) {
    2972           0 :         return ENOMEM;
    2973             :     }
    2974             : 
    2975           1 :     basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
    2976             :                             SYSDB_TMPL_NETGROUP_BASE, domain->name);
    2977           1 :     if (!basedn) {
    2978           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
    2979           0 :         ret = ENOMEM;
    2980           0 :         goto fail;
    2981             :     }
    2982             : 
    2983           1 :     filter = talloc_asprintf(tmp_ctx, "(&(%s)%s)", SYSDB_NC, sub_filter);
    2984           1 :     if (!filter) {
    2985           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
    2986           0 :         ret = ENOMEM;
    2987           0 :         goto fail;
    2988             :     }
    2989             : 
    2990           1 :     DEBUG(SSSDBG_TRACE_FUNC, "Search netgroups with filter: %s\n", filter);
    2991             : 
    2992           1 :     ret = sysdb_search_entry(mem_ctx, domain->sysdb, basedn,
    2993             :                              LDB_SCOPE_SUBTREE, filter, attrs,
    2994             :                              msgs_count, msgs);
    2995           1 :     if (ret) {
    2996           1 :         goto fail;
    2997             :     }
    2998             : 
    2999           0 :     talloc_zfree(tmp_ctx);
    3000           0 :     return EOK;
    3001             : 
    3002             : fail:
    3003           1 :     if (ret == ENOENT) {
    3004           1 :         DEBUG(SSSDBG_TRACE_FUNC, "Entry not found\n");
    3005             :     } else {
    3006           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    3007             :     }
    3008           1 :     talloc_zfree(tmp_ctx);
    3009           1 :     return ret;
    3010             : }
    3011             : 
    3012             : /* =Delete-Netgroup-by-Name============================================== */
    3013             : 
    3014           5 : int sysdb_delete_netgroup(struct sss_domain_info *domain,
    3015             :                           const char *name)
    3016             : {
    3017             :     TALLOC_CTX *tmp_ctx;
    3018             :     struct ldb_message *msg;
    3019             :     int ret;
    3020             : 
    3021           5 :     if (!name) return EINVAL;
    3022             : 
    3023           5 :     tmp_ctx = talloc_new(NULL);
    3024           5 :     if (!tmp_ctx) {
    3025           0 :         return ENOMEM;
    3026             :     }
    3027             : 
    3028           5 :     ret = sysdb_search_netgroup_by_name(tmp_ctx, domain, name, NULL, &msg);
    3029           5 :     if (ret != EOK && ret != ENOENT) {
    3030           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    3031             :               "sysdb_search_netgroup_by_name failed: %d (%s)\n",
    3032             :                    ret, strerror(ret));
    3033           0 :         goto done;
    3034           5 :     } else if (ret == ENOENT) {
    3035           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    3036             :               "Netgroup does not exist, nothing to delete\n");
    3037           0 :         ret = EOK;
    3038           0 :         goto done;
    3039             :     }
    3040             : 
    3041           5 :     ret = sysdb_delete_entry(domain->sysdb, msg->dn, false);
    3042           5 :     if (ret != EOK) {
    3043           0 :         goto done;
    3044             :     }
    3045             : 
    3046             : done:
    3047           5 :     if (ret != EOK) {
    3048           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, strerror(ret));
    3049             :     }
    3050           5 :     talloc_free(tmp_ctx);
    3051           5 :     return ret;
    3052             : }
    3053             : 
    3054           2 : int sysdb_delete_by_sid(struct sysdb_ctx *sysdb,
    3055             :                         struct sss_domain_info *domain,
    3056             :                         const char *sid_str)
    3057             : {
    3058             :     TALLOC_CTX *tmp_ctx;
    3059             :     struct ldb_result *res;
    3060             :     int ret;
    3061             : 
    3062           2 :     if (!sid_str) return EINVAL;
    3063             : 
    3064           2 :     tmp_ctx = talloc_new(NULL);
    3065           2 :     if (!tmp_ctx) {
    3066           0 :         return ENOMEM;
    3067             :     }
    3068             : 
    3069           2 :     ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res);
    3070             : 
    3071           2 :     if (ret == ENOENT) {
    3072             :         /* No existing entry. Just quit. */
    3073           1 :         DEBUG(SSSDBG_TRACE_FUNC,
    3074             :               "search by sid did not return any results.\n");
    3075           1 :         ret = EOK;
    3076           1 :         goto done;
    3077           1 :     } else if (ret != EOK) {
    3078           0 :         DEBUG(SSSDBG_OP_FAILURE, "search by sid failed: %d (%s)\n",
    3079             :               ret, strerror(ret));
    3080           0 :         goto done;
    3081             :     }
    3082             : 
    3083           1 :     if (res->count > 1) {
    3084           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
    3085             :                                      "result !?!\n");
    3086           0 :         ret = EIO;
    3087           0 :         goto done;
    3088             :     }
    3089             : 
    3090           1 :     ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, false);
    3091           1 :     if (ret != EOK) {
    3092           0 :         goto done;
    3093             :     }
    3094             : 
    3095             : done:
    3096           2 :     if (ret != EOK) {
    3097           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    3098             :     }
    3099           2 :     talloc_free(tmp_ctx);
    3100           2 :     return ret;
    3101             : }
    3102             : 
    3103             : /* ========= Authentication against cached password ============ */
    3104             : 
    3105             : 
    3106          34 : errno_t check_failed_login_attempts(struct confdb_ctx *cdb,
    3107             :                                     struct ldb_message *ldb_msg,
    3108             :                                     uint32_t *failed_login_attempts,
    3109             :                                     time_t *delayed_until)
    3110             : {
    3111             :     int ret;
    3112             :     int allowed_failed_login_attempts;
    3113             :     int failed_login_delay;
    3114             :     time_t last_failed_login;
    3115             :     time_t end;
    3116             :     TALLOC_CTX *tmp_ctx;
    3117             : 
    3118          34 :     tmp_ctx = talloc_new(NULL);
    3119          34 :     if (!tmp_ctx) {
    3120           0 :         return ENOMEM;
    3121             :     }
    3122             : 
    3123          34 :     *delayed_until = -1;
    3124          34 :     *failed_login_attempts = ldb_msg_find_attr_as_uint(ldb_msg,
    3125             :                                                 SYSDB_FAILED_LOGIN_ATTEMPTS, 0);
    3126          34 :     last_failed_login = (time_t) ldb_msg_find_attr_as_int64(ldb_msg,
    3127             :                                                     SYSDB_LAST_FAILED_LOGIN, 0);
    3128          34 :     ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
    3129             :                          CONFDB_PAM_FAILED_LOGIN_ATTEMPTS,
    3130             :                          CONFDB_DEFAULT_PAM_FAILED_LOGIN_ATTEMPTS,
    3131             :                          &allowed_failed_login_attempts);
    3132          34 :     if (ret != EOK) {
    3133           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    3134             :               "Failed to read the number of allowed failed login "
    3135             :                   "attempts.\n");
    3136           0 :         ret = ERR_INTERNAL;
    3137           0 :         goto done;
    3138             :     }
    3139          34 :     ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
    3140             :                          CONFDB_PAM_FAILED_LOGIN_DELAY,
    3141             :                          CONFDB_DEFAULT_PAM_FAILED_LOGIN_DELAY,
    3142             :                          &failed_login_delay);
    3143          34 :     if (ret != EOK) {
    3144           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read the failed login delay.\n");
    3145           0 :         ret = ERR_INTERNAL;
    3146           0 :         goto done;
    3147             :     }
    3148          34 :     DEBUG(SSSDBG_TRACE_ALL,
    3149             :           "Failed login attempts [%d], allowed failed login attempts [%d], "
    3150             :               "failed login delay [%d].\n", *failed_login_attempts,
    3151             :               allowed_failed_login_attempts, failed_login_delay);
    3152             : 
    3153          34 :     if (allowed_failed_login_attempts) {
    3154           8 :         if (*failed_login_attempts >= allowed_failed_login_attempts) {
    3155           4 :             if (failed_login_delay) {
    3156           2 :                 end = last_failed_login + (failed_login_delay * 60);
    3157           2 :                 if (end < time(NULL)) {
    3158           1 :                     DEBUG(SSSDBG_TRACE_LIBS, "failed_login_delay has passed, "
    3159             :                               "resetting failed_login_attempts.\n");
    3160           1 :                     *failed_login_attempts = 0;
    3161             :                 } else {
    3162           1 :                     DEBUG(SSSDBG_TRACE_LIBS,
    3163             :                           "login delayed until %lld.\n", (long long) end);
    3164           1 :                     *delayed_until = end;
    3165           1 :                     ret = ERR_AUTH_DENIED;
    3166           1 :                     goto done;
    3167             :                 }
    3168             :             } else {
    3169           2 :                 DEBUG(SSSDBG_CONF_SETTINGS, "Too many failed logins.\n");
    3170           2 :                 ret = ERR_AUTH_DENIED;
    3171           2 :                 goto done;
    3172             :             }
    3173             :         }
    3174             :     }
    3175             : 
    3176          31 :     ret = EOK;
    3177             : done:
    3178          34 :     talloc_free(tmp_ctx);
    3179          34 :     return ret;
    3180             : }
    3181             : 
    3182           9 : static errno_t check_for_combined_2fa_password(struct sss_domain_info *domain,
    3183             :                                                struct ldb_message *ldb_msg,
    3184             :                                                const char *password,
    3185             :                                                const char *userhash)
    3186             : {
    3187             : 
    3188             :     unsigned int cached_authtok_type;
    3189             :     unsigned int cached_fa2_len;
    3190             :     char *short_pw;
    3191             :     char *comphash;
    3192             :     size_t pw_len;
    3193             :     TALLOC_CTX *tmp_ctx;
    3194             :     int ret;
    3195             : 
    3196           9 :     cached_authtok_type = ldb_msg_find_attr_as_uint(ldb_msg,
    3197             :                                                     SYSDB_CACHEDPWD_TYPE,
    3198             :                                                     SSS_AUTHTOK_TYPE_EMPTY);
    3199           9 :     if (cached_authtok_type != SSS_AUTHTOK_TYPE_2FA) {
    3200           4 :         DEBUG(SSSDBG_TRACE_LIBS, "Wrong authtok type.\n");
    3201           4 :         return EINVAL;
    3202             :     }
    3203             : 
    3204           5 :     cached_fa2_len = ldb_msg_find_attr_as_uint(ldb_msg, SYSDB_CACHEDPWD_FA2_LEN,
    3205             :                                                0);
    3206           5 :     if (cached_fa2_len == 0) {
    3207           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Second factor size not available.\n");
    3208           0 :         return EINVAL;
    3209             :     }
    3210             : 
    3211           5 :     pw_len = strlen(password);
    3212           5 :     if (pw_len < cached_fa2_len + domain->cache_credentials_min_ff_length) {
    3213           3 :         DEBUG(SSSDBG_TRACE_LIBS, "Password too short.\n");
    3214           3 :         return EINVAL;
    3215             :     }
    3216             : 
    3217           2 :     tmp_ctx = talloc_new(NULL);
    3218           2 :     if (tmp_ctx == NULL) {
    3219           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
    3220           0 :         return ENOMEM;
    3221             :     }
    3222             : 
    3223           2 :     short_pw = talloc_strndup(tmp_ctx, password, (pw_len - cached_fa2_len));
    3224           2 :     if (short_pw == NULL) {
    3225           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
    3226           0 :         ret = ENOMEM;
    3227           0 :         goto done;
    3228             :     }
    3229             : 
    3230           2 :     ret = s3crypt_sha512(tmp_ctx, short_pw, userhash, &comphash);
    3231           2 :     if (ret != EOK) {
    3232           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
    3233           0 :         ret = ERR_INTERNAL;
    3234           0 :         goto done;
    3235             :     }
    3236             : 
    3237           2 :     if (strcmp(userhash, comphash) != 0) {
    3238           1 :         DEBUG(SSSDBG_MINOR_FAILURE,
    3239             :               "Hash of shorten password does not match.\n");
    3240           1 :         ret = ERR_AUTH_FAILED;
    3241           1 :         goto done;
    3242             :     }
    3243             : 
    3244           1 :     ret = EOK;
    3245             : 
    3246             : done:
    3247           2 :     talloc_free(tmp_ctx);
    3248             : 
    3249           2 :     return ret;
    3250             : }
    3251             : 
    3252          18 : int sysdb_cache_auth(struct sss_domain_info *domain,
    3253             :                      const char *name,
    3254             :                      const char *password,
    3255             :                      struct confdb_ctx *cdb,
    3256             :                      bool just_check,
    3257             :                      time_t *_expire_date,
    3258             :                      time_t *_delayed_until)
    3259             : {
    3260             :     TALLOC_CTX *tmp_ctx;
    3261          18 :     const char *attrs[] = { SYSDB_NAME, SYSDB_CACHEDPWD, SYSDB_DISABLED,
    3262             :                             SYSDB_LAST_LOGIN, SYSDB_LAST_ONLINE_AUTH,
    3263             :                             "lastCachedPasswordChange",
    3264             :                             "accountExpires", SYSDB_FAILED_LOGIN_ATTEMPTS,
    3265             :                             SYSDB_LAST_FAILED_LOGIN, SYSDB_CACHEDPWD_TYPE,
    3266             :                             SYSDB_CACHEDPWD_FA2_LEN, NULL };
    3267             :     struct ldb_message *ldb_msg;
    3268             :     const char *userhash;
    3269             :     char *comphash;
    3270          18 :     uint64_t lastLogin = 0;
    3271             :     int cred_expiration;
    3272          18 :     uint32_t failed_login_attempts = 0;
    3273             :     struct sysdb_attrs *update_attrs;
    3274          18 :     bool authentication_successful = false;
    3275          18 :     time_t expire_date = -1;
    3276          18 :     time_t delayed_until = -1;
    3277             :     int ret;
    3278             : 
    3279          18 :     if (name == NULL || *name == '\0') {
    3280           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
    3281           0 :         return EINVAL;
    3282             :     }
    3283             : 
    3284          18 :     if (cdb == NULL) {
    3285           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing config db context.\n");
    3286           0 :         return EINVAL;
    3287             :     }
    3288             : 
    3289          18 :     if (domain->sysdb == NULL) {
    3290           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing sysdb db context.\n");
    3291           0 :         return EINVAL;
    3292             :     }
    3293             : 
    3294          18 :     if (!domain->cache_credentials) {
    3295           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Cached credentials not available.\n");
    3296           0 :         return EINVAL;
    3297             :     }
    3298             : 
    3299          18 :     tmp_ctx = talloc_new(NULL);
    3300          18 :     if (!tmp_ctx) {
    3301           0 :         return ENOMEM;
    3302             :     }
    3303             : 
    3304          18 :     ret = ldb_transaction_start(domain->sysdb->ldb);
    3305          18 :     if (ret) {
    3306           0 :         talloc_zfree(tmp_ctx);
    3307           0 :         ret = sysdb_error_to_errno(ret);
    3308           0 :         return ret;
    3309             :     }
    3310             : 
    3311          18 :     ret = sysdb_search_user_by_name(tmp_ctx, domain, name, attrs, &ldb_msg);
    3312          18 :     if (ret != EOK) {
    3313           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    3314             :               "sysdb_search_user_by_name failed [%d][%s].\n",
    3315             :                   ret, strerror(ret));
    3316           0 :         if (ret == ENOENT) ret = ERR_ACCOUNT_UNKNOWN;
    3317           0 :         goto done;
    3318             :     }
    3319             : 
    3320             :     /* Check offline_auth_cache_timeout */
    3321          18 :     lastLogin = ldb_msg_find_attr_as_uint64(ldb_msg,
    3322             :                                             SYSDB_LAST_ONLINE_AUTH,
    3323             :                                             0);
    3324             : 
    3325          18 :     ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY,
    3326             :                          CONFDB_PAM_CRED_TIMEOUT, 0, &cred_expiration);
    3327          18 :     if (ret != EOK) {
    3328           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    3329             :               "Failed to read expiration time of offline credentials.\n");
    3330           0 :         goto done;
    3331             :     }
    3332          18 :     DEBUG(SSSDBG_TRACE_ALL, "Offline credentials expiration is [%d] days.\n",
    3333             :               cred_expiration);
    3334             : 
    3335          18 :     if (cred_expiration) {
    3336           3 :         expire_date = lastLogin + (cred_expiration * 86400);
    3337           3 :         if (expire_date < time(NULL)) {
    3338           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "Cached user entry is too old.\n");
    3339           0 :             expire_date = 0;
    3340           0 :             ret = ERR_CACHED_CREDS_EXPIRED;
    3341           0 :             goto done;
    3342             :         }
    3343             :     } else {
    3344          15 :         expire_date = 0;
    3345             :     }
    3346             : 
    3347          18 :     ret = check_failed_login_attempts(cdb, ldb_msg, &failed_login_attempts,
    3348             :                                       &delayed_until);
    3349          18 :     if (ret != EOK) {
    3350           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to check login attempts\n");
    3351           0 :         goto done;
    3352             :     }
    3353             : 
    3354             :     /* TODO: verify user account (disabled, expired ...) */
    3355             : 
    3356          18 :     userhash = ldb_msg_find_attr_as_string(ldb_msg, SYSDB_CACHEDPWD, NULL);
    3357          18 :     if (userhash == NULL || *userhash == '\0') {
    3358           3 :         DEBUG(SSSDBG_CONF_SETTINGS, "Cached credentials not available.\n");
    3359           3 :         ret = ERR_NO_CACHED_CREDS;
    3360           3 :         goto done;
    3361             :     }
    3362             : 
    3363          15 :     ret = s3crypt_sha512(tmp_ctx, password, userhash, &comphash);
    3364          15 :     if (ret) {
    3365           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Failed to create password hash.\n");
    3366           0 :         ret = ERR_INTERNAL;
    3367           0 :         goto done;
    3368             :     }
    3369             : 
    3370          15 :     update_attrs = sysdb_new_attrs(tmp_ctx);
    3371          15 :     if (update_attrs == NULL) {
    3372           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_new_attrs failed.\n");
    3373           0 :         ret = ENOMEM;
    3374           0 :         goto done;
    3375             :     }
    3376             : 
    3377          15 :     if (strcmp(userhash, comphash) == 0
    3378           9 :             || check_for_combined_2fa_password(domain, ldb_msg,
    3379             :                                                password, userhash) == EOK) {
    3380             :         /* TODO: probable good point for audit logging */
    3381           7 :         DEBUG(SSSDBG_CONF_SETTINGS, "Hashes do match!\n");
    3382           7 :         authentication_successful = true;
    3383             : 
    3384           7 :         if (just_check) {
    3385           0 :             ret = EOK;
    3386           0 :             goto done;
    3387             :         }
    3388             : 
    3389           7 :         ret = sysdb_attrs_add_time_t(update_attrs,
    3390             :                                      SYSDB_LAST_LOGIN, time(NULL));
    3391           7 :         if (ret != EOK) {
    3392           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_time_t failed, "
    3393             :                       "but authentication is successful.\n");
    3394           0 :             ret = EOK;
    3395           0 :             goto done;
    3396             :         }
    3397             : 
    3398           7 :         ret = sysdb_attrs_add_uint32(update_attrs,
    3399             :                                      SYSDB_FAILED_LOGIN_ATTEMPTS, 0U);
    3400          14 :         if (ret != EOK) {
    3401           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_uint32 failed, "
    3402             :                       "but authentication is successful.\n");
    3403           0 :             ret = EOK;
    3404           0 :             goto done;
    3405             :         }
    3406             : 
    3407             :     } else {
    3408           8 :         DEBUG(SSSDBG_CONF_SETTINGS, "Authentication failed.\n");
    3409           8 :         authentication_successful = false;
    3410             : 
    3411           8 :         ret = sysdb_attrs_add_time_t(update_attrs,
    3412             :                                      SYSDB_LAST_FAILED_LOGIN,
    3413             :                                      time(NULL));
    3414           8 :         if (ret != EOK) {
    3415           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_time_t failed.\n");
    3416           0 :             goto done;
    3417             :         }
    3418             : 
    3419           8 :         ret = sysdb_attrs_add_uint32(update_attrs,
    3420             :                                      SYSDB_FAILED_LOGIN_ATTEMPTS,
    3421             :                                      ++failed_login_attempts);
    3422           8 :         if (ret != EOK) {
    3423           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_add_uint32 failed.\n");
    3424           0 :             goto done;
    3425             :         }
    3426             :     }
    3427             : 
    3428          15 :     ret = sysdb_set_user_attr(domain, name, update_attrs,
    3429             :                               LDB_FLAG_MOD_REPLACE);
    3430          15 :     if (ret) {
    3431           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    3432             :               "Failed to update Login attempt information!\n");
    3433             :     }
    3434             : 
    3435             : done:
    3436          18 :     if (_expire_date != NULL) {
    3437          18 :         *_expire_date = expire_date;
    3438             :     }
    3439          18 :     if (_delayed_until != NULL) {
    3440          18 :         *_delayed_until = delayed_until;
    3441             :     }
    3442          18 :     if (ret) {
    3443           3 :         ldb_transaction_cancel(domain->sysdb->ldb);
    3444             :     } else {
    3445          15 :         ret = ldb_transaction_commit(domain->sysdb->ldb);
    3446          15 :         ret = sysdb_error_to_errno(ret);
    3447          15 :         if (ret) {
    3448           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to commit transaction!\n");
    3449             :         }
    3450             :     }
    3451          18 :     if (authentication_successful) {
    3452           7 :         ret = EOK;
    3453             :     } else {
    3454          11 :         if (ret == EOK) {
    3455           8 :             ret = ERR_AUTH_FAILED;
    3456             :         }
    3457             :     }
    3458          18 :     talloc_free(tmp_ctx);
    3459          18 :     return ret;
    3460             : }
    3461             : 
    3462           5 : static errno_t sysdb_update_members_ex(struct sss_domain_info *domain,
    3463             :                                        const char *member,
    3464             :                                        enum sysdb_member_type type,
    3465             :                                        const char *const *add_groups,
    3466             :                                        const char *const *del_groups,
    3467             :                                        bool is_dn)
    3468             : {
    3469             :     errno_t ret;
    3470             :     errno_t sret;
    3471             :     int i;
    3472           5 :     bool in_transaction = false;
    3473             : 
    3474           5 :     TALLOC_CTX *tmp_ctx = talloc_new(NULL);
    3475           5 :     if(!tmp_ctx) {
    3476           0 :         return ENOMEM;
    3477             :     }
    3478             : 
    3479           5 :     ret = sysdb_transaction_start(domain->sysdb);
    3480           5 :     if (ret != EOK) {
    3481           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start update transaction\n");
    3482           0 :         goto done;
    3483             :     }
    3484             : 
    3485           5 :     in_transaction = true;
    3486             : 
    3487           5 :     if (add_groups) {
    3488             :         /* Add the user to all add_groups */
    3489           9 :         for (i = 0; add_groups[i]; i++) {
    3490           5 :             ret = sysdb_add_group_member(domain, add_groups[i],
    3491             :                                          member, type, is_dn);
    3492           5 :             if (ret != EOK) {
    3493           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    3494             :                       "Could not add member [%s] to group [%s]. "
    3495             :                           "Skipping.\n", member, add_groups[i]);
    3496             :                 /* Continue on, we should try to finish the rest */
    3497             :             }
    3498             :         }
    3499             :     }
    3500             : 
    3501           5 :     if (del_groups) {
    3502             :         /* Remove the user from all del_groups */
    3503           5 :         for (i = 0; del_groups[i]; i++) {
    3504           3 :             ret = sysdb_remove_group_member(domain, del_groups[i],
    3505             :                                             member, type, is_dn);
    3506           3 :             if (ret != EOK) {
    3507           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    3508             :                       "Could not remove member [%s] from group [%s]. "
    3509             :                           "Skipping\n", member, del_groups[i]);
    3510             :                 /* Continue on, we should try to finish the rest */
    3511             :             }
    3512             :         }
    3513             :     }
    3514             : 
    3515           5 :     ret = sysdb_transaction_commit(domain->sysdb);
    3516           5 :     if (ret != EOK) {
    3517           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
    3518           0 :         goto done;
    3519             :     }
    3520             : 
    3521           5 :     in_transaction = false;
    3522             : 
    3523             : done:
    3524           5 :     if (in_transaction) {
    3525           0 :         sret = sysdb_transaction_cancel(domain->sysdb);
    3526           0 :         if (sret != EOK) {
    3527           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
    3528             :         }
    3529             :     }
    3530           5 :     talloc_free(tmp_ctx);
    3531           5 :     return ret;
    3532             : }
    3533             : 
    3534           3 : errno_t sysdb_update_members(struct sss_domain_info *domain,
    3535             :                              const char *member,
    3536             :                              enum sysdb_member_type type,
    3537             :                              const char *const *add_groups,
    3538             :                              const char *const *del_groups)
    3539             : {
    3540           3 :     return sysdb_update_members_ex(domain, member, type,
    3541             :                                    add_groups, del_groups, false);
    3542             : }
    3543             : 
    3544           2 : errno_t sysdb_update_members_dn(struct sss_domain_info *member_domain,
    3545             :                                 const char *member,
    3546             :                                 enum sysdb_member_type type,
    3547             :                                 const char *const *add_groups,
    3548             :                                 const char *const *del_groups)
    3549             : {
    3550           2 :     return sysdb_update_members_ex(member_domain, member, type,
    3551             :                                    add_groups, del_groups, true);
    3552             : }
    3553             : 
    3554          10 : errno_t sysdb_remove_attrs(struct sss_domain_info *domain,
    3555             :                            const char *name,
    3556             :                            enum sysdb_member_type type,
    3557             :                            char **remove_attrs)
    3558             : {
    3559             :     errno_t ret;
    3560          10 :     errno_t sret = EOK;
    3561          10 :     bool in_transaction = false;
    3562             :     struct ldb_message *msg;
    3563             :     int lret;
    3564             :     size_t i;
    3565             : 
    3566          10 :     msg = ldb_msg_new(NULL);
    3567          10 :     if (!msg) return ENOMEM;
    3568             : 
    3569          10 :     switch(type) {
    3570             :     case SYSDB_MEMBER_USER:
    3571          10 :         msg->dn = sysdb_user_dn(msg, domain, name);
    3572          10 :         break;
    3573             : 
    3574             :     case SYSDB_MEMBER_GROUP:
    3575           0 :         msg->dn = sysdb_group_dn(msg, domain, name);
    3576           0 :         break;
    3577             : 
    3578             :     case SYSDB_MEMBER_NETGROUP:
    3579           0 :         msg->dn = sysdb_netgroup_dn(msg, domain, name);
    3580           0 :         break;
    3581             : 
    3582             :     case SYSDB_MEMBER_SERVICE:
    3583           0 :         msg->dn = sysdb_svc_dn(domain->sysdb, msg, domain->name, name);
    3584           0 :         break;
    3585             :     }
    3586          10 :     if (!msg->dn) {
    3587           0 :         ret = ENOMEM;
    3588           0 :         goto done;
    3589             :     }
    3590             : 
    3591          10 :     ret = sysdb_transaction_start(domain->sysdb);
    3592          10 :     if (ret != EOK) {
    3593           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    3594           0 :         goto done;
    3595             :     }
    3596             : 
    3597          10 :     in_transaction = true;
    3598             : 
    3599          20 :     for (i = 0; remove_attrs[i]; i++) {
    3600             :         /* SYSDB_MEMBEROF is exclusively handled by the memberof plugin */
    3601          10 :         if (strcasecmp(remove_attrs[i], SYSDB_MEMBEROF) == 0) {
    3602           0 :             continue;
    3603             :         }
    3604          10 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Removing attribute [%s] from [%s]\n",
    3605             :                   remove_attrs[i], name);
    3606          10 :         lret = ldb_msg_add_empty(msg, remove_attrs[i],
    3607             :                                  LDB_FLAG_MOD_DELETE, NULL);
    3608          10 :         if (lret != LDB_SUCCESS) {
    3609           0 :             ret = sysdb_error_to_errno(lret);
    3610           0 :             goto done;
    3611             :         }
    3612             : 
    3613             :         /* We need to do individual modifies so that we can
    3614             :          * skip unknown attributes. Otherwise, any nonexistent
    3615             :          * attribute in the sysdb will cause other removals to
    3616             :          * fail.
    3617             :          */
    3618          10 :         lret = ldb_modify(domain->sysdb->ldb, msg);
    3619          10 :         if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
    3620           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    3621             :                   "ldb_modify failed: [%s](%d)[%s]\n",
    3622             :                   ldb_strerror(lret), lret, ldb_errstring(domain->sysdb->ldb));
    3623           0 :             ret = sysdb_error_to_errno(lret);
    3624           0 :             goto done;
    3625             :         }
    3626             : 
    3627             :         /* Remove this attribute and move on to the next one */
    3628          10 :         ldb_msg_remove_attr(msg, remove_attrs[i]);
    3629             :     }
    3630             : 
    3631          10 :     ret = sysdb_transaction_commit(domain->sysdb);
    3632          10 :     if (ret != EOK) {
    3633           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
    3634           0 :         goto done;
    3635             :     }
    3636             : 
    3637          10 :     in_transaction = false;
    3638             : 
    3639          10 :     ret = EOK;
    3640             : done:
    3641          10 :     if (in_transaction) {
    3642           0 :         sret = sysdb_transaction_cancel(domain->sysdb);
    3643           0 :         if (sret != EOK) {
    3644           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
    3645             :         }
    3646             :     }
    3647          10 :     talloc_free(msg);
    3648          10 :     return ret;
    3649             : }
    3650             : 
    3651          26 : static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx,
    3652             :                                    struct sss_domain_info *domain,
    3653             :                                    const char *filter_tmpl,
    3654             :                                    const char *str,
    3655             :                                    const char **attrs,
    3656             :                                    struct ldb_result **_res)
    3657             : {
    3658             :     TALLOC_CTX *tmp_ctx;
    3659          26 :     const char *def_attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM,
    3660             :                                 ORIGINALAD_PREFIX SYSDB_NAME,
    3661             :                                 SYSDB_DEFAULT_ATTRS,
    3662             :                                 NULL };
    3663             :     struct ldb_dn *basedn;
    3664             :     int ret;
    3665          26 :     struct ldb_result *res = NULL;
    3666             : 
    3667          26 :     tmp_ctx = talloc_new(NULL);
    3668          26 :     if (!tmp_ctx) {
    3669           0 :         return ENOMEM;
    3670             :     }
    3671             : 
    3672          26 :     basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_DOM_BASE,
    3673             :                             domain->name);
    3674          26 :     if (basedn == NULL) {
    3675           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
    3676           0 :         ret = ENOMEM;
    3677           0 :         goto done;
    3678             :     }
    3679             : 
    3680          26 :     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
    3681             :                      basedn, LDB_SCOPE_SUBTREE, attrs?attrs:def_attrs,
    3682             :                      filter_tmpl, str);
    3683          26 :     if (ret != EOK) {
    3684           0 :         ret = sysdb_error_to_errno(ret);
    3685           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n");
    3686           0 :         goto done;
    3687             :     }
    3688             : 
    3689          26 :     if (res->count > 1) {
    3690           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Search for [%s]  with filter [%s] " \
    3691             :                                    "returned more than one object.\n",
    3692             :                                    str, filter_tmpl);
    3693           0 :         ret = EINVAL;
    3694           0 :         goto done;
    3695          26 :     } else if (res->count == 0) {
    3696          15 :         ret = ENOENT;
    3697          15 :         goto done;
    3698             :     }
    3699             : 
    3700          11 :     *_res = talloc_steal(mem_ctx, res);
    3701             : 
    3702             : done:
    3703          26 :     if (ret == ENOENT) {
    3704          15 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry.\n");
    3705          11 :     } else if (ret) {
    3706           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    3707             :     }
    3708             : 
    3709          26 :     talloc_zfree(tmp_ctx);
    3710          26 :     return ret;
    3711             : }
    3712             : 
    3713           8 : errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
    3714             :                                    struct sss_domain_info *domain,
    3715             :                                    const char *sid_str,
    3716             :                                    const char **attrs,
    3717             :                                    struct ldb_result **res)
    3718             : {
    3719           8 :     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
    3720             :                                            sid_str, attrs, res);
    3721             : }
    3722             : 
    3723           4 : errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
    3724             :                                     struct sss_domain_info *domain,
    3725             :                                     const char *uuid_str,
    3726             :                                     const char **attrs,
    3727             :                                     struct ldb_result **res)
    3728             : {
    3729           4 :     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_UUID_FILTER,
    3730             :                                            uuid_str, attrs, res);
    3731             : }
    3732             : 
    3733          14 : errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
    3734             :                                     struct sss_domain_info *domain,
    3735             :                                     const char *cert,
    3736             :                                     const char **attrs,
    3737             :                                     struct ldb_result **res)
    3738             : {
    3739             :     int ret;
    3740             :     char *user_filter;
    3741             : 
    3742          14 :     ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT,
    3743             :                                          &user_filter);
    3744          14 :     if (ret != EOK) {
    3745           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
    3746           0 :         return ret;
    3747             :     }
    3748             : 
    3749          14 :     ret = sysdb_search_object_by_str_attr(mem_ctx, domain,
    3750             :                                           SYSDB_USER_CERT_FILTER,
    3751             :                                           user_filter, attrs, res);
    3752          14 :     talloc_free(user_filter);
    3753             : 
    3754          14 :     return ret;
    3755             : }
    3756             : 
    3757          14 : errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
    3758             :                                   struct sss_domain_info *domain,
    3759             :                                   const char *cert,
    3760             :                                   struct ldb_result **res)
    3761             : {
    3762          14 :     const char *user_attrs[] = SYSDB_PW_ATTRS;
    3763             : 
    3764          14 :     return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
    3765             : }
    3766             : 
    3767           0 : errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
    3768             :                                   struct sss_domain_info *dom,
    3769             :                                   const char *group_name,
    3770             :                                   const char ***_sids,
    3771             :                                   const char ***_dns,
    3772             :                                   size_t *_n)
    3773             : {
    3774             :     errno_t ret;
    3775             :     size_t i, m_count;
    3776             :     TALLOC_CTX *tmp_ctx;
    3777             :     struct ldb_message *msg;
    3778             :     struct ldb_message **members;
    3779           0 :     const char *attrs[] = { SYSDB_SID_STR, NULL };
    3780           0 :     const char **sids = NULL, **dns = NULL;
    3781           0 :     size_t n = 0;
    3782             : 
    3783           0 :     tmp_ctx = talloc_new(NULL);
    3784           0 :     if (tmp_ctx == NULL) {
    3785           0 :         return ENOMEM;
    3786             :     }
    3787             : 
    3788           0 :     ret = sysdb_search_group_by_name(tmp_ctx, dom, group_name, NULL, &msg);
    3789           0 :     if (ret != EOK) {
    3790           0 :         goto done;
    3791             :     }
    3792             : 
    3793             :     /* Get sid_str attribute of all elemets pointed to by group members */
    3794           0 :     ret = sysdb_asq_search(tmp_ctx, dom, msg->dn, NULL, SYSDB_MEMBER, attrs,
    3795             :                            &m_count, &members);
    3796           0 :     if (ret != EOK) {
    3797           0 :         goto done;
    3798             :     }
    3799             : 
    3800           0 :     sids = talloc_array(tmp_ctx, const char*, m_count);
    3801           0 :     if (sids == NULL) {
    3802           0 :         ret = ENOMEM;
    3803           0 :         goto done;
    3804             :     }
    3805             : 
    3806           0 :     dns = talloc_array(tmp_ctx, const char*, m_count);
    3807           0 :     if (dns == NULL) {
    3808           0 :         ret = ENOMEM;
    3809           0 :         goto done;
    3810             :     }
    3811             : 
    3812           0 :     for (i=0; i < m_count; i++) {
    3813             :         const char *sidstr;
    3814             : 
    3815           0 :         sidstr = ldb_msg_find_attr_as_string(members[i], SYSDB_SID_STR, NULL);
    3816             : 
    3817           0 :         if (sidstr != NULL) {
    3818           0 :             sids[n] = talloc_steal(sids, sidstr);
    3819             : 
    3820           0 :             dns[n] = talloc_steal(dns, ldb_dn_get_linearized(members[i]->dn));
    3821           0 :             if (dns[n] == NULL) {
    3822           0 :                 ret = ENOMEM;
    3823           0 :                 goto done;
    3824             :             }
    3825           0 :             n++;
    3826             :         }
    3827             :     }
    3828             : 
    3829           0 :     if (n == 0) {
    3830           0 :         ret = ENOENT;
    3831           0 :         goto done;
    3832             :     }
    3833             : 
    3834           0 :     *_n = n;
    3835           0 :     *_sids = talloc_steal(mem_ctx, sids);
    3836           0 :     *_dns = talloc_steal(mem_ctx, dns);
    3837             : 
    3838           0 :     ret = EOK;
    3839             : 
    3840             : done:
    3841           0 :     if (ret == ENOENT) {
    3842           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n");
    3843           0 :     } else if (ret) {
    3844           0 :         DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
    3845             :     }
    3846           0 :     talloc_free(tmp_ctx);
    3847           0 :     return ret;
    3848             : }
    3849             : 
    3850           7 : errno_t sysdb_handle_original_uuid(const char *orig_name,
    3851             :                                    struct sysdb_attrs *src_attrs,
    3852             :                                    const char *src_name,
    3853             :                                    struct sysdb_attrs *dest_attrs,
    3854             :                                    const char *dest_name)
    3855             : {
    3856             :     int ret;
    3857             :     struct ldb_message_element *el;
    3858             :     char guid_str_buf[GUID_STR_BUF_SIZE];
    3859             : 
    3860           7 :     if (orig_name == NULL) {
    3861             :         /* This provider doesn't handle UUIDs */
    3862           2 :         return ENOENT;
    3863             :     }
    3864             : 
    3865           5 :     if (src_attrs == NULL || src_name == NULL
    3866           4 :             || dest_attrs == NULL || dest_name == NULL) {
    3867           1 :         return EINVAL;
    3868             :     }
    3869             : 
    3870           4 :     ret = sysdb_attrs_get_el_ext(src_attrs, src_name, false, &el);
    3871           4 :     if (ret != EOK) {
    3872           1 :         if (ret != ENOENT) {
    3873           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el failed.\n");
    3874             :         }
    3875           1 :         return ret;
    3876             :     }
    3877             : 
    3878           3 :     if (el->num_values != 1) {
    3879           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    3880             :               "Found more than one UUID value, using the first.\n");
    3881             :     }
    3882             : 
    3883             :     /* Check if we got a binary AD objectGUID */
    3884           3 :     if (el->values[0].length == GUID_BIN_LENGTH
    3885           1 :             && strcasecmp(orig_name, "objectGUID") == 0) {
    3886           1 :         ret = guid_blob_to_string_buf(el->values[0].data, guid_str_buf,
    3887             :                                       GUID_STR_BUF_SIZE);
    3888           1 :         if (ret != EOK) {
    3889           0 :             DEBUG(SSSDBG_OP_FAILURE, "guid_blob_to_string_buf failed.\n");
    3890           0 :             return ret;
    3891             :         }
    3892             : 
    3893           1 :         ret = sysdb_attrs_add_string(dest_attrs, dest_name, guid_str_buf);
    3894             :     } else {
    3895           2 :         ret = sysdb_attrs_add_string(dest_attrs, dest_name,
    3896           2 :                                      (const char *)el->values[0].data);
    3897             :     }
    3898             : 
    3899           3 :     if (ret != EOK) {
    3900           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
    3901           0 :         return ret;;
    3902             :     }
    3903             : 
    3904           3 :     return EOK;
    3905             : }
    3906             : 
    3907             : /* Mark entry as expired */
    3908           2 : errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom,
    3909             :                                            struct ldb_dn *ldbdn)
    3910             : {
    3911             :     struct ldb_message *msg;
    3912             :     errno_t ret;
    3913             :     TALLOC_CTX *tmp_ctx;
    3914             : 
    3915           2 :     tmp_ctx = talloc_new(NULL);
    3916           2 :     if (tmp_ctx == NULL) {
    3917           0 :         return ENOMEM;
    3918             :     }
    3919             : 
    3920           2 :     msg = ldb_msg_new(tmp_ctx);
    3921           2 :     if (msg == NULL) {
    3922           0 :         ret = ENOMEM;
    3923           0 :         goto done;
    3924             :     }
    3925             : 
    3926           2 :     msg->dn = ldbdn;
    3927             : 
    3928           2 :     ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE,
    3929             :                             LDB_FLAG_MOD_REPLACE, NULL);
    3930           2 :     if (ret != LDB_SUCCESS) {
    3931           0 :         ret = sysdb_error_to_errno(ret);
    3932           0 :         goto done;
    3933             :     }
    3934             : 
    3935           2 :     ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1");
    3936           2 :     if (ret != LDB_SUCCESS) {
    3937           0 :         ret = sysdb_error_to_errno(ret);
    3938           0 :         goto done;
    3939             :     }
    3940             : 
    3941           2 :     ret = ldb_modify(dom->sysdb->ldb, msg);
    3942           2 :     if (ret != LDB_SUCCESS) {
    3943           0 :         ret = sysdb_error_to_errno(ret);
    3944           0 :         goto done;
    3945             :     }
    3946             : 
    3947           2 :     ret = EOK;
    3948             : 
    3949             : done:
    3950           2 :     talloc_free(tmp_ctx);
    3951           2 :     return ret;
    3952             : }
    3953             : 
    3954           0 : errno_t sysdb_mark_entry_as_expired_ldb_val(struct sss_domain_info *dom,
    3955             :                                             struct ldb_val *dn_val)
    3956             : {
    3957             :     struct ldb_dn *ldbdn;
    3958             :     errno_t ret;
    3959             :     TALLOC_CTX *tmp_ctx;
    3960             : 
    3961           0 :     tmp_ctx = talloc_new(NULL);
    3962           0 :     if (tmp_ctx == NULL) {
    3963           0 :         return ENOMEM;
    3964             :     }
    3965             : 
    3966           0 :     ldbdn = ldb_dn_from_ldb_val(tmp_ctx, dom->sysdb->ldb, dn_val);
    3967           0 :     if (ldbdn == NULL) {
    3968           0 :         ret = ENOMEM;
    3969           0 :         goto done;
    3970             :     }
    3971             : 
    3972           0 :     ret = sysdb_mark_entry_as_expired_ldb_dn(dom, ldbdn);
    3973             : 
    3974             : done:
    3975           0 :     talloc_free(tmp_ctx);
    3976           0 :     return ret;
    3977             : }

Generated by: LCOV version 1.10