1 | /* |
---|
2 | * nss_afspag.c |
---|
3 | * nsswitch module to assign group names to AFS PAG groups. |
---|
4 | * |
---|
5 | * Copyright © 2007 Anders Kaseorg <andersk@mit.edu> |
---|
6 | * |
---|
7 | * Permission is hereby granted, free of charge, to any person |
---|
8 | * obtaining a copy of this software and associated documentation |
---|
9 | * files (the "Software"), to deal in the Software without |
---|
10 | * restriction, including without limitation the rights to use, copy, |
---|
11 | * modify, merge, publish, distribute, sublicense, and/or sell copies |
---|
12 | * of the Software, and to permit persons to whom the Software is |
---|
13 | * furnished to do so, subject to the following conditions: |
---|
14 | * |
---|
15 | * The above copyright notice and this permission notice shall be |
---|
16 | * included in all copies or substantial portions of the Software. |
---|
17 | * |
---|
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
---|
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
---|
22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
---|
23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
---|
24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
---|
25 | * SOFTWARE. |
---|
26 | */ |
---|
27 | |
---|
28 | #include <sys/types.h> |
---|
29 | #include <unistd.h> |
---|
30 | #include <stdlib.h> |
---|
31 | #include <stdint.h> |
---|
32 | #include <grp.h> |
---|
33 | #include <nss.h> |
---|
34 | #include <string.h> |
---|
35 | #include <stdio.h> |
---|
36 | #include <errno.h> |
---|
37 | |
---|
38 | static enum nss_status |
---|
39 | getfakegr_r(gid_t gid, struct group *grp, char *buffer, size_t buflen, int *errnop) |
---|
40 | { |
---|
41 | int n; |
---|
42 | |
---|
43 | n = snprintf(buffer, buflen, "afspag-%d", gid); |
---|
44 | if (n < 0 || n >= buflen) |
---|
45 | goto erange; |
---|
46 | grp->gr_name = buffer; |
---|
47 | buffer += n + 1; |
---|
48 | buflen -= n + 1; |
---|
49 | |
---|
50 | n = snprintf(buffer, buflen, "x"); |
---|
51 | if (n < 0 || n >= buflen) |
---|
52 | goto erange; |
---|
53 | grp->gr_passwd = buffer; |
---|
54 | buffer += n + 1; |
---|
55 | buflen -= n + 1; |
---|
56 | |
---|
57 | grp->gr_gid = gid; |
---|
58 | |
---|
59 | if (buflen < sizeof((char *)0)) |
---|
60 | goto erange; |
---|
61 | grp->gr_mem = (char **)buffer; |
---|
62 | *grp->gr_mem = NULL; |
---|
63 | buffer += sizeof((char *)0); |
---|
64 | buflen -= sizeof((char *)0); |
---|
65 | |
---|
66 | return NSS_STATUS_SUCCESS; |
---|
67 | erange: |
---|
68 | *errnop = ERANGE; |
---|
69 | return NSS_STATUS_TRYAGAIN; |
---|
70 | } |
---|
71 | |
---|
72 | enum nss_status |
---|
73 | _nss_afspag_getgrgid_r(gid_t gid, struct group *grp, |
---|
74 | char *buffer, size_t buflen, int *errnop) |
---|
75 | { |
---|
76 | gid_t *gids = NULL, *pgid; |
---|
77 | int ngids = getgroups(0, gids); |
---|
78 | if (ngids == -1) { |
---|
79 | *errnop = EINVAL; |
---|
80 | return NSS_STATUS_TRYAGAIN; |
---|
81 | } |
---|
82 | gids = malloc(ngids * sizeof(gid_t)); |
---|
83 | if (gids == NULL) { |
---|
84 | *errnop = ENOMEM; |
---|
85 | return NSS_STATUS_TRYAGAIN; |
---|
86 | } |
---|
87 | ngids = getgroups(ngids, gids); |
---|
88 | if (ngids == -1) { |
---|
89 | free(gids); |
---|
90 | *errnop = EINVAL; |
---|
91 | return NSS_STATUS_TRYAGAIN; |
---|
92 | } |
---|
93 | |
---|
94 | /* See openafs/src/afs/afs_osi_pag.c. */ |
---|
95 | for (pgid = gids; pgid < gids + ngids; pgid++) |
---|
96 | if (*pgid == gid && ((gid >> 24) & 0xff) == 'A') { |
---|
97 | free(gids); |
---|
98 | return getfakegr_r(gid, grp, buffer, buflen, errnop); |
---|
99 | } |
---|
100 | |
---|
101 | if ((gid == gids[0] || gid == gids[1])) { |
---|
102 | uint32_t g0 = gids[0], g1 = gids[1]; |
---|
103 | free(gids); |
---|
104 | g0 -= 0x3f00; |
---|
105 | g1 -= 0x3f00; |
---|
106 | if (g0 < 0xc000 && g1 < 0xc000) { |
---|
107 | uint32_t l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff); |
---|
108 | uint32_t h = (g1 >> 14) + 3*(g0 >> 14); |
---|
109 | uint32_t ret = ((h << 28) | l); |
---|
110 | if (((ret >> 24) & 0xff) == 'A') |
---|
111 | return getfakegr_r(gid, grp, buffer, buflen, errnop); |
---|
112 | } |
---|
113 | } else { |
---|
114 | free(gids); |
---|
115 | } |
---|
116 | |
---|
117 | return NSS_STATUS_NOTFOUND; |
---|
118 | } |
---|
119 | |
---|
120 | enum nss_status |
---|
121 | _nss_afspag_getgrnam_r(const char *name, struct group *grp, |
---|
122 | char *buffer, size_t buflen, int *errnop) |
---|
123 | { |
---|
124 | unsigned int gid; |
---|
125 | int n; |
---|
126 | if (strncmp(name, "afspag-", 7) == 0 && |
---|
127 | sscanf(name + 7, "%u%n", &gid, &n) >= 1 && |
---|
128 | n == strlen(name + 7)) |
---|
129 | return _nss_afspag_getgrgid_r((gid_t)gid, grp, buffer, buflen, errnop); |
---|
130 | return NSS_STATUS_NOTFOUND; |
---|
131 | } |
---|