xref: /unit/src/nxt_clone.c (revision 1306)
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 
28*1306St.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);
30*1306St.nateldemoura@f5.com nxt_int_t nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile,
31*1306St.nateldemoura@f5.com     pid_t pid, nxt_int_t default_container, nxt_int_t default_host,
32*1306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map);
33*1306St.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
38*1306St.nateldemoura@f5.com nxt_clone_credential_setgroups(nxt_task_t *task, pid_t child_pid,
39*1306St.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
84*1306St.nateldemoura@f5.com nxt_clone_credential_map_write(nxt_task_t *task, const char *mapfile,
85*1306St.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
134*1306St.nateldemoura@f5.com nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid,
135*1306St.nateldemoura@f5.com     nxt_int_t default_container, nxt_int_t default_host,
136*1306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map)
1371182St.nateldemoura@f5.com {
138*1306St.nateldemoura@f5.com     u_char      *p, *end, *mapinfo;
139*1306St.nateldemoura@f5.com     nxt_int_t   ret, len;
140*1306St.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 
148*1306St.nateldemoura@f5.com     if (map->size > 0) {
149*1306St.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 
159*1306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
160*1306St.nateldemoura@f5.com             p = nxt_sprintf(p, end, "%d %d %d", map->map[i].container,
161*1306St.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)) {
164*1306St.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 
169*1306St.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;
184*1306St.nateldemoura@f5.com         p = nxt_sprintf(mapinfo, end, "%d %d 1",
185*1306St.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)) {
189*1306St.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 
195*1306St.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
204*1306St.nateldemoura@f5.com nxt_clone_credential_map(nxt_task_t *task, pid_t pid,
205*1306St.nateldemoura@f5.com     nxt_credential_t *app_creds, nxt_clone_t *clone)
2061182St.nateldemoura@f5.com {
2071182St.nateldemoura@f5.com     nxt_int_t      ret;
208*1306St.nateldemoura@f5.com     nxt_int_t      default_host_uid;
209*1306St.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;
214*1306St.nateldemoura@f5.com 
215*1306St.nateldemoura@f5.com     if (rt->capabilities.setid) {
216*1306St.nateldemoura@f5.com         rule = "allow";
2171182St.nateldemoura@f5.com 
218*1306St.nateldemoura@f5.com         /*
219*1306St.nateldemoura@f5.com          * By default we don't map a privileged user
220*1306St.nateldemoura@f5.com          */
221*1306St.nateldemoura@f5.com         default_host_uid = app_creds->uid;
222*1306St.nateldemoura@f5.com         default_host_gid = app_creds->base_gid;
223*1306St.nateldemoura@f5.com     } else {
224*1306St.nateldemoura@f5.com         rule = "deny";
2251182St.nateldemoura@f5.com 
226*1306St.nateldemoura@f5.com         default_host_uid = nxt_euid;
227*1306St.nateldemoura@f5.com         default_host_gid = nxt_egid;
228*1306St.nateldemoura@f5.com     }
229*1306St.nateldemoura@f5.com 
230*1306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "uid_map", pid, app_creds->uid,
231*1306St.nateldemoura@f5.com                                        default_host_uid,
232*1306St.nateldemoura@f5.com                                        &clone->uidmap);
233*1306St.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 
238*1306St.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 
244*1306St.nateldemoura@f5.com     ret = nxt_clone_credential_map_set(task, "gid_map", pid, app_creds->base_gid,
245*1306St.nateldemoura@f5.com                                        default_host_gid,
246*1306St.nateldemoura@f5.com                                        &clone->gidmap);
247*1306St.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 
255*1306St.nateldemoura@f5.com 
256*1306St.nateldemoura@f5.com nxt_int_t
257*1306St.nateldemoura@f5.com nxt_clone_vldt_credential_uidmap(nxt_task_t *task,
258*1306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
259*1306St.nateldemoura@f5.com {
260*1306St.nateldemoura@f5.com     nxt_int_t              id;
261*1306St.nateldemoura@f5.com     nxt_uint_t             i;
262*1306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
263*1306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
264*1306St.nateldemoura@f5.com 
265*1306St.nateldemoura@f5.com     if (map->size == 0) {
266*1306St.nateldemoura@f5.com         return NXT_OK;
267*1306St.nateldemoura@f5.com     }
268*1306St.nateldemoura@f5.com 
269*1306St.nateldemoura@f5.com     rt = task->thread->runtime;
270*1306St.nateldemoura@f5.com 
271*1306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
272*1306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
273*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has %d entries "
274*1306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
275*1306St.nateldemoura@f5.com                     map->size);
276*1306St.nateldemoura@f5.com 
277*1306St.nateldemoura@f5.com             return NXT_ERROR;
278*1306St.nateldemoura@f5.com         }
279*1306St.nateldemoura@f5.com 
280*1306St.nateldemoura@f5.com         id = map->map[0].host;
281*1306St.nateldemoura@f5.com 
282*1306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_uid_t) id != nxt_euid)) {
283*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has an entry for "
284*1306St.nateldemoura@f5.com                     "host uid %d but unprivileged unit can only map itself "
285*1306St.nateldemoura@f5.com                     "(uid %d) into child namespaces.", id, nxt_euid);
286*1306St.nateldemoura@f5.com 
287*1306St.nateldemoura@f5.com             return NXT_ERROR;
288*1306St.nateldemoura@f5.com         }
289*1306St.nateldemoura@f5.com 
290*1306St.nateldemoura@f5.com         return NXT_OK;
291*1306St.nateldemoura@f5.com     }
292*1306St.nateldemoura@f5.com 
293*1306St.nateldemoura@f5.com     for (i = 0; i < map->size; i++) {
294*1306St.nateldemoura@f5.com         m = map->map[i];
295*1306St.nateldemoura@f5.com 
296*1306St.nateldemoura@f5.com         if (creds->uid >= (nxt_uid_t) m.container
297*1306St.nateldemoura@f5.com             && creds->uid < (nxt_uid_t) (m.container + m.size))
298*1306St.nateldemoura@f5.com         {
299*1306St.nateldemoura@f5.com             return NXT_OK;
300*1306St.nateldemoura@f5.com         }
301*1306St.nateldemoura@f5.com     }
302*1306St.nateldemoura@f5.com 
303*1306St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_NOTICE, "\"uidmap\" field has no \"container\" "
304*1306St.nateldemoura@f5.com             "entry for user \"%s\" (uid %d)", creds->user, creds->uid);
305*1306St.nateldemoura@f5.com 
306*1306St.nateldemoura@f5.com     return NXT_ERROR;
307*1306St.nateldemoura@f5.com }
308*1306St.nateldemoura@f5.com 
309*1306St.nateldemoura@f5.com 
310*1306St.nateldemoura@f5.com nxt_int_t
311*1306St.nateldemoura@f5.com nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
312*1306St.nateldemoura@f5.com     nxt_clone_credential_map_t *map, nxt_credential_t *creds)
313*1306St.nateldemoura@f5.com {
314*1306St.nateldemoura@f5.com     nxt_uint_t             base_ok, gid_ok, gids_ok;
315*1306St.nateldemoura@f5.com     nxt_uint_t             i, j;
316*1306St.nateldemoura@f5.com     nxt_runtime_t          *rt;
317*1306St.nateldemoura@f5.com     nxt_clone_map_entry_t  m;
318*1306St.nateldemoura@f5.com 
319*1306St.nateldemoura@f5.com     rt = task->thread->runtime;
320*1306St.nateldemoura@f5.com 
321*1306St.nateldemoura@f5.com     if (!rt->capabilities.setid) {
322*1306St.nateldemoura@f5.com         if (creds->ngroups > 0
323*1306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid)) {
324*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE,
325*1306St.nateldemoura@f5.com                     "unprivileged unit disallow supplementary groups for "
326*1306St.nateldemoura@f5.com                     "new namespace (user \"%s\" has %d group%s).",
327*1306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
328*1306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
329*1306St.nateldemoura@f5.com 
330*1306St.nateldemoura@f5.com             return NXT_ERROR;
331*1306St.nateldemoura@f5.com         }
332*1306St.nateldemoura@f5.com 
333*1306St.nateldemoura@f5.com         if (map->size == 0) {
334*1306St.nateldemoura@f5.com             return NXT_OK;
335*1306St.nateldemoura@f5.com         }
336*1306St.nateldemoura@f5.com 
337*1306St.nateldemoura@f5.com         if (nxt_slow_path(map->size > 1)) {
338*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_NOTICE, "\"gidmap\" field has %d entries "
339*1306St.nateldemoura@f5.com                     "but unprivileged unit has a maximum of 1 map.",
340*1306St.nateldemoura@f5.com                     map->size);
341*1306St.nateldemoura@f5.com 
342*1306St.nateldemoura@f5.com             return NXT_ERROR;
343*1306St.nateldemoura@f5.com         }
344*1306St.nateldemoura@f5.com 
345*1306St.nateldemoura@f5.com         m = map->map[0];
346*1306St.nateldemoura@f5.com 
347*1306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) {
348*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for "
349*1306St.nateldemoura@f5.com                     "host gid %d but unprivileged unit can only map itself "
350*1306St.nateldemoura@f5.com                     "(gid %d) into child namespaces.", m.host, nxt_egid);
351*1306St.nateldemoura@f5.com 
352*1306St.nateldemoura@f5.com             return NXT_ERROR;
353*1306St.nateldemoura@f5.com         }
354*1306St.nateldemoura@f5.com 
355*1306St.nateldemoura@f5.com         if (nxt_slow_path(m.size > 1)) {
356*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with "
357*1306St.nateldemoura@f5.com                     "\"size\": %d, but for unprivileged unit it must be 1.",
358*1306St.nateldemoura@f5.com                     m.size);
359*1306St.nateldemoura@f5.com 
360*1306St.nateldemoura@f5.com             return NXT_ERROR;
361*1306St.nateldemoura@f5.com         }
362*1306St.nateldemoura@f5.com 
363*1306St.nateldemoura@f5.com         if (nxt_slow_path((nxt_gid_t) m.container != creds->base_gid)) {
364*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR,
365*1306St.nateldemoura@f5.com                     "\"gidmap\" field has no \"container\" entry for gid %d.",
366*1306St.nateldemoura@f5.com                     creds->base_gid);
367*1306St.nateldemoura@f5.com 
368*1306St.nateldemoura@f5.com             return NXT_ERROR;
369*1306St.nateldemoura@f5.com         }
370*1306St.nateldemoura@f5.com 
371*1306St.nateldemoura@f5.com         return NXT_OK;
372*1306St.nateldemoura@f5.com     }
373*1306St.nateldemoura@f5.com 
374*1306St.nateldemoura@f5.com     if (map->size == 0) {
375*1306St.nateldemoura@f5.com         if (creds->ngroups > 0
376*1306St.nateldemoura@f5.com             && !(creds->ngroups == 1 && creds->gids[0] == creds->base_gid))
377*1306St.nateldemoura@f5.com         {
378*1306St.nateldemoura@f5.com             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no entries "
379*1306St.nateldemoura@f5.com                     "but user \"%s\" has %d suplementary group%s.",
380*1306St.nateldemoura@f5.com                     creds->user, creds->ngroups,
381*1306St.nateldemoura@f5.com                     creds->ngroups > 1 ? "s" : "");
382*1306St.nateldemoura@f5.com 
383*1306St.nateldemoura@f5.com             return NXT_ERROR;
384*1306St.nateldemoura@f5.com         }
385*1306St.nateldemoura@f5.com 
386*1306St.nateldemoura@f5.com         return NXT_OK;
387*1306St.nateldemoura@f5.com    }
388*1306St.nateldemoura@f5.com 
389*1306St.nateldemoura@f5.com     base_ok = 0;
390*1306St.nateldemoura@f5.com     gids_ok = 0;
391*1306St.nateldemoura@f5.com 
392*1306St.nateldemoura@f5.com     for (i = 0; i < creds->ngroups; i++) {
393*1306St.nateldemoura@f5.com         gid_ok = 0;
394*1306St.nateldemoura@f5.com 
395*1306St.nateldemoura@f5.com         for (j = 0; j < map->size; j++) {
396*1306St.nateldemoura@f5.com             m = map->map[j];
397*1306St.nateldemoura@f5.com 
398*1306St.nateldemoura@f5.com             if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container
399*1306St.nateldemoura@f5.com                 && creds->base_gid < (nxt_gid_t) (m.container+m.size))
400*1306St.nateldemoura@f5.com             {
401*1306St.nateldemoura@f5.com                 base_ok = 1;
402*1306St.nateldemoura@f5.com             }
403*1306St.nateldemoura@f5.com 
404*1306St.nateldemoura@f5.com             if (creds->gids[i] >= (nxt_gid_t) m.container
405*1306St.nateldemoura@f5.com                 && creds->gids[i] < (nxt_gid_t) (m.container+m.size))
406*1306St.nateldemoura@f5.com             {
407*1306St.nateldemoura@f5.com                 gid_ok = 1;
408*1306St.nateldemoura@f5.com                 break;
409*1306St.nateldemoura@f5.com             }
410*1306St.nateldemoura@f5.com         }
411*1306St.nateldemoura@f5.com 
412*1306St.nateldemoura@f5.com         if (nxt_fast_path(gid_ok)) {
413*1306St.nateldemoura@f5.com             gids_ok++;
414*1306St.nateldemoura@f5.com         }
415*1306St.nateldemoura@f5.com     }
416*1306St.nateldemoura@f5.com 
417*1306St.nateldemoura@f5.com     if (!base_ok) {
418*1306St.nateldemoura@f5.com         for (i = 0; i < map->size; i++) {
419*1306St.nateldemoura@f5.com             m = map->map[i];
420*1306St.nateldemoura@f5.com 
421*1306St.nateldemoura@f5.com             if (creds->base_gid >= (nxt_gid_t) m.container
422*1306St.nateldemoura@f5.com                 && creds->base_gid < (nxt_gid_t) (m.container+m.size))
423*1306St.nateldemoura@f5.com             {
424*1306St.nateldemoura@f5.com                 base_ok = 1;
425*1306St.nateldemoura@f5.com                 break;
426*1306St.nateldemoura@f5.com             }
427*1306St.nateldemoura@f5.com         }
428*1306St.nateldemoura@f5.com     }
429*1306St.nateldemoura@f5.com 
430*1306St.nateldemoura@f5.com     if (nxt_slow_path(!base_ok)) {
431*1306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has no \"container\" "
432*1306St.nateldemoura@f5.com                 "entry for gid %d.", creds->base_gid);
433*1306St.nateldemoura@f5.com 
434*1306St.nateldemoura@f5.com         return NXT_ERROR;
435*1306St.nateldemoura@f5.com     }
436*1306St.nateldemoura@f5.com 
437*1306St.nateldemoura@f5.com     if (nxt_slow_path(gids_ok < creds->ngroups)) {
438*1306St.nateldemoura@f5.com         nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has missing "
439*1306St.nateldemoura@f5.com                 "suplementary gid mappings (found %d out of %d).", gids_ok,
440*1306St.nateldemoura@f5.com                 creds->ngroups);
441*1306St.nateldemoura@f5.com 
442*1306St.nateldemoura@f5.com         return NXT_ERROR;
443*1306St.nateldemoura@f5.com     }
444*1306St.nateldemoura@f5.com 
445*1306St.nateldemoura@f5.com     return NXT_OK;
446*1306St.nateldemoura@f5.com }
447*1306St.nateldemoura@f5.com 
4481182St.nateldemoura@f5.com #endif
449