xref: /unit/src/nxt_clone.c (revision 2629:116cb969f351)
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 
121182St.nateldemoura@f5.com #if (NXT_HAVE_CLONE_NEWUSER)
131182St.nateldemoura@f5.com 
141306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid,
151182St.nateldemoura@f5.com     const char *str);
161306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile,
171306St.nateldemoura@f5.com     pid_t pid, nxt_int_t default_container, nxt_int_t default_host,
181306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map);
191306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile,
201182St.nateldemoura@f5.com     pid_t pid, u_char *mapinfo);
211182St.nateldemoura@f5.com 
221182St.nateldemoura@f5.com 
231182St.nateldemoura@f5.com nxt_int_t
nxt_clone_credential_setgroups(nxt_task_t * task,pid_t child_pid,const char * str)241306St.nateldemoura@f5.com nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid,
251306St.nateldemoura@f5.com     const char *str)
261182St.nateldemoura@f5.com {
271182St.nateldemoura@f5.com     int     fd, n;
281182St.nateldemoura@f5.com     u_char  *p, *end;
291182St.nateldemoura@f5.com     u_char  path[PATH_MAX];
301182St.nateldemoura@f5.com 
311182St.nateldemoura@f5.com     end = path + PATH_MAX;
321182St.nateldemoura@f5.com     p = nxt_sprintf(path, end, "/proc/%d/setgroups", child_pid);
331182St.nateldemoura@f5.com     *p = '\0';
341182St.nateldemoura@f5.com 
351182St.nateldemoura@f5.com     if (nxt_slow_path(p == end)) {
361182St.nateldemoura@f5.com         nxt_alert(task, "error write past the buffer: %s", path);
371182St.nateldemoura@f5.com         return NXT_ERROR;
381182St.nateldemoura@f5.com     }
391182St.nateldemoura@f5.com 
401182St.nateldemoura@f5.com     fd = open((char *)path, O_RDWR);
411182St.nateldemoura@f5.com 
421182St.nateldemoura@f5.com     if (fd == -1) {
431182St.nateldemoura@f5.com         /*
441182St.nateldemoura@f5.com          * If the /proc/pid/setgroups doesn't exists, we are
451182St.nateldemoura@f5.com          * safe to set uid/gid maps. But if the error is anything
461182St.nateldemoura@f5.com          * other than ENOENT, then we should abort and let user know.
471182St.nateldemoura@f5.com          */
481182St.nateldemoura@f5.com 
491182St.nateldemoura@f5.com         if (errno != ENOENT) {
501182St.nateldemoura@f5.com             nxt_alert(task, "open(%s): %E", path, nxt_errno);
511182St.nateldemoura@f5.com             return NXT_ERROR;
521182St.nateldemoura@f5.com         }
531182St.nateldemoura@f5.com 
541182St.nateldemoura@f5.com         return NXT_OK;
551182St.nateldemoura@f5.com     }
561182St.nateldemoura@f5.com 
571182St.nateldemoura@f5.com     n = write(fd, str, strlen(str));
581182St.nateldemoura@f5.com     close(fd);
591182St.nateldemoura@f5.com 
601182St.nateldemoura@f5.com     if (nxt_slow_path(n == -1)) {
611182St.nateldemoura@f5.com         nxt_alert(task, "write(%s): %E", path, nxt_errno);
621182St.nateldemoura@f5.com         return NXT_ERROR;
631182St.nateldemoura@f5.com     }
641182St.nateldemoura@f5.com 
651182St.nateldemoura@f5.com     return NXT_OK;
661182St.nateldemoura@f5.com }
671182St.nateldemoura@f5.com 
681182St.nateldemoura@f5.com 
691182St.nateldemoura@f5.com nxt_int_t
nxt_clone_credential_map_write(nxt_task_t * task,const char * mapfile,pid_t pid,u_char * mapinfo)701306St.nateldemoura@f5.com nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile,
711306St.nateldemoura@f5.com     pid_t pid, u_char *mapinfo)
721182St.nateldemoura@f5.com {
731182St.nateldemoura@f5.com     int      len, mapfd;
741182St.nateldemoura@f5.com     u_char   *p, *end;
751182St.nateldemoura@f5.com     ssize_t  n;
761182St.nateldemoura@f5.com     u_char   buf[256];
771182St.nateldemoura@f5.com 
781182St.nateldemoura@f5.com     end = buf + sizeof(buf);
791182St.nateldemoura@f5.com 
801182St.nateldemoura@f5.com     p = nxt_sprintf(buf, end, "/proc/%d/%s", pid, mapfile);
811182St.nateldemoura@f5.com     if (nxt_slow_path(p == end)) {
821182St.nateldemoura@f5.com         nxt_alert(task, "writing past the buffer");
831182St.nateldemoura@f5.com         return NXT_ERROR;
841182St.nateldemoura@f5.com     }
851182St.nateldemoura@f5.com 
861182St.nateldemoura@f5.com     *p = '\0';
871182St.nateldemoura@f5.com 
881182St.nateldemoura@f5.com     mapfd = open((char*)buf, O_RDWR);
891182St.nateldemoura@f5.com     if (nxt_slow_path(mapfd == -1)) {
901182St.nateldemoura@f5.com         nxt_alert(task, "failed to open proc map (%s) %E", buf, nxt_errno);
911182St.nateldemoura@f5.com         return NXT_ERROR;
921182St.nateldemoura@f5.com     }
931182St.nateldemoura@f5.com 
941182St.nateldemoura@f5.com     len = nxt_strlen(mapinfo);
951182St.nateldemoura@f5.com 
961182St.nateldemoura@f5.com     n = write(mapfd, (char *)mapinfo, len);
971182St.nateldemoura@f5.com     if (nxt_slow_path(n != len)) {
981182St.nateldemoura@f5.com 
991182St.nateldemoura@f5.com         if (n == -1 && nxt_errno == EINVAL) {
1001182St.nateldemoura@f5.com             nxt_alert(task, "failed to write %s: Check kernel maximum " \
1011182St.nateldemoura@f5.com                       "allowed lines %E", buf, nxt_errno);
1021182St.nateldemoura@f5.com 
1031182St.nateldemoura@f5.com         } else {
1041182St.nateldemoura@f5.com             nxt_alert(task, "failed to write proc map (%s) %E", buf,
1051182St.nateldemoura@f5.com                       nxt_errno);
1061182St.nateldemoura@f5.com         }
1071182St.nateldemoura@f5.com 
1081201St.nateldemoura@f5.com         close(mapfd);
1091201St.nateldemoura@f5.com 
1101182St.nateldemoura@f5.com         return NXT_ERROR;
1111182St.nateldemoura@f5.com     }
1121182St.nateldemoura@f5.com 
1131201St.nateldemoura@f5.com     close(mapfd);
1141201St.nateldemoura@f5.com 
1151182St.nateldemoura@f5.com     return NXT_OK;
1161182St.nateldemoura@f5.com }
1171182St.nateldemoura@f5.com 
1181182St.nateldemoura@f5.com 
1191182St.nateldemoura@f5.com nxt_int_t
nxt_clone_credential_map_set(nxt_task_t * task,const char * mapfile,pid_t pid,nxt_int_t default_container,nxt_int_t default_host,nxt_clone_credential_map_t * map)1201306St.nateldemoura@f5.com nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid,
1211306St.nateldemoura@f5.com     nxt_int_t default_container, nxt_int_t default_host,
1221306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map)
1231182St.nateldemoura@f5.com {
1241306St.nateldemoura@f5.com     u_char      *p, *end, *mapinfo;
1251306St.nateldemoura@f5.com     nxt_int_t   ret, len;
1261306St.nateldemoura@f5.com     nxt_uint_t  i;
1271182St.nateldemoura@f5.com 
1281182St.nateldemoura@f5.com     /*
1291182St.nateldemoura@f5.com      * uid_map one-entry size:
1301182St.nateldemoura@f5.com      *   alloc space for 3 numbers (32bit) plus 2 spaces and \n.
1311182St.nateldemoura@f5.com      */
1321182St.nateldemoura@f5.com     len = sizeof(u_char) * (10 + 10 + 10 + 2 + 1);
1331182St.nateldemoura@f5.com 
1341306St.nateldemoura@f5.com     if (map->size > 0) {
1351306St.nateldemoura@f5.com         len = len * map->size + 1;
1361182St.nateldemoura@f5.com 
1371182St.nateldemoura@f5.com         mapinfo = nxt_malloc(len);
1381182St.nateldemoura@f5.com         if (nxt_slow_path(mapinfo == NULL)) {
1391182St.nateldemoura@f5.com             return NXT_ERROR;
1401182St.nateldemoura@f5.com         }
1411182St.nateldemoura@f5.com 
1421182St.nateldemoura@f5.com         p = mapinfo;
1431182St.nateldemoura@f5.com         end = mapinfo + len;
1441182St.nateldemoura@f5.com 
1451306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
146*2629Sa.clayton@nginx.com             p = nxt_sprintf(p, end, "%L %L %L", map->map[i].container,
1471306St.nateldemoura@f5.com                             map->map[i].host, map->map[i].size);
1481182St.nateldemoura@f5.com 
1491182St.nateldemoura@f5.com             if (nxt_slow_path(p == end)) {
1501306St.nateldemoura@f5.com                 nxt_alert(task, "write past the mapinfo buffer");
1511182St.nateldemoura@f5.com                 nxt_free(mapinfo);
1521182St.nateldemoura@f5.com                 return NXT_ERROR;
1531182St.nateldemoura@f5.com             }
1541182St.nateldemoura@f5.com 
1552617Szelenkov@nginx.com             if (i + 1 < map->size) {
1561182St.nateldemoura@f5.com                 *p++ = '\n';
1571182St.nateldemoura@f5.com 
1581182St.nateldemoura@f5.com             } else {
1591182St.nateldemoura@f5.com                 *p = '\0';
1601182St.nateldemoura@f5.com             }
1611182St.nateldemoura@f5.com         }
1621182St.nateldemoura@f5.com 
1631182St.nateldemoura@f5.com     } else {
1641182St.nateldemoura@f5.com         mapinfo = nxt_malloc(len);
1651182St.nateldemoura@f5.com         if (nxt_slow_path(mapinfo == NULL)) {
1661182St.nateldemoura@f5.com             return NXT_ERROR;
1671182St.nateldemoura@f5.com         }
1681182St.nateldemoura@f5.com 
1691182St.nateldemoura@f5.com         end = mapinfo + len;
1701306St.nateldemoura@f5.com         p = nxt_sprintf(mapinfo, end, "%d %d 1",
1711306St.nateldemoura@f5.com                         default_container, default_host);
1721182St.nateldemoura@f5.com         *p = '\0';
1731182St.nateldemoura@f5.com 
1741182St.nateldemoura@f5.com         if (nxt_slow_path(p == end)) {
1751306St.nateldemoura@f5.com             nxt_alert(task, "write past mapinfo buffer");
1761182St.nateldemoura@f5.com             nxt_free(mapinfo);
1771182St.nateldemoura@f5.com             return NXT_ERROR;
1781182St.nateldemoura@f5.com         }
1791182St.nateldemoura@f5.com     }
1801182St.nateldemoura@f5.com 
1811306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_write(task, mapfile, pid, mapinfo);
1821182St.nateldemoura@f5.com 
1831182St.nateldemoura@f5.com     nxt_free(mapinfo);
1841182St.nateldemoura@f5.com 
1851182St.nateldemoura@f5.com     return ret;
1861182St.nateldemoura@f5.com }
1871182St.nateldemoura@f5.com 
1881182St.nateldemoura@f5.com 
1891182St.nateldemoura@f5.com nxt_int_t
nxt_clone_credential_map(nxt_task_t * task,pid_t pid,nxt_credential_t * app_creds,nxt_clone_t * clone)1901306St.nateldemoura@f5.com nxt_clone_credential_map(nxt_task_t *task, pid_t pid,
1911306St.nateldemoura@f5.com     nxt_credential_t *app_creds, nxt_clone_t *clone)
1921182St.nateldemoura@f5.com {
1931182St.nateldemoura@f5.com     nxt_int_t      ret;
1941306St.nateldemoura@f5.com     nxt_int_t      default_host_uid;
1951306St.nateldemoura@f5.com     nxt_int_t      default_host_gid;
1961182St.nateldemoura@f5.com     const char     *rule;
1971182St.nateldemoura@f5.com     nxt_runtime_t  *rt;
1981182St.nateldemoura@f5.com 
1991182St.nateldemoura@f5.com     rt  = task->thread->runtime;
2001306St.nateldemoura@f5.com 
2011306St.nateldemoura@f5.com     if (rt->capabilities.setid) {
2021306St.nateldemoura@f5.com         rule = "allow";
2031182St.nateldemoura@f5.com 
2041306St.nateldemoura@f5.com         /*
2051306St.nateldemoura@f5.com          * By default we don't map a privileged user
2061306St.nateldemoura@f5.com          */
2071306St.nateldemoura@f5.com         default_host_uid = app_creds->uid;
2081306St.nateldemoura@f5.com         default_host_gid = app_creds->base_gid;
2091306St.nateldemoura@f5.com     } else {
2101306St.nateldemoura@f5.com         rule = "deny";
2111182St.nateldemoura@f5.com 
2121306St.nateldemoura@f5.com         default_host_uid = nxt_euid;
2131306St.nateldemoura@f5.com         default_host_gid = nxt_egid;
2141306St.nateldemoura@f5.com     }
2151306St.nateldemoura@f5.com 
2161306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "uid_map", pid, app_creds->uid,
2171306St.nateldemoura@f5.com                                        default_host_uid,
2181306St.nateldemoura@f5.com                                        &clone->uidmap);
2191306St.nateldemoura@f5.com 
2201182St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
2211182St.nateldemoura@f5.com         return NXT_ERROR;
2221182St.nateldemoura@f5.com     }
2231182St.nateldemoura@f5.com 
2241306St.nateldemoura@f5.com     ret = nxt_clone_credential_setgroups(task, pid, rule);
2251182St.nateldemoura@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
2261182St.nateldemoura@f5.com         nxt_alert(task, "failed to write /proc/%d/setgroups", pid);
2271182St.nateldemoura@f5.com         return NXT_ERROR;
2281182St.nateldemoura@f5.com     }
2291182St.nateldemoura@f5.com 
2301306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "gid_map", pid, app_creds->base_gid,
2311306St.nateldemoura@f5.com                                        default_host_gid,
2321306St.nateldemoura@f5.com                                        &clone->gidmap);
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 
2381182St.nateldemoura@f5.com     return NXT_OK;
2391182St.nateldemoura@f5.com }
2401182St.nateldemoura@f5.com 
2411306St.nateldemoura@f5.com 
2421306St.nateldemoura@f5.com nxt_int_t
nxt_clone_vldt_credential_uidmap(nxt_task_t * task,nxt_clone_credential_map_t * map,nxt_credential_t * creds)2431306St.nateldemoura@f5.com nxt_clone_vldt_credential_uidmap(nxt_task_t *task,
2441306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
2451306St.nateldemoura@f5.com {
2461306St.nateldemoura@f5.com     nxt_int_t              id;
2471306St.nateldemoura@f5.com     nxt_uint_t             i;
2481306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
2491306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
2501306St.nateldemoura@f5.com 
2511306St.nateldemoura@f5.com     if (map->size == 0) {
2521306St.nateldemoura@f5.com         return NXT_OK;
2531306St.nateldemoura@f5.com     }
2541306St.nateldemoura@f5.com 
2551306St.nateldemoura@f5.com     rt = task->thread->runtime;
2561306St.nateldemoura@f5.com 
2571306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
2581306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
2591306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has %d entries "
2601306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
2611306St.nateldemoura@f5.com                     map->size);
2621306St.nateldemoura@f5.com 
2631306St.nateldemoura@f5.com             return NXT_ERROR;
2641306St.nateldemoura@f5.com         }
2651306St.nateldemoura@f5.com 
2661306St.nateldemoura@f5.com         id = map->map[0].host;
2671306St.nateldemoura@f5.com 
2681306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_uid_t) id != nxt_euid)) {
2691306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has an entry for "
2701306St.nateldemoura@f5.com                     "host uid %d but unprivileged unit can only map itself "
2711306St.nateldemoura@f5.com                     "(uid %d) into child namespaces.", id, nxt_euid);
2721306St.nateldemoura@f5.com 
2731306St.nateldemoura@f5.com             return NXT_ERROR;
2741306St.nateldemoura@f5.com         }
2751306St.nateldemoura@f5.com 
2761306St.nateldemoura@f5.com         return NXT_OK;
2771306St.nateldemoura@f5.com     }
2781306St.nateldemoura@f5.com 
2791306St.nateldemoura@f5.com     for (i = 0; i < map->size; i++) {
2801306St.nateldemoura@f5.com         m = map->map[i];
2811306St.nateldemoura@f5.com 
2821306St.nateldemoura@f5.com         if (creds->uid >= (nxt_uid_t) m.container
2831306St.nateldemoura@f5.com             && creds->uid < (nxt_uid_t) (m.container + m.size))
2841306St.nateldemoura@f5.com         {
2851306St.nateldemoura@f5.com             return NXT_OK;
2861306St.nateldemoura@f5.com         }
2871306St.nateldemoura@f5.com     }
2881306St.nateldemoura@f5.com 
2891306St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has no \"container\" "
2901306St.nateldemoura@f5.com             "entry for user \"%s\" (uid %d)", creds->user, creds->uid);
2911306St.nateldemoura@f5.com 
2921306St.nateldemoura@f5.com     return NXT_ERROR;
2931306St.nateldemoura@f5.com }
2941306St.nateldemoura@f5.com 
2951306St.nateldemoura@f5.com 
2961306St.nateldemoura@f5.com nxt_int_t
nxt_clone_vldt_credential_gidmap(nxt_task_t * task,nxt_clone_credential_map_t * map,nxt_credential_t * creds)2971306St.nateldemoura@f5.com nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
2981306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
2991306St.nateldemoura@f5.com {
3001306St.nateldemoura@f5.com     nxt_uint_t             base_ok, gid_ok, gids_ok;
3011306St.nateldemoura@f5.com     nxt_uint_t             i, j;
3021306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
3031306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
3041306St.nateldemoura@f5.com 
3051306St.nateldemoura@f5.com     rt = task->thread->runtime;
3061306St.nateldemoura@f5.com 
3071306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
3081306St.nateldemoura@f5.com         if (creds->ngroups > 0
3091306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) {
3101306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE,
3111306St.nateldemoura@f5.com                     "unprivileged unit disallow supplementary groups for "
3121306St.nateldemoura@f5.com                     "new namespace (user \"%s\" has %d group%s).",
3131306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
3141306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
3151306St.nateldemoura@f5.com 
3161306St.nateldemoura@f5.com             return NXT_ERROR;
3171306St.nateldemoura@f5.com         }
3181306St.nateldemoura@f5.com 
3191306St.nateldemoura@f5.com         if (map->size == 0) {
3201306St.nateldemoura@f5.com             return NXT_OK;
3211306St.nateldemoura@f5.com         }
3221306St.nateldemoura@f5.com 
3231306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
3241306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"gidmap\" field has %d entries "
3251306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
3261306St.nateldemoura@f5.com                     map->size);
3271306St.nateldemoura@f5.com 
3281306St.nateldemoura@f5.com             return NXT_ERROR;
3291306St.nateldemoura@f5.com         }
3301306St.nateldemoura@f5.com 
3311306St.nateldemoura@f5.com         m = map->map[0];
3321306St.nateldemoura@f5.com 
3331306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) {
3341306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for "
335*2629Sa.clayton@nginx.com                     "host gid %L but unprivileged unit can only map itself "
3361306St.nateldemoura@f5.com                     "(gid %d) into child namespaces.", m.host, nxt_egid);
3371306St.nateldemoura@f5.com 
3381306St.nateldemoura@f5.com             return NXT_ERROR;
3391306St.nateldemoura@f5.com         }
3401306St.nateldemoura@f5.com 
3411306St.nateldemoura@f5.com         if (nxt_slow_path(m.size > 1)) {
3421306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with "
343*2629Sa.clayton@nginx.com                     "\"size\": %L, but for unprivileged unit it must be 1.",
3441306St.nateldemoura@f5.com                     m.size);
3451306St.nateldemoura@f5.com 
3461306St.nateldemoura@f5.com             return NXT_ERROR;
3471306St.nateldemoura@f5.com         }
3481306St.nateldemoura@f5.com 
3491306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.container != creds->base_gid)) {
3501306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR,
3511306St.nateldemoura@f5.com                     "\"gidmap\" field has no \"container\" entry for gid %d.",
3521306St.nateldemoura@f5.com                     creds->base_gid);
3531306St.nateldemoura@f5.com 
3541306St.nateldemoura@f5.com             return NXT_ERROR;
3551306St.nateldemoura@f5.com         }
3561306St.nateldemoura@f5.com 
3571306St.nateldemoura@f5.com         return NXT_OK;
3581306St.nateldemoura@f5.com     }
3591306St.nateldemoura@f5.com 
3601306St.nateldemoura@f5.com     if (map->size == 0) {
3611306St.nateldemoura@f5.com         if (creds->ngroups > 0
3621306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid))
3631306St.nateldemoura@f5.com         {
3641306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no entries "
3651306St.nateldemoura@f5.com                     "but user \"%s\" has %d suplementary group%s.",
3661306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
3671306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
3681306St.nateldemoura@f5.com 
3691306St.nateldemoura@f5.com             return NXT_ERROR;
3701306St.nateldemoura@f5.com         }
3711306St.nateldemoura@f5.com 
3721306St.nateldemoura@f5.com         return NXT_OK;
3732078Salx.manpages@gmail.com     }
3741306St.nateldemoura@f5.com 
3751306St.nateldemoura@f5.com     base_ok = 0;
3761306St.nateldemoura@f5.com     gids_ok = 0;
3771306St.nateldemoura@f5.com 
3781306St.nateldemoura@f5.com     for (i = 0; i < creds->ngroups; i++) {
3791306St.nateldemoura@f5.com         gid_ok = 0;
3801306St.nateldemoura@f5.com 
3811306St.nateldemoura@f5.com         for (j = 0; j < map->size; j++) {
3821306St.nateldemoura@f5.com             m = map->map[j];
3831306St.nateldemoura@f5.com 
3841306St.nateldemoura@f5.com             if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container
3852617Szelenkov@nginx.com                 && creds->base_gid < (nxt_gid_t) (m.container + m.size))
3861306St.nateldemoura@f5.com             {
3871306St.nateldemoura@f5.com                 base_ok = 1;
3881306St.nateldemoura@f5.com             }
3891306St.nateldemoura@f5.com 
3901306St.nateldemoura@f5.com             if (creds->gids[i] >= (nxt_gid_t) m.container
3912617Szelenkov@nginx.com                 && creds->gids[i] < (nxt_gid_t) (m.container + m.size))
3921306St.nateldemoura@f5.com             {
3931306St.nateldemoura@f5.com                 gid_ok = 1;
3941306St.nateldemoura@f5.com                 break;
3951306St.nateldemoura@f5.com             }
3961306St.nateldemoura@f5.com         }
3971306St.nateldemoura@f5.com 
3981306St.nateldemoura@f5.com         if (nxt_fast_path(gid_ok)) {
3991306St.nateldemoura@f5.com             gids_ok++;
4001306St.nateldemoura@f5.com         }
4011306St.nateldemoura@f5.com     }
4021306St.nateldemoura@f5.com 
4031306St.nateldemoura@f5.com     if (!base_ok) {
4041306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
4051306St.nateldemoura@f5.com             m = map->map[i];
4061306St.nateldemoura@f5.com 
4071306St.nateldemoura@f5.com             if (creds->base_gid >= (nxt_gid_t) m.container
4082617Szelenkov@nginx.com                 && creds->base_gid < (nxt_gid_t) (m.container + m.size))
4091306St.nateldemoura@f5.com             {
4101306St.nateldemoura@f5.com                 base_ok = 1;
4111306St.nateldemoura@f5.com                 break;
4121306St.nateldemoura@f5.com             }
4131306St.nateldemoura@f5.com         }
4141306St.nateldemoura@f5.com     }
4151306St.nateldemoura@f5.com 
4161306St.nateldemoura@f5.com     if (nxt_slow_path(!base_ok)) {
4171306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no \"container\" "
4181306St.nateldemoura@f5.com                 "entry for gid %d.", creds->base_gid);
4191306St.nateldemoura@f5.com 
4201306St.nateldemoura@f5.com         return NXT_ERROR;
4211306St.nateldemoura@f5.com     }
4221306St.nateldemoura@f5.com 
4231306St.nateldemoura@f5.com     if (nxt_slow_path(gids_ok < creds->ngroups)) {
4241306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has missing "
4251306St.nateldemoura@f5.com                 "suplementary gid mappings (found %d out of %d).", gids_ok,
4261306St.nateldemoura@f5.com                 creds->ngroups);
4271306St.nateldemoura@f5.com 
4281306St.nateldemoura@f5.com         return NXT_ERROR;
4291306St.nateldemoura@f5.com     }
4301306St.nateldemoura@f5.com 
4311306St.nateldemoura@f5.com     return NXT_OK;
4321306St.nateldemoura@f5.com }
4331306St.nateldemoura@f5.com 
4341182St.nateldemoura@f5.com #endif
435