xref: /unit/src/nxt_clone.c (revision 2078)
11182St.nateldemoura@f5.com /*
21182St.nateldemoura@f5.com  * Copyright (C) Igor Sysoev
31182St.nateldemoura@f5.com  * Copyright (C) NGINX, Inc.
41182St.nateldemoura@f5.com  */
51182St.nateldemoura@f5.com 
61182St.nateldemoura@f5.com #include <nxt_main.h>
71182St.nateldemoura@f5.com #include <sys/types.h>
81182St.nateldemoura@f5.com #include <nxt_conf.h>
91182St.nateldemoura@f5.com #include <nxt_clone.h>
101182St.nateldemoura@f5.com 
111182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE)
121182St.nateldemoura@f5.com 
131182St.nateldemoura@f5.com pid_t
141182St.nateldemoura@f5.com nxt_clone(nxt_int_t flags)
151182St.nateldemoura@f5.com {
161182St.nateldemoura@f5.com #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__)
171182St.nateldemoura@f5.com     return syscall(__NR_clone, NULL, flags);
181182St.nateldemoura@f5.com #else
191182St.nateldemoura@f5.com     return syscall(__NR_clone, flags, NULL);
201182St.nateldemoura@f5.com #endif
211182St.nateldemoura@f5.com }
221182St.nateldemoura@f5.com 
231182St.nateldemoura@f5.com #endif
241182St.nateldemoura@f5.com 
251182St.nateldemoura@f5.com 
261182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER)
271182St.nateldemoura@f5.com 
281306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid,
291182St.nateldemoura@f5.com     const char *str);
301306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile,
311306St.nateldemoura@f5.com     pid_t pid, nxt_int_t default_container, nxt_int_t default_host,
321306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map);
331306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile,
341182St.nateldemoura@f5.com     pid_t pid, u_char *mapinfo);
351182St.nateldemoura@f5.com 
361182St.nateldemoura@f5.com 
371182St.nateldemoura@f5.com nxt_int_t
381306St.nateldemoura@f5.com nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid,
391306St.nateldemoura@f5.com     const char *str)
401182St.nateldemoura@f5.com {
411182St.nateldemoura@f5.com     int     fd, n;
421182St.nateldemoura@f5.com     u_char  *p, *end;
431182St.nateldemoura@f5.com     u_char  path[PATH_MAX];
441182St.nateldemoura@f5.com 
451182St.nateldemoura@f5.com     end = path + PATH_MAX;
461182St.nateldemoura@f5.com     p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid);
471182St.nateldemoura@f5.com     *p = '\0';
481182St.nateldemoura@f5.com 
491182St.nateldemoura@f5.com     if (nxt_slow_path(p == end)) {
501182St.nateldemoura@f5.com         nxt_alert(task, "error write past the buffer: %s", path);
511182St.nateldemoura@f5.com         return NXT_ERROR;
521182St.nateldemoura@f5.com     }
531182St.nateldemoura@f5.com 
541182St.nateldemoura@f5.com     fd = open((char *)path, O_RDWR);
551182St.nateldemoura@f5.com 
561182St.nateldemoura@f5.com     if (fd == -1) {
571182St.nateldemoura@f5.com         /*
581182St.nateldemoura@f5.com          * If the /proc/pid/setgroups doesn't exists, we are
591182St.nateldemoura@f5.com          * safe to set uid/gid maps. But if the error is anything
601182St.nateldemoura@f5.com          * other than ENOENT, then we should abort and let user know.
611182St.nateldemoura@f5.com          */
621182St.nateldemoura@f5.com 
631182St.nateldemoura@f5.com         if (errno != ENOENT) {
641182St.nateldemoura@f5.com             nxt_alert(task, "open(%s): %E", path, nxt_errno);
651182St.nateldemoura@f5.com             return NXT_ERROR;
661182St.nateldemoura@f5.com         }
671182St.nateldemoura@f5.com 
681182St.nateldemoura@f5.com         return NXT_OK;
691182St.nateldemoura@f5.com     }
701182St.nateldemoura@f5.com 
711182St.nateldemoura@f5.com     n = write(fd, str, strlen(str));
721182St.nateldemoura@f5.com     close(fd);
731182St.nateldemoura@f5.com 
741182St.nateldemoura@f5.com     if (nxt_slow_path(n == -1)) {
751182St.nateldemoura@f5.com         nxt_alert(task, "write(%s): %E", path, nxt_errno);
761182St.nateldemoura@f5.com         return NXT_ERROR;
771182St.nateldemoura@f5.com     }
781182St.nateldemoura@f5.com 
791182St.nateldemoura@f5.com     return NXT_OK;
801182St.nateldemoura@f5.com }
811182St.nateldemoura@f5.com 
821182St.nateldemoura@f5.com 
831182St.nateldemoura@f5.com nxt_int_t
841306St.nateldemoura@f5.com nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile,
851306St.nateldemoura@f5.com     pid_t pid, u_char *mapinfo)
861182St.nateldemoura@f5.com {
871182St.nateldemoura@f5.com     int      len, mapfd;
881182St.nateldemoura@f5.com     u_char   *p, *end;
891182St.nateldemoura@f5.com     ssize_t  n;
901182St.nateldemoura@f5.com     u_char   buf[256];
911182St.nateldemoura@f5.com 
921182St.nateldemoura@f5.com     end = buf + sizeof(buf);
931182St.nateldemoura@f5.com 
941182St.nateldemoura@f5.com     p = nxt_sprintf(buf, end, "/proc/%d/%s", pid, mapfile);
951182St.nateldemoura@f5.com     if (nxt_slow_path(p == end)) {
961182St.nateldemoura@f5.com         nxt_alert(task, "writing past the buffer");
971182St.nateldemoura@f5.com         return NXT_ERROR;
981182St.nateldemoura@f5.com     }
991182St.nateldemoura@f5.com 
1001182St.nateldemoura@f5.com     *p = '\0';
1011182St.nateldemoura@f5.com 
1021182St.nateldemoura@f5.com     mapfd = open((char*)buf, O_RDWR);
1031182St.nateldemoura@f5.com     if (nxt_slow_path(mapfd == -1)) {
1041182St.nateldemoura@f5.com         nxt_alert(task, "failed to open proc map (%s) %E", buf, nxt_errno);
1051182St.nateldemoura@f5.com         return NXT_ERROR;
1061182St.nateldemoura@f5.com     }
1071182St.nateldemoura@f5.com 
1081182St.nateldemoura@f5.com     len = nxt_strlen(mapinfo);
1091182St.nateldemoura@f5.com 
1101182St.nateldemoura@f5.com     n = write(mapfd, (char *)mapinfo, len);
1111182St.nateldemoura@f5.com     if (nxt_slow_path(n != len)) {
1121182St.nateldemoura@f5.com 
1131182St.nateldemoura@f5.com         if (n == -1 && nxt_errno == EINVAL) {
1141182St.nateldemoura@f5.com             nxt_alert(task, "failed to write %s: Check kernel maximum " \
1151182St.nateldemoura@f5.com                       "allowed lines %E", buf, nxt_errno);
1161182St.nateldemoura@f5.com 
1171182St.nateldemoura@f5.com         } else {
1181182St.nateldemoura@f5.com             nxt_alert(task, "failed to write proc map (%s) %E", buf,
1191182St.nateldemoura@f5.com                       nxt_errno);
1201182St.nateldemoura@f5.com         }
1211182St.nateldemoura@f5.com 
1221201St.nateldemoura@f5.com         close(mapfd);
1231201St.nateldemoura@f5.com 
1241182St.nateldemoura@f5.com         return NXT_ERROR;
1251182St.nateldemoura@f5.com     }
1261182St.nateldemoura@f5.com 
1271201St.nateldemoura@f5.com     close(mapfd);
1281201St.nateldemoura@f5.com 
1291182St.nateldemoura@f5.com     return NXT_OK;
1301182St.nateldemoura@f5.com }
1311182St.nateldemoura@f5.com 
1321182St.nateldemoura@f5.com 
1331182St.nateldemoura@f5.com nxt_int_t
1341306St.nateldemoura@f5.com nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid,
1351306St.nateldemoura@f5.com     nxt_int_t default_container, nxt_int_t default_host,
1361306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map)
1371182St.nateldemoura@f5.com {
1381306St.nateldemoura@f5.com     u_char      *p, *end, *mapinfo;
1391306St.nateldemoura@f5.com     nxt_int_t   ret, len;
1401306St.nateldemoura@f5.com     nxt_uint_t  i;
1411182St.nateldemoura@f5.com 
1421182St.nateldemoura@f5.com     /*
1431182St.nateldemoura@f5.com      * uid_map one-entry size:
1441182St.nateldemoura@f5.com      *   alloc space for 3 numbers (32bit) plus 2 spaces and \n.
1451182St.nateldemoura@f5.com      */
1461182St.nateldemoura@f5.com     len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1);
1471182St.nateldemoura@f5.com 
1481306St.nateldemoura@f5.com     if (map->size > 0) {
1491306St.nateldemoura@f5.com         len = len * map->size + 1;
1501182St.nateldemoura@f5.com 
1511182St.nateldemoura@f5.com         mapinfo = nxt_malloc(len);
1521182St.nateldemoura@f5.com         if (nxt_slow_path(mapinfo == NULL)) {
1531182St.nateldemoura@f5.com             return NXT_ERROR;
1541182St.nateldemoura@f5.com         }
1551182St.nateldemoura@f5.com 
1561182St.nateldemoura@f5.com         p = mapinfo;
1571182St.nateldemoura@f5.com         end = mapinfo + len;
1581182St.nateldemoura@f5.com 
1591306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
1601306St.nateldemoura@f5.com             p = nxt_sprintf(p, end, "%d %d %d", map->map[i].container,
1611306St.nateldemoura@f5.com                             map->map[i].host, map->map[i].size);
1621182St.nateldemoura@f5.com 
1631182St.nateldemoura@f5.com             if (nxt_slow_path(p == end)) {
1641306St.nateldemoura@f5.com                 nxt_alert(task, "write past the mapinfo buffer");
1651182St.nateldemoura@f5.com                 nxt_free(mapinfo);
1661182St.nateldemoura@f5.com                 return NXT_ERROR;
1671182St.nateldemoura@f5.com             }
1681182St.nateldemoura@f5.com 
1691306St.nateldemoura@f5.com             if (i+1 < map->size) {
1701182St.nateldemoura@f5.com                 *p++ = '\n';
1711182St.nateldemoura@f5.com 
1721182St.nateldemoura@f5.com             } else {
1731182St.nateldemoura@f5.com                 *p = '\0';
1741182St.nateldemoura@f5.com             }
1751182St.nateldemoura@f5.com         }
1761182St.nateldemoura@f5.com 
1771182St.nateldemoura@f5.com     } else {
1781182St.nateldemoura@f5.com         mapinfo = nxt_malloc(len);
1791182St.nateldemoura@f5.com         if (nxt_slow_path(mapinfo == NULL)) {
1801182St.nateldemoura@f5.com             return NXT_ERROR;
1811182St.nateldemoura@f5.com         }
1821182St.nateldemoura@f5.com 
1831182St.nateldemoura@f5.com         end = mapinfo + len;
1841306St.nateldemoura@f5.com         p = nxt_sprintf(mapinfo, end, "%d %d 1",
1851306St.nateldemoura@f5.com                         default_container, default_host);
1861182St.nateldemoura@f5.com         *p = '\0';
1871182St.nateldemoura@f5.com 
1881182St.nateldemoura@f5.com         if (nxt_slow_path(p == end)) {
1891306St.nateldemoura@f5.com             nxt_alert(task, "write past mapinfo buffer");
1901182St.nateldemoura@f5.com             nxt_free(mapinfo);
1911182St.nateldemoura@f5.com             return NXT_ERROR;
1921182St.nateldemoura@f5.com         }
1931182St.nateldemoura@f5.com     }
1941182St.nateldemoura@f5.com 
1951306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_write(task, mapfile, pid, mapinfo);
1961182St.nateldemoura@f5.com 
1971182St.nateldemoura@f5.com     nxt_free(mapinfo);
1981182St.nateldemoura@f5.com 
1991182St.nateldemoura@f5.com     return ret;
2001182St.nateldemoura@f5.com }
2011182St.nateldemoura@f5.com 
2021182St.nateldemoura@f5.com 
2031182St.nateldemoura@f5.com nxt_int_t
2041306St.nateldemoura@f5.com nxt_clone_credential_map(nxt_task_t *task, pid_t pid,
2051306St.nateldemoura@f5.com     nxt_credential_t *app_creds, nxt_clone_t *clone)
2061182St.nateldemoura@f5.com {
2071182St.nateldemoura@f5.com     nxt_int_t      ret;
2081306St.nateldemoura@f5.com     nxt_int_t      default_host_uid;
2091306St.nateldemoura@f5.com     nxt_int_t      default_host_gid;
2101182St.nateldemoura@f5.com     const char     *rule;
2111182St.nateldemoura@f5.com     nxt_runtime_t  *rt;
2121182St.nateldemoura@f5.com 
2131182St.nateldemoura@f5.com     rt  = task->thread->runtime;
2141306St.nateldemoura@f5.com 
2151306St.nateldemoura@f5.com     if (rt->capabilities.setid) {
2161306St.nateldemoura@f5.com         rule = "allow";
2171182St.nateldemoura@f5.com 
2181306St.nateldemoura@f5.com         /*
2191306St.nateldemoura@f5.com          * By default we don't map a privileged user
2201306St.nateldemoura@f5.com          */
2211306St.nateldemoura@f5.com         default_host_uid = app_creds->uid;
2221306St.nateldemoura@f5.com         default_host_gid = app_creds->base_gid;
2231306St.nateldemoura@f5.com     } else {
2241306St.nateldemoura@f5.com         rule = "deny";
2251182St.nateldemoura@f5.com 
2261306St.nateldemoura@f5.com         default_host_uid = nxt_euid;
2271306St.nateldemoura@f5.com         default_host_gid = nxt_egid;
2281306St.nateldemoura@f5.com     }
2291306St.nateldemoura@f5.com 
2301306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "uid_map", pid, app_creds->uid,
2311306St.nateldemoura@f5.com                                        default_host_uid,
2321306St.nateldemoura@f5.com                                        &clone->uidmap);
2331306St.nateldemoura@f5.com 
2341182St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
2351182St.nateldemoura@f5.com         return NXT_ERROR;
2361182St.nateldemoura@f5.com     }
2371182St.nateldemoura@f5.com 
2381306St.nateldemoura@f5.com     ret = nxt_clone_credential_setgroups(task, pid, rule);
2391182St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
2401182St.nateldemoura@f5.com         nxt_alert(task, "failed to write /proc/%d/setgroups", pid);
2411182St.nateldemoura@f5.com         return NXT_ERROR;
2421182St.nateldemoura@f5.com     }
2431182St.nateldemoura@f5.com 
2441306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "gid_map", pid, app_creds->base_gid,
2451306St.nateldemoura@f5.com                                        default_host_gid,
2461306St.nateldemoura@f5.com                                        &clone->gidmap);
2471306St.nateldemoura@f5.com 
2481182St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
2491182St.nateldemoura@f5.com         return NXT_ERROR;
2501182St.nateldemoura@f5.com     }
2511182St.nateldemoura@f5.com 
2521182St.nateldemoura@f5.com     return NXT_OK;
2531182St.nateldemoura@f5.com }
2541182St.nateldemoura@f5.com 
2551306St.nateldemoura@f5.com 
2561306St.nateldemoura@f5.com nxt_int_t
2571306St.nateldemoura@f5.com nxt_clone_vldt_credential_uidmap(nxt_task_t *task,
2581306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
2591306St.nateldemoura@f5.com {
2601306St.nateldemoura@f5.com     nxt_int_t              id;
2611306St.nateldemoura@f5.com     nxt_uint_t             i;
2621306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
2631306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
2641306St.nateldemoura@f5.com 
2651306St.nateldemoura@f5.com     if (map->size == 0) {
2661306St.nateldemoura@f5.com         return NXT_OK;
2671306St.nateldemoura@f5.com     }
2681306St.nateldemoura@f5.com 
2691306St.nateldemoura@f5.com     rt = task->thread->runtime;
2701306St.nateldemoura@f5.com 
2711306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
2721306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
2731306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has %d entries "
2741306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
2751306St.nateldemoura@f5.com                     map->size);
2761306St.nateldemoura@f5.com 
2771306St.nateldemoura@f5.com             return NXT_ERROR;
2781306St.nateldemoura@f5.com         }
2791306St.nateldemoura@f5.com 
2801306St.nateldemoura@f5.com         id = map->map[0].host;
2811306St.nateldemoura@f5.com 
2821306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_uid_t) id != nxt_euid)) {
2831306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has an entry for "
2841306St.nateldemoura@f5.com                     "host uid %d but unprivileged unit can only map itself "
2851306St.nateldemoura@f5.com                     "(uid %d) into child namespaces.", id, nxt_euid);
2861306St.nateldemoura@f5.com 
2871306St.nateldemoura@f5.com             return NXT_ERROR;
2881306St.nateldemoura@f5.com         }
2891306St.nateldemoura@f5.com 
2901306St.nateldemoura@f5.com         return NXT_OK;
2911306St.nateldemoura@f5.com     }
2921306St.nateldemoura@f5.com 
2931306St.nateldemoura@f5.com     for (i = 0; i < map->size; i++) {
2941306St.nateldemoura@f5.com         m = map->map[i];
2951306St.nateldemoura@f5.com 
2961306St.nateldemoura@f5.com         if (creds->uid >= (nxt_uid_t) m.container
2971306St.nateldemoura@f5.com             && creds->uid < (nxt_uid_t) (m.container + m.size))
2981306St.nateldemoura@f5.com         {
2991306St.nateldemoura@f5.com             return NXT_OK;
3001306St.nateldemoura@f5.com         }
3011306St.nateldemoura@f5.com     }
3021306St.nateldemoura@f5.com 
3031306St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has no \"container\" "
3041306St.nateldemoura@f5.com             "entry for user \"%s\" (uid %d)", creds->user, creds->uid);
3051306St.nateldemoura@f5.com 
3061306St.nateldemoura@f5.com     return NXT_ERROR;
3071306St.nateldemoura@f5.com }
3081306St.nateldemoura@f5.com 
3091306St.nateldemoura@f5.com 
3101306St.nateldemoura@f5.com nxt_int_t
3111306St.nateldemoura@f5.com nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
3121306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
3131306St.nateldemoura@f5.com {
3141306St.nateldemoura@f5.com     nxt_uint_t             base_ok, gid_ok, gids_ok;
3151306St.nateldemoura@f5.com     nxt_uint_t             i, j;
3161306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
3171306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
3181306St.nateldemoura@f5.com 
3191306St.nateldemoura@f5.com     rt = task->thread->runtime;
3201306St.nateldemoura@f5.com 
3211306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
3221306St.nateldemoura@f5.com         if (creds->ngroups > 0
3231306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) {
3241306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE,
3251306St.nateldemoura@f5.com                     "unprivileged unit disallow supplementary groups for "
3261306St.nateldemoura@f5.com                     "new namespace (user \"%s\" has %d group%s).",
3271306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
3281306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
3291306St.nateldemoura@f5.com 
3301306St.nateldemoura@f5.com             return NXT_ERROR;
3311306St.nateldemoura@f5.com         }
3321306St.nateldemoura@f5.com 
3331306St.nateldemoura@f5.com         if (map->size == 0) {
3341306St.nateldemoura@f5.com             return NXT_OK;
3351306St.nateldemoura@f5.com         }
3361306St.nateldemoura@f5.com 
3371306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
3381306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"gidmap\" field has %d entries "
3391306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
3401306St.nateldemoura@f5.com                     map->size);
3411306St.nateldemoura@f5.com 
3421306St.nateldemoura@f5.com             return NXT_ERROR;
3431306St.nateldemoura@f5.com         }
3441306St.nateldemoura@f5.com 
3451306St.nateldemoura@f5.com         m = map->map[0];
3461306St.nateldemoura@f5.com 
3471306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) {
3481306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for "
3491306St.nateldemoura@f5.com                     "host gid %d but unprivileged unit can only map itself "
3501306St.nateldemoura@f5.com                     "(gid %d) into child namespaces.", m.host, nxt_egid);
3511306St.nateldemoura@f5.com 
3521306St.nateldemoura@f5.com             return NXT_ERROR;
3531306St.nateldemoura@f5.com         }
3541306St.nateldemoura@f5.com 
3551306St.nateldemoura@f5.com         if (nxt_slow_path(m.size > 1)) {
3561306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with "
3571306St.nateldemoura@f5.com                     "\"size\": %d, but for unprivileged unit it must be 1.",
3581306St.nateldemoura@f5.com                     m.size);
3591306St.nateldemoura@f5.com 
3601306St.nateldemoura@f5.com             return NXT_ERROR;
3611306St.nateldemoura@f5.com         }
3621306St.nateldemoura@f5.com 
3631306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.container != creds->base_gid)) {
3641306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR,
3651306St.nateldemoura@f5.com                     "\"gidmap\" field has no \"container\" entry for gid %d.",
3661306St.nateldemoura@f5.com                     creds->base_gid);
3671306St.nateldemoura@f5.com 
3681306St.nateldemoura@f5.com             return NXT_ERROR;
3691306St.nateldemoura@f5.com         }
3701306St.nateldemoura@f5.com 
3711306St.nateldemoura@f5.com         return NXT_OK;
3721306St.nateldemoura@f5.com     }
3731306St.nateldemoura@f5.com 
3741306St.nateldemoura@f5.com     if (map->size == 0) {
3751306St.nateldemoura@f5.com         if (creds->ngroups > 0
3761306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid))
3771306St.nateldemoura@f5.com         {
3781306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no entries "
3791306St.nateldemoura@f5.com                     "but user \"%s\" has %d suplementary group%s.",
3801306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
3811306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
3821306St.nateldemoura@f5.com 
3831306St.nateldemoura@f5.com             return NXT_ERROR;
3841306St.nateldemoura@f5.com         }
3851306St.nateldemoura@f5.com 
3861306St.nateldemoura@f5.com         return NXT_OK;
387*2078Salx.manpages@gmail.com     }
3881306St.nateldemoura@f5.com 
3891306St.nateldemoura@f5.com     base_ok = 0;
3901306St.nateldemoura@f5.com     gids_ok = 0;
3911306St.nateldemoura@f5.com 
3921306St.nateldemoura@f5.com     for (i = 0; i < creds->ngroups; i++) {
3931306St.nateldemoura@f5.com         gid_ok = 0;
3941306St.nateldemoura@f5.com 
3951306St.nateldemoura@f5.com         for (j = 0; j < map->size; j++) {
3961306St.nateldemoura@f5.com             m = map->map[j];
3971306St.nateldemoura@f5.com 
3981306St.nateldemoura@f5.com             if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container
3991306St.nateldemoura@f5.com                 && creds->base_gid < (nxt_gid_t) (m.container+m.size))
4001306St.nateldemoura@f5.com             {
4011306St.nateldemoura@f5.com                 base_ok = 1;
4021306St.nateldemoura@f5.com             }
4031306St.nateldemoura@f5.com 
4041306St.nateldemoura@f5.com             if (creds->gids[i] >= (nxt_gid_t) m.container
4051306St.nateldemoura@f5.com                 && creds->gids[i] < (nxt_gid_t) (m.container+m.size))
4061306St.nateldemoura@f5.com             {
4071306St.nateldemoura@f5.com                 gid_ok = 1;
4081306St.nateldemoura@f5.com                 break;
4091306St.nateldemoura@f5.com             }
4101306St.nateldemoura@f5.com         }
4111306St.nateldemoura@f5.com 
4121306St.nateldemoura@f5.com         if (nxt_fast_path(gid_ok)) {
4131306St.nateldemoura@f5.com             gids_ok++;
4141306St.nateldemoura@f5.com         }
4151306St.nateldemoura@f5.com     }
4161306St.nateldemoura@f5.com 
4171306St.nateldemoura@f5.com     if (!base_ok) {
4181306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
4191306St.nateldemoura@f5.com             m = map->map[i];
4201306St.nateldemoura@f5.com 
4211306St.nateldemoura@f5.com             if (creds->base_gid >= (nxt_gid_t) m.container
4221306St.nateldemoura@f5.com                 && creds->base_gid < (nxt_gid_t) (m.container+m.size))
4231306St.nateldemoura@f5.com             {
4241306St.nateldemoura@f5.com                 base_ok = 1;
4251306St.nateldemoura@f5.com                 break;
4261306St.nateldemoura@f5.com             }
4271306St.nateldemoura@f5.com         }
4281306St.nateldemoura@f5.com     }
4291306St.nateldemoura@f5.com 
4301306St.nateldemoura@f5.com     if (nxt_slow_path(!base_ok)) {
4311306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no \"container\" "
4321306St.nateldemoura@f5.com                 "entry for gid %d.", creds->base_gid);
4331306St.nateldemoura@f5.com 
4341306St.nateldemoura@f5.com         return NXT_ERROR;
4351306St.nateldemoura@f5.com     }
4361306St.nateldemoura@f5.com 
4371306St.nateldemoura@f5.com     if (nxt_slow_path(gids_ok < creds->ngroups)) {
4381306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has missing "
4391306St.nateldemoura@f5.com                 "suplementary gid mappings (found %d out of %d).", gids_ok,
4401306St.nateldemoura@f5.com                 creds->ngroups);
4411306St.nateldemoura@f5.com 
4421306St.nateldemoura@f5.com         return NXT_ERROR;
4431306St.nateldemoura@f5.com     }
4441306St.nateldemoura@f5.com 
4451306St.nateldemoura@f5.com     return NXT_OK;
4461306St.nateldemoura@f5.com }
4471306St.nateldemoura@f5.com 
4481182St.nateldemoura@f5.com #endif
449