LCOV - code coverage report
Current view: top level - providers/proxy - proxy_id.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 733 0.0 %
Date: 2016-06-29 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     proxy_id.c
       5             : 
       6             :     Authors:
       7             :         Stephen Gallagher <sgallagh@redhat.com>
       8             : 
       9             :     Copyright (C) 2010 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "config.h"
      26             : 
      27             : #include "util/sss_format.h"
      28             : #include "util/strtonum.h"
      29             : #include "providers/proxy/proxy.h"
      30             : 
      31             : /* =Getpwnam-wrapper======================================================*/
      32             : 
      33             : static int save_user(struct sss_domain_info *domain,
      34             :                      bool lowercase, struct passwd *pwd, const char *real_name,
      35             :                      const char *alias, uint64_t cache_timeout);
      36             : 
      37             : static int
      38             : handle_getpw_result(enum nss_status status, struct passwd *pwd,
      39             :                     struct sss_domain_info *dom, bool *del_user);
      40             : 
      41             : static int
      42             : delete_user(struct sss_domain_info *domain,
      43             :             const char *name, uid_t uid);
      44             : 
      45           0 : static int get_pw_name(struct proxy_id_ctx *ctx,
      46             :                        struct sss_domain_info *dom,
      47             :                        const char *name)
      48             : {
      49             :     TALLOC_CTX *tmpctx;
      50             :     struct passwd *pwd;
      51             :     enum nss_status status;
      52             :     char *buffer;
      53             :     size_t buflen;
      54             :     int ret;
      55             :     uid_t uid;
      56             :     bool del_user;
      57           0 :     struct ldb_result *cached_pwd = NULL;
      58           0 :     const char *real_name = NULL;
      59             : 
      60           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Searching user by name (%s)\n", name);
      61             : 
      62           0 :     tmpctx = talloc_new(NULL);
      63           0 :     if (!tmpctx) {
      64           0 :         return ENOMEM;
      65             :     }
      66             : 
      67           0 :     pwd = talloc_zero(tmpctx, struct passwd);
      68           0 :     if (!pwd) {
      69           0 :         ret = ENOMEM;
      70           0 :         goto done;
      71             :     }
      72             : 
      73           0 :     buflen = DEFAULT_BUFSIZE;
      74           0 :     buffer = talloc_size(tmpctx, buflen);
      75           0 :     if (!buffer) {
      76           0 :         ret = ENOMEM;
      77           0 :         goto done;
      78             :     }
      79             : 
      80             :     /* FIXME: should we move this call outside the transaction to keep the
      81             :      * transaction as short as possible ? */
      82           0 :     status = ctx->ops.getpwnam_r(name, pwd, buffer, buflen, &ret);
      83           0 :     ret = handle_getpw_result(status, pwd, dom, &del_user);
      84           0 :     if (ret) {
      85           0 :         DEBUG(SSSDBG_OP_FAILURE,
      86             :               "getpwnam failed [%d]: %s\n", ret, strerror(ret));
      87           0 :         goto done;
      88             :     }
      89             : 
      90           0 :     if (del_user) {
      91           0 :         ret = delete_user(dom, name, 0);
      92           0 :         goto done;
      93             :     }
      94             : 
      95           0 :     uid = pwd->pw_uid;
      96             : 
      97             :     /* Canonicalize the username in case it was actually an alias */
      98             : 
      99           0 :     if (ctx->fast_alias == true) {
     100           0 :         ret = sysdb_getpwuid(tmpctx, dom, uid, &cached_pwd);
     101           0 :         if (ret != EOK) {
     102             :             /* Non-fatal, attempt to canonicalize online */
     103           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Request to cache failed [%d]: %s\n",
     104             :                   ret, strerror(ret));
     105             :         }
     106             : 
     107           0 :         if (ret == EOK && cached_pwd->count == 1) {
     108           0 :             real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0],
     109             :                                                     SYSDB_NAME, NULL);
     110           0 :             if (!real_name) {
     111           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cached user has no name?\n");
     112             :             }
     113             :         }
     114             :     }
     115             : 
     116           0 :     if (real_name == NULL) {
     117           0 :         memset(buffer, 0, buflen);
     118             : 
     119           0 :         status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret);
     120           0 :         ret = handle_getpw_result(status, pwd, dom, &del_user);
     121           0 :         if (ret) {
     122           0 :             DEBUG(SSSDBG_OP_FAILURE,
     123             :                 "getpwuid failed [%d]: %s\n", ret, strerror(ret));
     124           0 :             goto done;
     125             :         }
     126             : 
     127           0 :         real_name = pwd->pw_name;
     128             :     }
     129             : 
     130           0 :     if (del_user) {
     131           0 :         ret = delete_user(dom, name, uid);
     132           0 :         goto done;
     133             :     }
     134             : 
     135             :     /* Both lookups went fine, we can save the user now */
     136           0 :     ret = save_user(dom, !dom->case_sensitive, pwd,
     137           0 :                     real_name, name, dom->user_timeout);
     138             : 
     139             : done:
     140           0 :     talloc_zfree(tmpctx);
     141           0 :     if (ret) {
     142           0 :         DEBUG(SSSDBG_OP_FAILURE,
     143             :               "proxy -> getpwnam_r failed for '%s' <%d>: %s\n",
     144             :                name, ret, strerror(ret));
     145             :     }
     146           0 :     return ret;
     147             : }
     148             : 
     149             : static int
     150           0 : handle_getpw_result(enum nss_status status, struct passwd *pwd,
     151             :                     struct sss_domain_info *dom, bool *del_user)
     152             : {
     153           0 :     int ret = EOK;
     154             : 
     155           0 :     if (!del_user) {
     156           0 :         return EINVAL;
     157             :     }
     158           0 :     *del_user = false;
     159             : 
     160           0 :     switch (status) {
     161             :     case NSS_STATUS_NOTFOUND:
     162             : 
     163           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "User not found.\n");
     164           0 :         *del_user = true;
     165           0 :         break;
     166             : 
     167             :     case NSS_STATUS_SUCCESS:
     168             : 
     169           0 :         DEBUG(SSSDBG_TRACE_FUNC, "User found: (%s, %"SPRIuid", %"SPRIgid")\n",
     170             :               pwd->pw_name, pwd->pw_uid, pwd->pw_gid);
     171             : 
     172             :         /* uid=0 or gid=0 are invalid values */
     173             :         /* also check that the id is in the valid range for this domain */
     174           0 :         if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) ||
     175           0 :             OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) {
     176             : 
     177           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     178             :                   "User filtered out! (id out of range)\n");
     179           0 :             *del_user = true;
     180           0 :             break;
     181             :         }
     182           0 :         break;
     183             : 
     184             :     case NSS_STATUS_UNAVAIL:
     185           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     186             :               "Remote back end is not available. Entering offline mode\n");
     187           0 :         ret = ENXIO;
     188           0 :         break;
     189             : 
     190             :     default:
     191           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown return code %d\n", status);
     192           0 :         ret = EIO;
     193           0 :         break;
     194             :     }
     195             : 
     196           0 :     return ret;
     197             : }
     198             : 
     199             : static int
     200           0 : delete_user(struct sss_domain_info *domain,
     201             :             const char *name, uid_t uid)
     202             : {
     203           0 :     int ret = EOK;
     204             : 
     205           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     206             :           "User %s does not exist (or is invalid) on remote server,"
     207             :            " deleting!\n", name);
     208           0 :     ret = sysdb_delete_user(domain, name, uid);
     209           0 :     if (ret == ENOENT) {
     210           0 :         ret = EOK;
     211             :     }
     212             : 
     213           0 :     return ret;
     214             : }
     215             : 
     216           0 : static int save_user(struct sss_domain_info *domain,
     217             :                      bool lowercase, struct passwd *pwd, const char *real_name,
     218             :                      const char *alias, uint64_t cache_timeout)
     219             : {
     220             :     const char *shell;
     221             :     const char *gecos;
     222           0 :     struct sysdb_attrs *attrs = NULL;
     223             :     errno_t ret;
     224             :     const char *cased_alias;
     225           0 :     const char *lc_pw_name = NULL;
     226             : 
     227           0 :     if (pwd->pw_shell && pwd->pw_shell[0] != '\0') {
     228           0 :         shell = pwd->pw_shell;
     229             :     } else {
     230           0 :         shell = NULL;
     231             :     }
     232             : 
     233           0 :     if (pwd->pw_gecos && pwd->pw_gecos[0] != '\0') {
     234           0 :         gecos = pwd->pw_gecos;
     235             :     } else {
     236           0 :         gecos = NULL;
     237             :     }
     238             : 
     239           0 :     if (lowercase || alias) {
     240           0 :         attrs = sysdb_new_attrs(NULL);
     241           0 :         if (!attrs) {
     242           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n");
     243           0 :             ret = ENOMEM;
     244           0 :             goto done;
     245             :         }
     246             :     }
     247             : 
     248           0 :     if (lowercase) {
     249           0 :         lc_pw_name = sss_tc_utf8_str_tolower(attrs, pwd->pw_name);
     250           0 :         if (lc_pw_name == NULL) {
     251           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
     252           0 :             ret = ENOMEM;
     253           0 :             goto done;
     254             :         }
     255             : 
     256           0 :         ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_pw_name);
     257           0 :         if (ret) {
     258           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
     259           0 :             ret = ENOMEM;
     260           0 :             goto done;
     261             :         }
     262             : 
     263             :     }
     264             : 
     265           0 :     if (alias) {
     266           0 :         cased_alias = sss_get_cased_name(attrs, alias, !lowercase);
     267           0 :         if (!cased_alias) {
     268           0 :             ret = ENOMEM;
     269           0 :             goto done;
     270             :         }
     271             : 
     272             :         /* Add the alias only if it differs from lowercased pw_name */
     273           0 :         if (lc_pw_name == NULL || strcmp(cased_alias, lc_pw_name) != 0) {
     274           0 :             ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias);
     275           0 :             if (ret) {
     276           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
     277           0 :                 goto done;
     278             :             }
     279             :         }
     280             :     }
     281             : 
     282           0 :     ret = sysdb_store_user(domain,
     283             :                            real_name,
     284           0 :                            pwd->pw_passwd,
     285             :                            pwd->pw_uid,
     286             :                            pwd->pw_gid,
     287             :                            gecos,
     288           0 :                            pwd->pw_dir,
     289             :                            shell,
     290             :                            NULL,
     291             :                            attrs,
     292             :                            NULL,
     293             :                            cache_timeout,
     294             :                            0);
     295           0 :     if (ret) {
     296           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not add user to cache\n");
     297           0 :         goto done;
     298             :     }
     299             : 
     300             : done:
     301           0 :     talloc_zfree(attrs);
     302           0 :     return ret;
     303             : }
     304             : 
     305             : /* =Getpwuid-wrapper======================================================*/
     306             : 
     307           0 : static int get_pw_uid(struct proxy_id_ctx *ctx,
     308             :                       struct sss_domain_info *dom,
     309             :                       uid_t uid)
     310             : {
     311             :     TALLOC_CTX *tmpctx;
     312             :     struct passwd *pwd;
     313             :     enum nss_status status;
     314             :     char *buffer;
     315             :     size_t buflen;
     316           0 :     bool del_user = false;
     317             :     int ret;
     318             : 
     319           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Searching user by uid (%"SPRIuid")\n", uid);
     320             : 
     321           0 :     tmpctx = talloc_new(NULL);
     322           0 :     if (!tmpctx) {
     323           0 :         return ENOMEM;
     324             :     }
     325             : 
     326           0 :     pwd = talloc_zero(tmpctx, struct passwd);
     327           0 :     if (!pwd) {
     328           0 :         ret = ENOMEM;
     329           0 :         goto done;
     330             :     }
     331             : 
     332           0 :     buflen = DEFAULT_BUFSIZE;
     333           0 :     buffer = talloc_size(tmpctx, buflen);
     334           0 :     if (!buffer) {
     335           0 :         ret = ENOMEM;
     336           0 :         goto done;
     337             :     }
     338             : 
     339           0 :     status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret);
     340           0 :     ret = handle_getpw_result(status, pwd, dom, &del_user);
     341           0 :     if (ret) {
     342           0 :         DEBUG(SSSDBG_OP_FAILURE,
     343             :               "getpwuid failed [%d]: %s\n", ret, strerror(ret));
     344           0 :         goto done;
     345             :     }
     346             : 
     347           0 :     if (del_user) {
     348           0 :         ret = delete_user(dom, NULL, uid);
     349           0 :         goto done;
     350             :     }
     351             : 
     352           0 :     ret = save_user(dom, !dom->case_sensitive, pwd,
     353           0 :                     pwd->pw_name, NULL, dom->user_timeout);
     354             : 
     355             : done:
     356           0 :     talloc_zfree(tmpctx);
     357           0 :     if (ret) {
     358           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     359             :               "proxy -> getpwuid_r failed for '%"SPRIuid"' <%d>: %s\n",
     360             :                uid, ret, strerror(ret));
     361             :     }
     362           0 :     return ret;
     363             : }
     364             : 
     365             : /* =Getpwent-wrapper======================================================*/
     366             : 
     367           0 : static int enum_users(TALLOC_CTX *mem_ctx,
     368             :                       struct proxy_id_ctx *ctx,
     369             :                       struct sysdb_ctx *sysdb,
     370             :                       struct sss_domain_info *dom)
     371             : {
     372             :     TALLOC_CTX *tmpctx;
     373           0 :     bool in_transaction = false;
     374             :     struct passwd *pwd;
     375             :     enum nss_status status;
     376             :     size_t buflen;
     377             :     char *buffer;
     378             :     char *newbuf;
     379             :     int ret;
     380             :     errno_t sret;
     381             :     bool again;
     382             : 
     383           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Enumerating users\n");
     384             : 
     385           0 :     tmpctx = talloc_new(mem_ctx);
     386           0 :     if (!tmpctx) {
     387           0 :         return ENOMEM;
     388             :     }
     389             : 
     390           0 :     pwd = talloc_zero(tmpctx, struct passwd);
     391           0 :     if (!pwd) {
     392           0 :         ret = ENOMEM;
     393           0 :         goto done;
     394             :     }
     395             : 
     396           0 :     buflen = DEFAULT_BUFSIZE;
     397           0 :     buffer = talloc_size(tmpctx, buflen);
     398           0 :     if (!buffer) {
     399           0 :         ret = ENOMEM;
     400           0 :         goto done;
     401             :     }
     402             : 
     403           0 :     ret = sysdb_transaction_start(sysdb);
     404           0 :     if (ret) {
     405           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
     406           0 :         goto done;
     407             :     }
     408           0 :     in_transaction = true;
     409             : 
     410           0 :     status = ctx->ops.setpwent();
     411           0 :     if (status != NSS_STATUS_SUCCESS) {
     412           0 :         ret = EIO;
     413           0 :         goto done;
     414             :     }
     415             : 
     416             :     do {
     417           0 :         again = false;
     418             : 
     419             :         /* always zero out the pwd structure */
     420           0 :         memset(pwd, 0, sizeof(struct passwd));
     421             : 
     422             :         /* get entry */
     423           0 :         status = ctx->ops.getpwent_r(pwd, buffer, buflen, &ret);
     424             : 
     425           0 :         switch (status) {
     426             :             case NSS_STATUS_TRYAGAIN:
     427             :                 /* buffer too small ? */
     428           0 :                 if (buflen < MAX_BUF_SIZE) {
     429           0 :                     buflen *= 2;
     430             :                 }
     431           0 :                 if (buflen > MAX_BUF_SIZE) {
     432           0 :                     buflen = MAX_BUF_SIZE;
     433             :                 }
     434           0 :                 newbuf = talloc_realloc_size(tmpctx, buffer, buflen);
     435           0 :                 if (!newbuf) {
     436           0 :                     ret = ENOMEM;
     437           0 :                     goto done;
     438             :                 }
     439           0 :                 buffer = newbuf;
     440           0 :                 again = true;
     441           0 :                 break;
     442             : 
     443             :             case NSS_STATUS_NOTFOUND:
     444             : 
     445             :                 /* we are done here */
     446           0 :                 DEBUG(SSSDBG_TRACE_LIBS, "Enumeration completed.\n");
     447             : 
     448           0 :                 ret = sysdb_transaction_commit(sysdb);
     449           0 :                 if (ret != EOK) {
     450           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
     451           0 :                     goto done;
     452             :                 }
     453           0 :                 in_transaction = false;
     454           0 :                 break;
     455             : 
     456             :             case NSS_STATUS_SUCCESS:
     457             : 
     458           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
     459             :                       "User found (%s, %"SPRIuid", %"SPRIgid")\n",
     460             :                        pwd->pw_name, pwd->pw_uid, pwd->pw_gid);
     461             : 
     462             :                 /* uid=0 or gid=0 are invalid values */
     463             :                 /* also check that the id is in the valid range for this domain
     464             :                  */
     465           0 :                 if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) ||
     466           0 :                     OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) {
     467             : 
     468           0 :                     DEBUG(SSSDBG_OP_FAILURE, "User [%s] filtered out! (id out"
     469             :                         " of range)\n", pwd->pw_name);
     470             : 
     471           0 :                     again = true;
     472           0 :                     break;
     473             :                 }
     474             : 
     475           0 :                 ret = save_user(dom, !dom->case_sensitive, pwd,
     476           0 :                         pwd->pw_name, NULL, dom->user_timeout);
     477           0 :                 if (ret) {
     478             :                     /* Do not fail completely on errors.
     479             :                      * Just report the failure to save and go on */
     480           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Failed to store user %s."
     481             :                                 " Ignoring.\n", pwd->pw_name);
     482             :                 }
     483           0 :                 again = true;
     484           0 :                 break;
     485             : 
     486             :             case NSS_STATUS_UNAVAIL:
     487             :                 /* "remote" backend unavailable. Enter offline mode */
     488           0 :                 ret = ENXIO;
     489           0 :                 break;
     490             : 
     491             :             default:
     492           0 :                 ret = EIO;
     493           0 :                 DEBUG(SSSDBG_OP_FAILURE, "proxy -> getpwent_r failed (%d)[%s]"
     494             :                             "\n", ret, strerror(ret));
     495           0 :                 break;
     496             :         }
     497           0 :     } while (again);
     498             : 
     499             : done:
     500           0 :     talloc_zfree(tmpctx);
     501           0 :     if (in_transaction) {
     502           0 :         sret = sysdb_transaction_cancel(sysdb);
     503           0 :         if (sret != EOK) {
     504           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
     505             :         }
     506             :     }
     507           0 :     ctx->ops.endpwent();
     508           0 :     return ret;
     509             : }
     510             : 
     511             : /* =Save-group-utilities=================================================*/
     512             : #define DEBUG_GR_MEM(level, grp) \
     513             :     do { \
     514             :         if (DEBUG_IS_SET(level)) { \
     515             :             if (!grp->gr_mem || !grp->gr_mem[0]) { \
     516             :                 DEBUG(level, "Group %s has no members!\n", \
     517             :                               grp->gr_name); \
     518             :             } else { \
     519             :                 int i = 0; \
     520             :                 while (grp->gr_mem[i]) { \
     521             :                     /* count */ \
     522             :                     i++; \
     523             :                 } \
     524             :                 DEBUG(level, "Group %s has %d members!\n", \
     525             :                               grp->gr_name, i); \
     526             :             } \
     527             :         } \
     528             :     } while(0)
     529             : 
     530             : 
     531             : static errno_t proxy_process_missing_users(struct sysdb_ctx *sysdb,
     532             :                                            struct sss_domain_info *domain,
     533             :                                            struct sysdb_attrs *group_attrs,
     534             :                                            struct group *grp,
     535             :                                            time_t now);
     536           0 : static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom,
     537             :                       struct group *grp, const char *real_name,
     538             :                       const char *alias, uint64_t cache_timeout)
     539             : {
     540             :     errno_t ret, sret;
     541           0 :     struct sysdb_attrs *attrs = NULL;
     542             :     const char *cased_alias;
     543           0 :     const char *lc_gr_name = NULL;
     544             :     TALLOC_CTX *tmp_ctx;
     545           0 :     time_t now = time(NULL);
     546           0 :     bool in_transaction = false;
     547             : 
     548           0 :     tmp_ctx = talloc_new(NULL);
     549           0 :     if (!tmp_ctx) {
     550           0 :         return ENOMEM;
     551             :     }
     552             : 
     553           0 :     DEBUG_GR_MEM(SSSDBG_TRACE_LIBS, grp);
     554             : 
     555           0 :     ret = sysdb_transaction_start(sysdb);
     556           0 :     if (ret != EOK) {
     557           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
     558           0 :         goto done;
     559             :     }
     560           0 :     in_transaction = true;
     561             : 
     562           0 :     if (grp->gr_mem && grp->gr_mem[0]) {
     563           0 :         attrs = sysdb_new_attrs(tmp_ctx);
     564           0 :         if (!attrs) {
     565           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n");
     566           0 :             ret = ENOMEM;
     567           0 :             goto done;
     568             :         }
     569             : 
     570           0 :         ret = sysdb_attrs_users_from_str_list(
     571           0 :                 attrs, SYSDB_MEMBER, dom->name,
     572           0 :                 (const char *const *)grp->gr_mem);
     573           0 :         if (ret) {
     574           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add group members\n");
     575           0 :             goto done;
     576             :         }
     577             : 
     578             :         /* Create ghost users */
     579           0 :         ret = proxy_process_missing_users(sysdb, dom, attrs, grp, now);
     580           0 :         if (ret != EOK) {
     581           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add missing members\n");
     582           0 :             goto done;
     583             :         }
     584             :     }
     585             : 
     586           0 :     if (dom->case_sensitive == false || alias) {
     587           0 :         if (!attrs) {
     588           0 :             attrs = sysdb_new_attrs(tmp_ctx);
     589           0 :             if (!attrs) {
     590           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n");
     591           0 :                 ret = ENOMEM;
     592           0 :                 goto done;
     593             :             }
     594             :         }
     595             :     }
     596             : 
     597           0 :     if (dom->case_sensitive == false) {
     598           0 :         lc_gr_name = sss_tc_utf8_str_tolower(attrs, grp->gr_name);
     599           0 :         if (lc_gr_name == NULL) {
     600           0 :             DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n");
     601           0 :             ret = ENOMEM;
     602           0 :             goto done;
     603             :         }
     604             : 
     605           0 :         ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_gr_name);
     606           0 :         if (ret != EOK) {
     607           0 :             goto done;
     608             :         }
     609             :     }
     610             : 
     611           0 :     if (alias) {
     612           0 :         cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive);
     613           0 :         if (!cased_alias) {
     614           0 :             ret = ENOMEM;
     615           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
     616           0 :             goto done;
     617             :         }
     618             : 
     619           0 :         if (lc_gr_name == NULL || strcmp(cased_alias, lc_gr_name)) {
     620           0 :             ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias);
     621           0 :             if (ret) {
     622           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n");
     623           0 :                 goto done;
     624             :             }
     625             :         }
     626             :     }
     627             : 
     628           0 :     ret = sysdb_store_group(dom,
     629             :                             real_name,
     630             :                             grp->gr_gid,
     631             :                             attrs,
     632             :                             cache_timeout,
     633             :                             now);
     634           0 :     if (ret) {
     635           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not add group to cache\n");
     636           0 :         goto done;
     637             :     }
     638             : 
     639           0 :     ret = sysdb_transaction_commit(sysdb);
     640           0 :     if (ret != EOK) {
     641           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     642             :               "Could not commit transaction: [%s]\n",
     643             :                strerror(ret));
     644           0 :         goto done;
     645             :     }
     646           0 :     in_transaction = false;
     647             : 
     648             : done:
     649           0 :     if (in_transaction) {
     650           0 :         sret = sysdb_transaction_cancel(sysdb);
     651           0 :         if (sret != EOK) {
     652           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
     653             :         }
     654             :     }
     655           0 :     talloc_free(tmp_ctx);
     656           0 :     return ret;
     657             : }
     658             : 
     659           0 : static errno_t proxy_process_missing_users(struct sysdb_ctx *sysdb,
     660             :                                            struct sss_domain_info *domain,
     661             :                                            struct sysdb_attrs *group_attrs,
     662             :                                            struct group *grp,
     663             :                                            time_t now)
     664             : {
     665             :     errno_t ret;
     666             :     size_t i;
     667           0 :     TALLOC_CTX *tmp_ctx = NULL;
     668             :     struct ldb_message *msg;
     669             : 
     670           0 :     if (!sysdb || !grp) return EINVAL;
     671             : 
     672           0 :     tmp_ctx = talloc_new(NULL);
     673           0 :     if (!tmp_ctx) return ENOMEM;
     674             : 
     675           0 :     for (i = 0; grp->gr_mem[i]; i++) {
     676           0 :         ret = sysdb_search_user_by_name(tmp_ctx, domain, grp->gr_mem[i],
     677             :                                         NULL, &msg);
     678           0 :         if (ret == EOK) {
     679             :             /* Member already exists in the cache */
     680           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
     681             :                   "Member [%s] already cached\n", grp->gr_mem[i]);
     682             :             /* clean up */
     683           0 :             talloc_zfree(msg);
     684           0 :             continue;
     685           0 :         } else if (ret == ENOENT) {
     686             :             /* No entry for this user. Create a ghost user */
     687           0 :             DEBUG(SSSDBG_TRACE_LIBS,
     688             :                   "Member [%s] not cached, creating ghost user entry\n",
     689             :                    grp->gr_mem[i]);
     690             : 
     691           0 :             ret = sysdb_attrs_add_string(group_attrs, SYSDB_GHOST, grp->gr_mem[i]);
     692           0 :             if (ret != EOK) {
     693           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     694             :                       "Cannot store ghost user entry: [%d]: %s\n",
     695             :                        ret, strerror(ret));
     696           0 :                 goto done;
     697             :             }
     698             :         } else {
     699             :             /* Unexpected error */
     700           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     701             :                   "Error searching cache for user [%s]: [%s]\n",
     702             :                    grp->gr_mem[i], strerror(ret));
     703           0 :             goto done;
     704             :         }
     705             :     }
     706             : 
     707           0 :     ret = EOK;
     708             : done:
     709           0 :     talloc_free(tmp_ctx);
     710           0 :     return ret;
     711             : }
     712             : 
     713             : /* =Getgrnam-wrapper======================================================*/
     714             : static char *
     715           0 : grow_group_buffer(TALLOC_CTX *mem_ctx,
     716             :                   char **buffer, size_t *buflen)
     717             : {
     718             :     char *newbuf;
     719             : 
     720           0 :     if (*buflen == 0) {
     721           0 :         *buflen = DEFAULT_BUFSIZE;
     722             :     }
     723           0 :     if (*buflen < MAX_BUF_SIZE) {
     724           0 :         *buflen *= 2;
     725             :     }
     726           0 :     if (*buflen > MAX_BUF_SIZE) {
     727           0 :         *buflen = MAX_BUF_SIZE;
     728             :     }
     729             : 
     730           0 :     newbuf = talloc_realloc_size(mem_ctx, *buffer, *buflen);
     731           0 :     if (!newbuf) {
     732           0 :         return NULL;
     733             :     }
     734           0 :     *buffer = newbuf;
     735             : 
     736           0 :     return *buffer;
     737             : }
     738             : 
     739             : static errno_t
     740           0 : handle_getgr_result(enum nss_status status, struct group *grp,
     741             :                     struct sss_domain_info *dom,
     742             :                     bool *delete_group)
     743             : {
     744           0 :     switch (status) {
     745             :     case NSS_STATUS_TRYAGAIN:
     746           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Buffer too small\n");
     747           0 :         return EAGAIN;
     748             : 
     749             :     case NSS_STATUS_NOTFOUND:
     750           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Group not found.\n");
     751           0 :         *delete_group = true;
     752           0 :         break;
     753             : 
     754             :     case NSS_STATUS_SUCCESS:
     755           0 :         DEBUG(SSSDBG_FUNC_DATA, "Group found: (%s, %"SPRIgid")\n",
     756             :               grp->gr_name, grp->gr_gid);
     757             : 
     758             :         /* gid=0 is an invalid value */
     759             :         /* also check that the id is in the valid range for this domain */
     760           0 :         if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) {
     761           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     762             :                   "Group filtered out! (id out of range)\n");
     763           0 :             *delete_group = true;
     764           0 :             break;
     765             :         }
     766           0 :         break;
     767             : 
     768             :     case NSS_STATUS_UNAVAIL:
     769           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     770             :               "Remote back end is not available. Entering offline mode\n");
     771           0 :         return ENXIO;
     772             : 
     773             :     default:
     774           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown return code %d\n", status);
     775           0 :         return EIO;
     776             :     }
     777             : 
     778           0 :     return EOK;
     779             : }
     780             : 
     781           0 : static int get_gr_name(struct proxy_id_ctx *ctx,
     782             :                        struct sysdb_ctx *sysdb,
     783             :                        struct sss_domain_info *dom,
     784             :                        const char *name)
     785             : {
     786             :     TALLOC_CTX *tmpctx;
     787             :     struct group *grp;
     788             :     enum nss_status status;
     789           0 :     char *buffer = 0;
     790           0 :     size_t buflen = 0;
     791           0 :     bool delete_group = false;
     792             :     int ret;
     793             :     gid_t gid;
     794           0 :     struct ldb_result *cached_grp = NULL;
     795           0 :     const char *real_name = NULL;
     796             : 
     797           0 :     DEBUG(SSSDBG_FUNC_DATA, "Searching group by name (%s)\n", name);
     798             : 
     799           0 :     tmpctx = talloc_new(NULL);
     800           0 :     if (!tmpctx) {
     801           0 :         return ENOMEM;
     802             :     }
     803             : 
     804           0 :     grp = talloc(tmpctx, struct group);
     805           0 :     if (!grp) {
     806           0 :         ret = ENOMEM;
     807           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     808             :               "proxy -> getgrnam_r failed for '%s': [%d] %s\n",
     809             :               name, ret, strerror(ret));
     810           0 :         goto done;
     811             :     }
     812             : 
     813             :     do {
     814             :         /* always zero out the grp structure */
     815           0 :         memset(grp, 0, sizeof(struct group));
     816           0 :         buffer = grow_group_buffer(tmpctx, &buffer, &buflen);
     817           0 :         if (!buffer) {
     818           0 :             ret = ENOMEM;
     819           0 :             goto done;
     820             :         }
     821             : 
     822           0 :         status = ctx->ops.getgrnam_r(name, grp, buffer, buflen, &ret);
     823             : 
     824           0 :         ret = handle_getgr_result(status, grp, dom, &delete_group);
     825           0 :     } while (ret == EAGAIN);
     826             : 
     827           0 :     if (ret != EOK) {
     828           0 :         DEBUG(SSSDBG_OP_FAILURE,
     829             :               "getgrnam failed [%d]: %s\n", ret, strerror(ret));
     830           0 :         goto done;
     831             :     }
     832             : 
     833           0 :     gid = grp->gr_gid;
     834             : 
     835             :     /* Canonicalize the group name in case it was actually an alias */
     836           0 :     if (ctx->fast_alias == true) {
     837           0 :         ret = sysdb_getgrgid(tmpctx, dom, gid, &cached_grp);
     838           0 :         if (ret != EOK) {
     839             :             /* Non-fatal, attempt to canonicalize online */
     840           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Request to cache failed [%d]: %s\n",
     841             :                   ret, strerror(ret));
     842             :         }
     843             : 
     844           0 :         if (ret == EOK && cached_grp->count == 1) {
     845           0 :             real_name = ldb_msg_find_attr_as_string(cached_grp->msgs[0],
     846             :                                                     SYSDB_NAME, NULL);
     847           0 :             if (!real_name) {
     848           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cached group has no name?\n");
     849             :             }
     850             :         }
     851             :     }
     852             : 
     853           0 :     if (real_name == NULL) {
     854           0 :         talloc_zfree(buffer);
     855           0 :         buflen = 0;
     856             : 
     857             :         do {
     858           0 :             memset(grp, 0, sizeof(struct group));
     859           0 :             buffer = grow_group_buffer(tmpctx, &buffer, &buflen);
     860           0 :             if (!buffer) {
     861           0 :                 ret = ENOMEM;
     862           0 :                 goto done;
     863             :             }
     864             : 
     865           0 :             status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret);
     866             : 
     867           0 :             ret = handle_getgr_result(status, grp, dom, &delete_group);
     868           0 :         } while (ret == EAGAIN);
     869             : 
     870           0 :         if (ret != EOK) {
     871           0 :             DEBUG(SSSDBG_OP_FAILURE,
     872             :                 "getgrgid failed [%d]: %s\n", ret, strerror(ret));
     873           0 :             goto done;
     874             :         }
     875             : 
     876           0 :         real_name = grp->gr_name;
     877             :     }
     878             : 
     879           0 :     if (delete_group) {
     880           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     881             :               "Group %s does not exist (or is invalid) on remote server,"
     882             :                " deleting!\n", name);
     883             : 
     884           0 :         ret = sysdb_delete_group(dom, NULL, gid);
     885           0 :         if (ret == ENOENT) {
     886           0 :             ret = EOK;
     887             :         }
     888           0 :         goto done;
     889             :     }
     890             : 
     891           0 :     ret = save_group(sysdb, dom, grp, real_name, name, dom->group_timeout);
     892           0 :     if (ret) {
     893           0 :         DEBUG(SSSDBG_OP_FAILURE,
     894             :               "Cannot save group [%d]: %s\n", ret, strerror(ret));
     895           0 :         goto done;
     896             :     }
     897             : 
     898             : done:
     899           0 :     talloc_zfree(tmpctx);
     900           0 :     if (ret) {
     901           0 :         DEBUG(SSSDBG_OP_FAILURE,
     902             :               "proxy -> getgrnam_r failed for '%s' <%d>: %s\n",
     903             :               name, ret, strerror(ret));
     904             :     }
     905           0 :     return ret;
     906             : }
     907             : 
     908             : /* =Getgrgid-wrapper======================================================*/
     909           0 : static int get_gr_gid(TALLOC_CTX *mem_ctx,
     910             :                       struct proxy_id_ctx *ctx,
     911             :                       struct sysdb_ctx *sysdb,
     912             :                       struct sss_domain_info *dom,
     913             :                       gid_t gid,
     914             :                       time_t now)
     915             : {
     916             :     TALLOC_CTX *tmpctx;
     917             :     struct group *grp;
     918             :     enum nss_status status;
     919           0 :     char *buffer = NULL;
     920           0 :     size_t buflen = 0;
     921           0 :     bool delete_group = false;
     922             :     int ret;
     923             : 
     924           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Searching group by gid (%"SPRIgid")\n", gid);
     925             : 
     926           0 :     tmpctx = talloc_new(mem_ctx);
     927           0 :     if (!tmpctx) {
     928           0 :         return ENOMEM;
     929             :     }
     930             : 
     931           0 :     grp = talloc(tmpctx, struct group);
     932           0 :     if (!grp) {
     933           0 :         ret = ENOMEM;
     934           0 :         goto done;
     935             :     }
     936             : 
     937             :     do {
     938             :         /* always zero out the grp structure */
     939           0 :         memset(grp, 0, sizeof(struct group));
     940           0 :         buffer = grow_group_buffer(tmpctx, &buffer, &buflen);
     941           0 :         if (!buffer) {
     942           0 :             ret = ENOMEM;
     943           0 :             goto done;
     944             :         }
     945             : 
     946           0 :         status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret);
     947             : 
     948           0 :         ret = handle_getgr_result(status, grp, dom, &delete_group);
     949           0 :     } while (ret == EAGAIN);
     950             : 
     951           0 :     if (ret != EOK) {
     952           0 :         DEBUG(SSSDBG_OP_FAILURE,
     953             :               "getgrgid failed [%d]: %s\n", ret, strerror(ret));
     954           0 :         goto done;
     955             :     }
     956             : 
     957           0 :     if (delete_group) {
     958           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     959             :               "Group %"SPRIgid" does not exist (or is invalid) on remote "
     960             :                "server, deleting!\n", gid);
     961             : 
     962           0 :         ret = sysdb_delete_group(dom, NULL, gid);
     963           0 :         if (ret == ENOENT) {
     964           0 :             ret = EOK;
     965             :         }
     966           0 :         goto done;
     967             :     }
     968             : 
     969           0 :     ret = save_group(sysdb, dom, grp, grp->gr_name, NULL, dom->group_timeout);
     970           0 :     if (ret) {
     971           0 :         DEBUG(SSSDBG_OP_FAILURE,
     972             :               "Cannot save user [%d]: %s\n", ret, strerror(ret));
     973           0 :         goto done;
     974             :     }
     975             : 
     976             : done:
     977           0 :     talloc_zfree(tmpctx);
     978           0 :     if (ret) {
     979           0 :         DEBUG(SSSDBG_OP_FAILURE,
     980             :               "proxy -> getgrgid_r failed for '%"SPRIgid"' <%d>: %s\n",
     981             :                gid, ret, strerror(ret));
     982             :     }
     983           0 :     return ret;
     984             : }
     985             : 
     986             : /* =Getgrent-wrapper======================================================*/
     987             : 
     988           0 : static int enum_groups(TALLOC_CTX *mem_ctx,
     989             :                        struct proxy_id_ctx *ctx,
     990             :                        struct sysdb_ctx *sysdb,
     991             :                        struct sss_domain_info *dom)
     992             : {
     993             :     TALLOC_CTX *tmpctx;
     994           0 :     bool in_transaction = false;
     995             :     struct group *grp;
     996             :     enum nss_status status;
     997             :     size_t buflen;
     998             :     char *buffer;
     999             :     char *newbuf;
    1000             :     int ret;
    1001             :     errno_t sret;
    1002             :     bool again;
    1003             : 
    1004           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Enumerating groups\n");
    1005             : 
    1006           0 :     tmpctx = talloc_new(mem_ctx);
    1007           0 :     if (!tmpctx) {
    1008           0 :         return ENOMEM;
    1009             :     }
    1010             : 
    1011           0 :     grp = talloc(tmpctx, struct group);
    1012           0 :     if (!grp) {
    1013           0 :         ret = ENOMEM;
    1014           0 :         goto done;
    1015             :     }
    1016             : 
    1017           0 :     buflen = DEFAULT_BUFSIZE;
    1018           0 :     buffer = talloc_size(tmpctx, buflen);
    1019           0 :     if (!buffer) {
    1020           0 :         ret = ENOMEM;
    1021           0 :         goto done;
    1022             :     }
    1023             : 
    1024           0 :     ret = sysdb_transaction_start(sysdb);
    1025           0 :     if (ret) {
    1026           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    1027           0 :         goto done;
    1028             :     }
    1029           0 :     in_transaction = true;
    1030             : 
    1031           0 :     status = ctx->ops.setgrent();
    1032           0 :     if (status != NSS_STATUS_SUCCESS) {
    1033           0 :         ret = EIO;
    1034           0 :         goto done;
    1035             :     }
    1036             : 
    1037             :     do {
    1038           0 :         again = false;
    1039             : 
    1040             :         /* always zero out the grp structure */
    1041           0 :         memset(grp, 0, sizeof(struct group));
    1042             : 
    1043             :         /* get entry */
    1044           0 :         status = ctx->ops.getgrent_r(grp, buffer, buflen, &ret);
    1045             : 
    1046           0 :         switch (status) {
    1047             :             case NSS_STATUS_TRYAGAIN:
    1048             :                 /* buffer too small ? */
    1049           0 :                 if (buflen < MAX_BUF_SIZE) {
    1050           0 :                     buflen *= 2;
    1051             :                 }
    1052           0 :                 if (buflen > MAX_BUF_SIZE) {
    1053           0 :                     buflen = MAX_BUF_SIZE;
    1054             :                 }
    1055           0 :                 newbuf = talloc_realloc_size(tmpctx, buffer, buflen);
    1056           0 :                 if (!newbuf) {
    1057           0 :                     ret = ENOMEM;
    1058           0 :                     goto done;
    1059             :                 }
    1060           0 :                 buffer = newbuf;
    1061           0 :                 again = true;
    1062           0 :                 break;
    1063             : 
    1064             :             case NSS_STATUS_NOTFOUND:
    1065             : 
    1066             :                 /* we are done here */
    1067           0 :                 DEBUG(SSSDBG_TRACE_LIBS, "Enumeration completed.\n");
    1068             : 
    1069           0 :                 ret = sysdb_transaction_commit(sysdb);
    1070           0 :                 if (ret != EOK) {
    1071           0 :                     DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
    1072           0 :                     goto done;
    1073             :                 }
    1074           0 :                 in_transaction = false;
    1075           0 :                 break;
    1076             : 
    1077             :             case NSS_STATUS_SUCCESS:
    1078             : 
    1079           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Group found (%s, %"SPRIgid")\n",
    1080             :                             grp->gr_name, grp->gr_gid);
    1081             : 
    1082             :                 /* gid=0 is an invalid value */
    1083             :                 /* also check that the id is in the valid range for this domain
    1084             :                  */
    1085           0 :                 if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) {
    1086             : 
    1087           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Group [%s] filtered out! (id"
    1088             :                         "out of range)\n", grp->gr_name);
    1089             : 
    1090           0 :                     again = true;
    1091           0 :                     break;
    1092             :                 }
    1093             : 
    1094           0 :                 ret = save_group(sysdb, dom, grp, grp->gr_name,
    1095           0 :                         NULL, dom->group_timeout);
    1096           0 :                 if (ret) {
    1097             :                     /* Do not fail completely on errors.
    1098             :                      * Just report the failure to save and go on */
    1099           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Failed to store group."
    1100             :                                 "Ignoring\n");
    1101             :                 }
    1102           0 :                 again = true;
    1103           0 :                 break;
    1104             : 
    1105             :             case NSS_STATUS_UNAVAIL:
    1106             :                 /* "remote" backend unavailable. Enter offline mode */
    1107           0 :                 ret = ENXIO;
    1108           0 :                 break;
    1109             : 
    1110             :             default:
    1111           0 :                 ret = EIO;
    1112           0 :                 DEBUG(SSSDBG_OP_FAILURE, "proxy -> getgrent_r failed (%d)[%s]"
    1113             :                             "\n", ret, strerror(ret));
    1114           0 :                 break;
    1115             :         }
    1116           0 :     } while (again);
    1117             : 
    1118             : done:
    1119           0 :     talloc_zfree(tmpctx);
    1120           0 :     if (in_transaction) {
    1121           0 :         sret = sysdb_transaction_cancel(sysdb);
    1122           0 :         if (sret != EOK) {
    1123           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
    1124             :         }
    1125             :     }
    1126           0 :     ctx->ops.endgrent();
    1127           0 :     return ret;
    1128             : }
    1129             : 
    1130             : 
    1131             : /* =Initgroups-wrapper====================================================*/
    1132             : 
    1133             : static int get_initgr_groups_process(TALLOC_CTX *memctx,
    1134             :                                      struct proxy_id_ctx *ctx,
    1135             :                                      struct sysdb_ctx *sysdb,
    1136             :                                      struct sss_domain_info *dom,
    1137             :                                      struct passwd *pwd);
    1138             : 
    1139           0 : static int get_initgr(TALLOC_CTX *mem_ctx,
    1140             :                       struct proxy_id_ctx *ctx,
    1141             :                       struct sysdb_ctx *sysdb,
    1142             :                       struct sss_domain_info *dom,
    1143             :                       const char *name)
    1144             : {
    1145             :     TALLOC_CTX *tmpctx;
    1146           0 :     bool in_transaction = false;
    1147             :     struct passwd *pwd;
    1148             :     enum nss_status status;
    1149             :     char *buffer;
    1150             :     size_t buflen;
    1151             :     int ret;
    1152             :     errno_t sret;
    1153             :     bool del_user;
    1154             :     uid_t uid;
    1155           0 :     struct ldb_result *cached_pwd = NULL;
    1156           0 :     const char *real_name = NULL;
    1157             : 
    1158           0 :     tmpctx = talloc_new(mem_ctx);
    1159           0 :     if (!tmpctx) {
    1160           0 :         return ENOMEM;
    1161             :     }
    1162             : 
    1163           0 :     pwd = talloc_zero(tmpctx, struct passwd);
    1164           0 :     if (!pwd) {
    1165           0 :         ret = ENOMEM;
    1166           0 :         goto fail;
    1167             :     }
    1168             : 
    1169           0 :     buflen = DEFAULT_BUFSIZE;
    1170           0 :     buffer = talloc_size(tmpctx, buflen);
    1171           0 :     if (!buffer) {
    1172           0 :         ret = ENOMEM;
    1173           0 :         goto fail;
    1174             :     }
    1175             : 
    1176           0 :     ret = sysdb_transaction_start(sysdb);
    1177           0 :     if (ret) {
    1178           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    1179           0 :         goto fail;
    1180             :     }
    1181           0 :     in_transaction = true;
    1182             : 
    1183             :     /* FIXME: should we move this call outside the transaction to keep the
    1184             :      * transaction as short as possible ? */
    1185           0 :     status = ctx->ops.getpwnam_r(name, pwd, buffer, buflen, &ret);
    1186           0 :     ret = handle_getpw_result(status, pwd, dom, &del_user);
    1187           0 :     if (ret) {
    1188           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1189             :               "getpwnam failed [%d]: %s\n", ret, strerror(ret));
    1190           0 :         goto fail;
    1191             :     }
    1192             : 
    1193           0 :     if (del_user) {
    1194           0 :         ret = delete_user(dom, name, 0);
    1195           0 :         if (ret) {
    1196           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not delete user\n");
    1197           0 :             goto fail;
    1198             :         }
    1199           0 :         goto done;
    1200             :     }
    1201             : 
    1202           0 :     uid = pwd->pw_uid;
    1203           0 :     memset(buffer, 0, buflen);
    1204             : 
    1205             :     /* Canonicalize the username in case it was actually an alias */
    1206           0 :     if (ctx->fast_alias == true) {
    1207           0 :         ret = sysdb_getpwuid(tmpctx, dom, uid, &cached_pwd);
    1208           0 :         if (ret != EOK) {
    1209             :             /* Non-fatal, attempt to canonicalize online */
    1210           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Request to cache failed [%d]: %s\n",
    1211             :                   ret, strerror(ret));
    1212             :         }
    1213             : 
    1214           0 :         if (ret == EOK && cached_pwd->count == 1) {
    1215           0 :             real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0],
    1216             :                                                     SYSDB_NAME, NULL);
    1217           0 :             if (!real_name) {
    1218           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Cached user has no name?\n");
    1219             :             }
    1220             :         }
    1221             :     }
    1222             : 
    1223           0 :     if (real_name == NULL) {
    1224           0 :         memset(buffer, 0, buflen);
    1225             : 
    1226           0 :         status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret);
    1227           0 :         ret = handle_getpw_result(status, pwd, dom, &del_user);
    1228           0 :         if (ret) {
    1229           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1230             :                 "getpwuid failed [%d]: %s\n", ret, strerror(ret));
    1231           0 :             goto done;
    1232             :         }
    1233             : 
    1234           0 :         real_name = pwd->pw_name;
    1235             :     }
    1236             : 
    1237           0 :     if (del_user) {
    1238           0 :         ret = delete_user(dom, name, uid);
    1239           0 :         if (ret) {
    1240           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not delete user\n");
    1241           0 :             goto fail;
    1242             :         }
    1243           0 :         goto done;
    1244             :     }
    1245             : 
    1246           0 :     ret = save_user(dom, !dom->case_sensitive, pwd,
    1247           0 :                     real_name, name, dom->user_timeout);
    1248           0 :     if (ret) {
    1249           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not save user\n");
    1250           0 :         goto fail;
    1251             :     }
    1252             : 
    1253           0 :     ret = get_initgr_groups_process(tmpctx, ctx, sysdb, dom, pwd);
    1254           0 :     if (ret != EOK) {
    1255           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not process initgroups\n");
    1256           0 :         goto fail;
    1257             :     }
    1258             : 
    1259             : done:
    1260           0 :     ret = sysdb_transaction_commit(sysdb);
    1261           0 :     if (ret) {
    1262           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to commit transaction\n");
    1263           0 :         goto fail;
    1264             :     }
    1265           0 :     in_transaction = false;
    1266             : 
    1267             : fail:
    1268           0 :     talloc_zfree(tmpctx);
    1269           0 :     if (in_transaction) {
    1270           0 :         sret = sysdb_transaction_cancel(sysdb);
    1271           0 :         if (sret != EOK) {
    1272           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
    1273             :         }
    1274             :     }
    1275           0 :     return ret;
    1276             : }
    1277             : 
    1278           0 : static int get_initgr_groups_process(TALLOC_CTX *memctx,
    1279             :                                      struct proxy_id_ctx *ctx,
    1280             :                                      struct sysdb_ctx *sysdb,
    1281             :                                      struct sss_domain_info *dom,
    1282             :                                      struct passwd *pwd)
    1283             : {
    1284             :     enum nss_status status;
    1285             :     long int limit;
    1286             :     long int size;
    1287             :     long int num;
    1288             :     long int num_gids;
    1289             :     gid_t *gids;
    1290             :     int ret;
    1291             :     int i;
    1292             :     time_t now;
    1293             : 
    1294           0 :     num_gids = 0;
    1295           0 :     limit = 4096;
    1296           0 :     num = 4096;
    1297           0 :     size = num*sizeof(gid_t);
    1298           0 :     gids = talloc_size(memctx, size);
    1299           0 :     if (!gids) {
    1300           0 :         return ENOMEM;
    1301             :     }
    1302             : 
    1303             :     /* nss modules may skip the primary group when we pass it in so always add
    1304             :      * it in advance */
    1305           0 :     gids[0] = pwd->pw_gid;
    1306           0 :     num_gids++;
    1307             : 
    1308             :     /* FIXME: should we move this call outside the transaction to keep the
    1309             :      * transaction as short as possible ? */
    1310             :     do {
    1311           0 :         status = ctx->ops.initgroups_dyn(pwd->pw_name, pwd->pw_gid, &num_gids,
    1312             :                 &num, &gids, limit, &ret);
    1313             : 
    1314           0 :         if (status == NSS_STATUS_TRYAGAIN) {
    1315             :             /* buffer too small ? */
    1316           0 :             if (size < MAX_BUF_SIZE) {
    1317           0 :                 num *= 2;
    1318           0 :                 size = num*sizeof(gid_t);
    1319             :             }
    1320           0 :             if (size > MAX_BUF_SIZE) {
    1321           0 :                 size = MAX_BUF_SIZE;
    1322           0 :                 num = size/sizeof(gid_t);
    1323             :             }
    1324           0 :             limit = num;
    1325           0 :             gids = talloc_realloc_size(memctx, gids, size);
    1326           0 :             if (!gids) {
    1327           0 :                 return ENOMEM;
    1328             :             }
    1329             :         }
    1330           0 :     } while(status == NSS_STATUS_TRYAGAIN);
    1331             : 
    1332           0 :     switch (status) {
    1333             :     case NSS_STATUS_NOTFOUND:
    1334           0 :         DEBUG(SSSDBG_FUNC_DATA, "The initgroups call returned 'NOTFOUND'. "
    1335             :                                  "Assume the user is only member of its "
    1336             :                                  "primary group (%"SPRIgid")\n", pwd->pw_gid);
    1337             :         /* fall through */
    1338             :     case NSS_STATUS_SUCCESS:
    1339           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "User [%s] appears to be member of %lu "
    1340             :               "groups\n", pwd->pw_name, num_gids);
    1341             : 
    1342           0 :         now = time(NULL);
    1343           0 :         for (i = 0; i < num_gids; i++) {
    1344           0 :             ret = get_gr_gid(memctx, ctx, sysdb, dom, gids[i], now);
    1345           0 :             if (ret) {
    1346           0 :                 return ret;
    1347             :             }
    1348             :         }
    1349           0 :         ret = EOK;
    1350             : 
    1351           0 :         break;
    1352             : 
    1353             :     default:
    1354           0 :         DEBUG(SSSDBG_OP_FAILURE, "proxy -> initgroups_dyn failed (%d)[%s]\n",
    1355             :                   ret, strerror(ret));
    1356           0 :         ret = EIO;
    1357           0 :         break;
    1358             :     }
    1359             : 
    1360           0 :     return ret;
    1361             : }
    1362             : 
    1363             : /* =Proxy_Id-Functions====================================================*/
    1364             : 
    1365             : static struct dp_reply_std
    1366           0 : proxy_account_info(TALLOC_CTX *mem_ctx,
    1367             :                    struct proxy_id_ctx *ctx,
    1368             :                    struct be_acct_req *data,
    1369             :                    struct be_ctx *be_ctx,
    1370             :                    struct sss_domain_info *domain)
    1371             : {
    1372             :     struct dp_reply_std reply;
    1373             :     struct sysdb_ctx *sysdb;
    1374             :     uid_t uid;
    1375             :     gid_t gid;
    1376             :     errno_t ret;
    1377             :     char *endptr;
    1378             : 
    1379           0 :     sysdb = domain->sysdb;
    1380             : 
    1381             :     /* For now we support only core attrs. */
    1382           0 :     if (data->attr_type != BE_ATTR_CORE) {
    1383           0 :         dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL, "Invalid attr type");
    1384           0 :         return reply;
    1385             :     }
    1386             : 
    1387             :     /* Proxy provider does not support security ID lookups. */
    1388           0 :     if (data->filter_type == BE_FILTER_SECID) {
    1389           0 :         dp_reply_std_set(&reply, DP_ERR_FATAL, ENOSYS,
    1390             :                          "Security lookups are not supported");
    1391           0 :         return reply;
    1392             :     }
    1393             : 
    1394           0 :     switch (data->entry_type & BE_REQ_TYPE_MASK) {
    1395             :     case BE_REQ_USER: /* user */
    1396           0 :         switch (data->filter_type) {
    1397             :         case BE_FILTER_ENUM:
    1398           0 :             ret = enum_users(mem_ctx, ctx, sysdb, domain);
    1399           0 :             break;
    1400             : 
    1401             :         case BE_FILTER_NAME:
    1402           0 :             ret = get_pw_name(ctx, domain, data->filter_value);
    1403           0 :             break;
    1404             : 
    1405             :         case BE_FILTER_IDNUM:
    1406           0 :             uid = (uid_t) strtouint32(data->filter_value, &endptr, 10);
    1407           0 :             if (errno || *endptr || (data->filter_value == endptr)) {
    1408           0 :                 dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1409             :                                  "Invalid attr type");
    1410           0 :                 return reply;
    1411             :             }
    1412           0 :             ret = get_pw_uid(ctx, domain, uid);
    1413           0 :             break;
    1414             :         default:
    1415           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1416             :                              "Invalid filter type");
    1417           0 :             return reply;
    1418             :         }
    1419           0 :         break;
    1420             : 
    1421             :     case BE_REQ_GROUP: /* group */
    1422           0 :         switch (data->filter_type) {
    1423             :         case BE_FILTER_ENUM:
    1424           0 :             ret = enum_groups(mem_ctx, ctx, sysdb, domain);
    1425           0 :             break;
    1426             :         case BE_FILTER_NAME:
    1427           0 :             ret = get_gr_name(ctx, sysdb, domain, data->filter_value);
    1428           0 :             break;
    1429             :         case BE_FILTER_IDNUM:
    1430           0 :             gid = (gid_t) strtouint32(data->filter_value, &endptr, 10);
    1431           0 :             if (errno || *endptr || (data->filter_value == endptr)) {
    1432           0 :                 dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1433             :                                  "Invalid attr type");
    1434           0 :                 return reply;
    1435             :             }
    1436           0 :             ret = get_gr_gid(mem_ctx, ctx, sysdb, domain, gid, 0);
    1437           0 :             break;
    1438             :         default:
    1439           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1440             :                              "Invalid filter type");
    1441           0 :             return reply;
    1442             :         }
    1443           0 :         break;
    1444             : 
    1445             :     case BE_REQ_INITGROUPS: /* init groups for user */
    1446           0 :         if (data->filter_type != BE_FILTER_NAME) {
    1447           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1448             :                              "Invalid filter type");
    1449           0 :             return reply;
    1450             :         }
    1451           0 :         if (ctx->ops.initgroups_dyn == NULL) {
    1452           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
    1453             :                              "Initgroups call not supported");
    1454           0 :             return reply;
    1455             :         }
    1456           0 :         ret = get_initgr(mem_ctx, ctx, sysdb, domain, data->filter_value);
    1457           0 :         break;
    1458             : 
    1459             :     case BE_REQ_NETGROUP:
    1460           0 :         if (data->filter_type != BE_FILTER_NAME) {
    1461           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1462             :                              "Invalid filter type");
    1463           0 :             return reply;
    1464             :         }
    1465           0 :         if (ctx->ops.setnetgrent == NULL || ctx->ops.getnetgrent_r == NULL ||
    1466           0 :             ctx->ops.endnetgrent == NULL) {
    1467           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
    1468             :                              "Netgroups are not supported");
    1469           0 :             return reply;
    1470             :         }
    1471             : 
    1472           0 :         ret = get_netgroup(ctx, domain, data->filter_value);
    1473           0 :         break;
    1474             : 
    1475             :     case BE_REQ_SERVICES:
    1476           0 :         switch (data->filter_type) {
    1477             :         case BE_FILTER_NAME:
    1478           0 :             if (ctx->ops.getservbyname_r == NULL) {
    1479           0 :                 dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
    1480             :                                  "Services are not supported");
    1481           0 :                 return reply;
    1482             :             }
    1483           0 :             ret = get_serv_byname(ctx, domain,
    1484             :                                   data->filter_value,
    1485             :                                   data->extra_value);
    1486           0 :             break;
    1487             :         case BE_FILTER_IDNUM:
    1488           0 :             if (ctx->ops.getservbyport_r == NULL) {
    1489           0 :                 dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
    1490             :                                  "Services are not supported");
    1491           0 :                 return reply;
    1492             :             }
    1493           0 :             ret = get_serv_byport(ctx, domain,
    1494             :                                   data->filter_value,
    1495             :                                   data->extra_value);
    1496           0 :             break;
    1497             :         case BE_FILTER_ENUM:
    1498           0 :             if (!ctx->ops.setservent
    1499           0 :                     || !ctx->ops.getservent_r
    1500           0 :                     || !ctx->ops.endservent) {
    1501           0 :                 dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
    1502             :                                  "Services are not supported");
    1503           0 :                 return reply;
    1504             :             }
    1505           0 :             ret = enum_services(ctx, sysdb, domain);
    1506           0 :             break;
    1507             :         default:
    1508           0 :             dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1509             :                              "Invalid filter type");
    1510           0 :             return reply;
    1511             :         }
    1512           0 :         break;
    1513             : 
    1514             :     default: /*fail*/
    1515           0 :         dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
    1516             :                          "Invalid filter type");
    1517           0 :         return reply;
    1518             :     }
    1519             : 
    1520           0 :     if (ret) {
    1521           0 :         if (ret == ENXIO) {
    1522           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1523             :                   "proxy returned UNAVAIL error, going offline!\n");
    1524           0 :             be_mark_offline(be_ctx);
    1525             :         }
    1526             : 
    1527           0 :         dp_reply_std_set(&reply, DP_ERR_FATAL, ret, NULL);
    1528           0 :         return reply;
    1529             :     }
    1530             : 
    1531           0 :     dp_reply_std_set(&reply, DP_ERR_OK, EOK, NULL);
    1532           0 :     return reply;
    1533             : }
    1534             : 
    1535             : struct proxy_account_info_handler_state {
    1536             :     struct dp_reply_std reply;
    1537             : };
    1538             : 
    1539             : struct tevent_req *
    1540           0 : proxy_account_info_handler_send(TALLOC_CTX *mem_ctx,
    1541             :                                struct proxy_id_ctx *id_ctx,
    1542             :                                struct be_acct_req *data,
    1543             :                                struct dp_req_params *params)
    1544             : {
    1545             :     struct proxy_account_info_handler_state *state;
    1546             :     struct tevent_req *req;
    1547             : 
    1548           0 :     req = tevent_req_create(mem_ctx, &state,
    1549             :                             struct proxy_account_info_handler_state);
    1550           0 :     if (req == NULL) {
    1551           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
    1552           0 :         return NULL;
    1553             :     }
    1554             : 
    1555           0 :     state->reply = proxy_account_info(state, id_ctx, data, params->be_ctx,
    1556           0 :                                       params->be_ctx->domain);
    1557             : 
    1558             :     /* TODO For backward compatibility we always return EOK to DP now. */
    1559           0 :     tevent_req_done(req);
    1560           0 :     tevent_req_post(req, params->ev);
    1561             : 
    1562           0 :     return req;
    1563             : }
    1564             : 
    1565           0 : errno_t proxy_account_info_handler_recv(TALLOC_CTX *mem_ctx,
    1566             :                                        struct tevent_req *req,
    1567             :                                        struct dp_reply_std *data)
    1568             : {
    1569           0 :     struct proxy_account_info_handler_state *state = NULL;
    1570             : 
    1571           0 :     state = tevent_req_data(req, struct proxy_account_info_handler_state);
    1572             : 
    1573           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1574             : 
    1575           0 :     *data = state->reply;
    1576             : 
    1577           0 :     return EOK;
    1578             : }

Generated by: LCOV version 1.10