]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nss-mymachines/nss-mymachines.c
Revert "nss: prevent PROTECT_ERRNO from squashing changes to *errnop"
[thirdparty/systemd.git] / src / nss-mymachines / nss-mymachines.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netdb.h>
4 #include <nss.h>
5
6 #include "sd-bus.h"
7 #include "sd-login.h"
8
9 #include "alloc-util.h"
10 #include "bus-common-errors.h"
11 #include "env-util.h"
12 #include "hostname-util.h"
13 #include "in-addr-util.h"
14 #include "macro.h"
15 #include "nss-util.h"
16 #include "signal-util.h"
17 #include "string-util.h"
18 #include "user-util.h"
19 #include "util.h"
20
21 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
22 NSS_GETPW_PROTOTYPES(mymachines);
23 NSS_GETGR_PROTOTYPES(mymachines);
24
25 #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
26 #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
27
28 static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
29 unsigned c = 0;
30 int r;
31
32 assert(m);
33 assert(ret);
34
35 while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) {
36 int family;
37
38 r = sd_bus_message_read(m, "i", &family);
39 if (r < 0)
40 return r;
41
42 r = sd_bus_message_skip(m, "ay");
43 if (r < 0)
44 return r;
45
46 r = sd_bus_message_exit_container(m);
47 if (r < 0)
48 return r;
49
50 if (af != AF_UNSPEC && family != af)
51 continue;
52
53 c++;
54 }
55 if (r < 0)
56 return r;
57
58 r = sd_bus_message_rewind(m, false);
59 if (r < 0)
60 return r;
61
62 *ret = c;
63 return 0;
64 }
65
66 static bool avoid_deadlock(void) {
67
68 /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
69 * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to
70 * systemd-machined if we are required to finish before it can be started. This of course won't detect all
71 * possible dead locks of this kind, but it should work for the most obvious cases. */
72
73 if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
74 return false;
75
76 return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") &&
77 streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
78 }
79
80 enum nss_status _nss_mymachines_gethostbyname4_r(
81 const char *name,
82 struct gaih_addrtuple **pat,
83 char *buffer, size_t buflen,
84 int *errnop, int *h_errnop,
85 int32_t *ttlp) {
86
87 struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
88 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
89 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
90 _cleanup_free_ int *ifindices = NULL;
91 _cleanup_free_ char *class = NULL;
92 size_t l, ms, idx;
93 unsigned i = 0, c = 0;
94 char *r_name;
95 int n_ifindices, r;
96
97 PROTECT_ERRNO;
98 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
99
100 assert(name);
101 assert(pat);
102 assert(buffer);
103 assert(errnop);
104 assert(h_errnop);
105
106 r = sd_machine_get_class(name, &class);
107 if (r < 0)
108 goto fail;
109 if (!streq(class, "container")) {
110 r = -ENOTTY;
111 goto fail;
112 }
113
114 n_ifindices = sd_machine_get_ifindices(name, &ifindices);
115 if (n_ifindices < 0) {
116 r = n_ifindices;
117 goto fail;
118 }
119
120 if (avoid_deadlock()) {
121 r = -EDEADLK;
122 goto fail;
123 }
124
125 r = sd_bus_open_system(&bus);
126 if (r < 0)
127 goto fail;
128
129 r = sd_bus_call_method(bus,
130 "org.freedesktop.machine1",
131 "/org/freedesktop/machine1",
132 "org.freedesktop.machine1.Manager",
133 "GetMachineAddresses",
134 NULL,
135 &reply,
136 "s", name);
137 if (r < 0)
138 goto fail;
139
140 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
141 if (r < 0)
142 goto fail;
143
144 r = count_addresses(reply, AF_UNSPEC, &c);
145 if (r < 0)
146 goto fail;
147
148 if (c <= 0) {
149 *h_errnop = HOST_NOT_FOUND;
150 return NSS_STATUS_NOTFOUND;
151 }
152
153 l = strlen(name);
154 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
155 if (buflen < ms) {
156 *errnop = ERANGE;
157 *h_errnop = NETDB_INTERNAL;
158 return NSS_STATUS_TRYAGAIN;
159 }
160
161 /* First, append name */
162 r_name = buffer;
163 memcpy(r_name, name, l+1);
164 idx = ALIGN(l+1);
165
166 /* Second, append addresses */
167 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
168 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
169 int family;
170 const void *a;
171 size_t sz;
172
173 r = sd_bus_message_read(reply, "i", &family);
174 if (r < 0)
175 goto fail;
176
177 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
178 if (r < 0)
179 goto fail;
180
181 r = sd_bus_message_exit_container(reply);
182 if (r < 0)
183 goto fail;
184
185 if (!IN_SET(family, AF_INET, AF_INET6)) {
186 r = -EAFNOSUPPORT;
187 goto fail;
188 }
189
190 if (sz != FAMILY_ADDRESS_SIZE(family)) {
191 r = -EINVAL;
192 goto fail;
193 }
194
195 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
196 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
197 r_tuple->name = r_name;
198 r_tuple->family = family;
199 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
200 memcpy(r_tuple->addr, a, sz);
201
202 idx += ALIGN(sizeof(struct gaih_addrtuple));
203 i++;
204 }
205
206 assert(i == c);
207
208 r = sd_bus_message_exit_container(reply);
209 if (r < 0)
210 goto fail;
211
212 assert(idx == ms);
213
214 if (*pat)
215 **pat = *r_tuple_first;
216 else
217 *pat = r_tuple_first;
218
219 if (ttlp)
220 *ttlp = 0;
221
222 /* Explicitly reset both *h_errnop and h_errno to work around
223 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
224 *h_errnop = NETDB_SUCCESS;
225 h_errno = 0;
226
227 return NSS_STATUS_SUCCESS;
228
229 fail:
230 *errnop = -r;
231 *h_errnop = NO_DATA;
232 return NSS_STATUS_UNAVAIL;
233 }
234
235 enum nss_status _nss_mymachines_gethostbyname3_r(
236 const char *name,
237 int af,
238 struct hostent *result,
239 char *buffer, size_t buflen,
240 int *errnop, int *h_errnop,
241 int32_t *ttlp,
242 char **canonp) {
243
244 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
245 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
246 _cleanup_free_ char *class = NULL;
247 unsigned c = 0, i = 0;
248 char *r_name, *r_aliases, *r_addr, *r_addr_list;
249 size_t l, idx, ms, alen;
250 int r;
251
252 PROTECT_ERRNO;
253 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
254
255 assert(name);
256 assert(result);
257 assert(buffer);
258 assert(errnop);
259 assert(h_errnop);
260
261 if (af == AF_UNSPEC)
262 af = AF_INET;
263
264 if (af != AF_INET && af != AF_INET6) {
265 r = -EAFNOSUPPORT;
266 goto fail;
267 }
268
269 r = sd_machine_get_class(name, &class);
270 if (r < 0)
271 goto fail;
272 if (!streq(class, "container")) {
273 r = -ENOTTY;
274 goto fail;
275 }
276
277 if (avoid_deadlock()) {
278 r = -EDEADLK;
279 goto fail;
280 }
281
282 r = sd_bus_open_system(&bus);
283 if (r < 0)
284 goto fail;
285
286 r = sd_bus_call_method(bus,
287 "org.freedesktop.machine1",
288 "/org/freedesktop/machine1",
289 "org.freedesktop.machine1.Manager",
290 "GetMachineAddresses",
291 NULL,
292 &reply,
293 "s", name);
294 if (r < 0)
295 goto fail;
296
297 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
298 if (r < 0)
299 goto fail;
300
301 r = count_addresses(reply, af, &c);
302 if (r < 0)
303 goto fail;
304
305 if (c <= 0) {
306 *h_errnop = HOST_NOT_FOUND;
307 return NSS_STATUS_NOTFOUND;
308 }
309
310 alen = FAMILY_ADDRESS_SIZE(af);
311 l = strlen(name);
312
313 ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
314
315 if (buflen < ms) {
316 *errnop = ERANGE;
317 *h_errnop = NETDB_INTERNAL;
318 return NSS_STATUS_TRYAGAIN;
319 }
320
321 /* First, append name */
322 r_name = buffer;
323 memcpy(r_name, name, l+1);
324 idx = ALIGN(l+1);
325
326 /* Second, create aliases array */
327 r_aliases = buffer + idx;
328 ((char**) r_aliases)[0] = NULL;
329 idx += sizeof(char*);
330
331 /* Third, append addresses */
332 r_addr = buffer + idx;
333 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
334 int family;
335 const void *a;
336 size_t sz;
337
338 r = sd_bus_message_read(reply, "i", &family);
339 if (r < 0)
340 goto fail;
341
342 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
343 if (r < 0)
344 goto fail;
345
346 r = sd_bus_message_exit_container(reply);
347 if (r < 0)
348 goto fail;
349
350 if (family != af)
351 continue;
352
353 if (sz != alen) {
354 r = -EINVAL;
355 goto fail;
356 }
357
358 memcpy(r_addr + i*ALIGN(alen), a, alen);
359 i++;
360 }
361
362 assert(i == c);
363 idx += c * ALIGN(alen);
364
365 r = sd_bus_message_exit_container(reply);
366 if (r < 0)
367 goto fail;
368
369 /* Third, append address pointer array */
370 r_addr_list = buffer + idx;
371 for (i = 0; i < c; i++)
372 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
373
374 ((char**) r_addr_list)[i] = NULL;
375 idx += (c+1) * sizeof(char*);
376
377 assert(idx == ms);
378
379 result->h_name = r_name;
380 result->h_aliases = (char**) r_aliases;
381 result->h_addrtype = af;
382 result->h_length = alen;
383 result->h_addr_list = (char**) r_addr_list;
384
385 if (ttlp)
386 *ttlp = 0;
387
388 if (canonp)
389 *canonp = r_name;
390
391 /* Explicitly reset both *h_errnop and h_errno to work around
392 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
393 *h_errnop = NETDB_SUCCESS;
394 h_errno = 0;
395
396 return NSS_STATUS_SUCCESS;
397
398 fail:
399 *errnop = -r;
400 *h_errnop = NO_DATA;
401 return NSS_STATUS_UNAVAIL;
402 }
403
404 NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
405
406 enum nss_status _nss_mymachines_getpwnam_r(
407 const char *name,
408 struct passwd *pwd,
409 char *buffer, size_t buflen,
410 int *errnop) {
411
412 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
413 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
414 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
415 const char *p, *e, *machine;
416 uint32_t mapped;
417 uid_t uid;
418 size_t l;
419 int r;
420
421 PROTECT_ERRNO;
422 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
423
424 assert(name);
425 assert(pwd);
426
427 p = startswith(name, "vu-");
428 if (!p)
429 return NSS_STATUS_NOTFOUND;
430
431 e = strrchr(p, '-');
432 if (!e || e == p)
433 return NSS_STATUS_NOTFOUND;
434
435 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
436 return NSS_STATUS_NOTFOUND;
437
438 r = parse_uid(e + 1, &uid);
439 if (r < 0)
440 return NSS_STATUS_NOTFOUND;
441
442 machine = strndupa(p, e - p);
443 if (!machine_name_is_valid(machine))
444 return NSS_STATUS_NOTFOUND;
445
446 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
447 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
448 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
449 * running on the host. */
450 return NSS_STATUS_NOTFOUND;
451
452 if (avoid_deadlock()) {
453 r = -EDEADLK;
454 goto fail;
455 }
456
457 r = sd_bus_open_system(&bus);
458 if (r < 0)
459 goto fail;
460
461 r = sd_bus_call_method(bus,
462 "org.freedesktop.machine1",
463 "/org/freedesktop/machine1",
464 "org.freedesktop.machine1.Manager",
465 "MapFromMachineUser",
466 &error,
467 &reply,
468 "su",
469 machine, (uint32_t) uid);
470 if (r < 0) {
471 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
472 return NSS_STATUS_NOTFOUND;
473
474 goto fail;
475 }
476
477 r = sd_bus_message_read(reply, "u", &mapped);
478 if (r < 0)
479 goto fail;
480
481 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
482 if (mapped < HOST_UID_LIMIT || mapped == uid)
483 return NSS_STATUS_NOTFOUND;
484
485 l = strlen(name);
486 if (buflen < l+1) {
487 *errnop = ERANGE;
488 return NSS_STATUS_TRYAGAIN;
489 }
490
491 memcpy(buffer, name, l+1);
492
493 pwd->pw_name = buffer;
494 pwd->pw_uid = mapped;
495 pwd->pw_gid = GID_NOBODY;
496 pwd->pw_gecos = buffer;
497 pwd->pw_passwd = (char*) "*"; /* locked */
498 pwd->pw_dir = (char*) "/";
499 pwd->pw_shell = (char*) "/sbin/nologin";
500
501 return NSS_STATUS_SUCCESS;
502
503 fail:
504 *errnop = -r;
505 return NSS_STATUS_UNAVAIL;
506 }
507
508 enum nss_status _nss_mymachines_getpwuid_r(
509 uid_t uid,
510 struct passwd *pwd,
511 char *buffer, size_t buflen,
512 int *errnop) {
513
514 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
515 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
516 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
517 const char *machine;
518 uint32_t mapped;
519 int r;
520
521 PROTECT_ERRNO;
522 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
523
524 if (!uid_is_valid(uid))
525 return NSS_STATUS_NOTFOUND;
526
527 /* We consider all uids < 65536 host uids */
528 if (uid < HOST_UID_LIMIT)
529 return NSS_STATUS_NOTFOUND;
530
531 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
532 return NSS_STATUS_NOTFOUND;
533
534 if (avoid_deadlock()) {
535 r = -EDEADLK;
536 goto fail;
537 }
538
539 r = sd_bus_open_system(&bus);
540 if (r < 0)
541 goto fail;
542
543 r = sd_bus_call_method(bus,
544 "org.freedesktop.machine1",
545 "/org/freedesktop/machine1",
546 "org.freedesktop.machine1.Manager",
547 "MapToMachineUser",
548 &error,
549 &reply,
550 "u",
551 (uint32_t) uid);
552 if (r < 0) {
553 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
554 return NSS_STATUS_NOTFOUND;
555
556 goto fail;
557 }
558
559 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
560 if (r < 0)
561 goto fail;
562
563 if (mapped == uid)
564 return NSS_STATUS_NOTFOUND;
565
566 if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
567 *errnop = ERANGE;
568 return NSS_STATUS_TRYAGAIN;
569 }
570
571 pwd->pw_name = buffer;
572 pwd->pw_uid = uid;
573 pwd->pw_gid = GID_NOBODY;
574 pwd->pw_gecos = buffer;
575 pwd->pw_passwd = (char*) "*"; /* locked */
576 pwd->pw_dir = (char*) "/";
577 pwd->pw_shell = (char*) "/sbin/nologin";
578
579 return NSS_STATUS_SUCCESS;
580
581 fail:
582 *errnop = -r;
583 return NSS_STATUS_UNAVAIL;
584 }
585
586 #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
587
588 enum nss_status _nss_mymachines_getgrnam_r(
589 const char *name,
590 struct group *gr,
591 char *buffer, size_t buflen,
592 int *errnop) {
593
594 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
595 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
596 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
597 const char *p, *e, *machine;
598 uint32_t mapped;
599 uid_t gid;
600 size_t l;
601 int r;
602
603 PROTECT_ERRNO;
604 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
605
606 assert(name);
607 assert(gr);
608
609 p = startswith(name, "vg-");
610 if (!p)
611 return NSS_STATUS_NOTFOUND;
612
613 e = strrchr(p, '-');
614 if (!e || e == p)
615 return NSS_STATUS_NOTFOUND;
616
617 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
618 return NSS_STATUS_NOTFOUND;
619
620 r = parse_gid(e + 1, &gid);
621 if (r < 0)
622 return NSS_STATUS_NOTFOUND;
623
624 machine = strndupa(p, e - p);
625 if (!machine_name_is_valid(machine))
626 return NSS_STATUS_NOTFOUND;
627
628 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
629 return NSS_STATUS_NOTFOUND;
630
631 if (avoid_deadlock()) {
632 r = -EDEADLK;
633 goto fail;
634 }
635
636 r = sd_bus_open_system(&bus);
637 if (r < 0)
638 goto fail;
639
640 r = sd_bus_call_method(bus,
641 "org.freedesktop.machine1",
642 "/org/freedesktop/machine1",
643 "org.freedesktop.machine1.Manager",
644 "MapFromMachineGroup",
645 &error,
646 &reply,
647 "su",
648 machine, (uint32_t) gid);
649 if (r < 0) {
650 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
651 return NSS_STATUS_NOTFOUND;
652
653 goto fail;
654 }
655
656 r = sd_bus_message_read(reply, "u", &mapped);
657 if (r < 0)
658 goto fail;
659
660 if (mapped < HOST_GID_LIMIT || mapped == gid)
661 return NSS_STATUS_NOTFOUND;
662
663 l = sizeof(char*) + strlen(name) + 1;
664 if (buflen < l) {
665 *errnop = ERANGE;
666 return NSS_STATUS_TRYAGAIN;
667 }
668
669 memzero(buffer, sizeof(char*));
670 strcpy(buffer + sizeof(char*), name);
671
672 gr->gr_name = buffer + sizeof(char*);
673 gr->gr_gid = mapped;
674 gr->gr_passwd = (char*) "*"; /* locked */
675 gr->gr_mem = (char**) buffer;
676
677 return NSS_STATUS_SUCCESS;
678
679 fail:
680 *errnop = -r;
681 return NSS_STATUS_UNAVAIL;
682 }
683
684 enum nss_status _nss_mymachines_getgrgid_r(
685 gid_t gid,
686 struct group *gr,
687 char *buffer, size_t buflen,
688 int *errnop) {
689
690 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
691 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
692 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
693 const char *machine;
694 uint32_t mapped;
695 int r;
696
697 PROTECT_ERRNO;
698 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
699
700 if (!gid_is_valid(gid))
701 return NSS_STATUS_NOTFOUND;
702
703 /* We consider all gids < 65536 host gids */
704 if (gid < HOST_GID_LIMIT)
705 return NSS_STATUS_NOTFOUND;
706
707 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
708 return NSS_STATUS_NOTFOUND;
709
710 if (avoid_deadlock()) {
711 r = -EDEADLK;
712 goto fail;
713 }
714
715 r = sd_bus_open_system(&bus);
716 if (r < 0)
717 goto fail;
718
719 r = sd_bus_call_method(bus,
720 "org.freedesktop.machine1",
721 "/org/freedesktop/machine1",
722 "org.freedesktop.machine1.Manager",
723 "MapToMachineGroup",
724 &error,
725 &reply,
726 "u",
727 (uint32_t) gid);
728 if (r < 0) {
729 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
730 return NSS_STATUS_NOTFOUND;
731
732 goto fail;
733 }
734
735 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
736 if (r < 0)
737 goto fail;
738
739 if (mapped == gid)
740 return NSS_STATUS_NOTFOUND;
741
742 if (buflen < sizeof(char*) + 1) {
743 *errnop = ERANGE;
744 return NSS_STATUS_TRYAGAIN;
745 }
746
747 memzero(buffer, sizeof(char*));
748 if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
749 *errnop = ERANGE;
750 return NSS_STATUS_TRYAGAIN;
751 }
752
753 gr->gr_name = buffer + sizeof(char*);
754 gr->gr_gid = gid;
755 gr->gr_passwd = (char*) "*"; /* locked */
756 gr->gr_mem = (char**) buffer;
757
758 return NSS_STATUS_SUCCESS;
759
760 fail:
761 *errnop = -r;
762 return NSS_STATUS_UNAVAIL;
763 }