1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <pwd.h>
24: #include <stdint.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29: #include <sys/mman.h>
30: #include <sys/socket.h>
31: #include <sys/uio.h>
32: #include <sys/un.h>
33: #include <not-cancel.h>
34: #include <stdio-common/_itoa.h>
35:
36: #include "nscd-client.h"
37: #include "nscd_proto.h"
38:
39: int __nss_not_use_nscd_passwd;
40:
41: static int nscd_getpw_r (const char *key, size_t keylen, request_type type,
42: struct passwd *resultbuf, char *buffer,
43: size_t buflen, struct passwd **result)
44: internal_function;
45:
46: int
47: __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
48: size_t buflen, struct passwd **result)
49: {
50: if (name == NULL)
51: return -1;
52:
53: return nscd_getpw_r (name, strlen (name) + 1, GETPWBYNAME, resultbuf,
54: buffer, buflen, result);
55: }
56:
57: int
58: __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
59: size_t buflen, struct passwd **result)
60: {
61: char buf[3 * sizeof (uid_t)];
62: buf[sizeof (buf) - 1] = '\0';
63: char *cp = _itoa_word (uid, buf + sizeof (buf) - 1, 10, 0);
64:
65: return nscd_getpw_r (cp, buf + sizeof (buf) - cp, GETPWBYUID, resultbuf,
66: buffer, buflen, result);
67: }
68:
69:
70: libc_locked_map_ptr (static, map_handle);
71:
72:
73:
74: libc_freeres_fn (pw_map_free)
75: {
76: if (map_handle.mapped != NO_MAPPING)
77: {
78: void *p = map_handle.mapped;
79: map_handle.mapped = NO_MAPPING;
80: free (p);
81: }
82: }
83:
84:
85: static int
86: internal_function
87: nscd_getpw_r (const char *key, size_t keylen, request_type type,
88: struct passwd *resultbuf, char *buffer, size_t buflen,
89: struct passwd **result)
90: {
91: int gc_cycle;
92: int nretries = 0;
93:
94:
95:
96: struct mapped_database *mapped;
97: mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
98:
99: retry:;
100: const char *pw_name = NULL;
101: int retval = -1;
102: const char *recend = (const char *) ~UINTMAX_C (0);
103: pw_response_header pw_resp;
104:
105: if (mapped != NO_MAPPING)
106: {
107: struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
108: if (found != NULL)
109: {
110: pw_name = (const char *) (&found->data[0].pwdata + 1);
111: pw_resp = found->data[0].pwdata;
112: recend = (const char *) found->data + found->recsize;
113:
114:
115: if (mapped->head->gc_cycle != gc_cycle)
116: {
117: retval = -2;
118: goto out;
119: }
120: }
121: }
122:
123: int sock = -1;
124: if (pw_name == NULL)
125: {
126: sock = __nscd_open_socket (key, keylen, type, &pw_resp,
127: sizeof (pw_resp));
128: if (sock == -1)
129: {
130: __nss_not_use_nscd_passwd = 1;
131: goto out;
132: }
133: }
134:
135:
136: *result = NULL;
137:
138: if (__builtin_expect (pw_resp.found == -1, 0))
139: {
140:
141: __nss_not_use_nscd_passwd = 1;
142: goto out_close;
143: }
144:
145: if (pw_resp.found == 1)
146: {
147:
148: resultbuf->pw_uid = pw_resp.pw_uid;
149: resultbuf->pw_gid = pw_resp.pw_gid;
150:
151: char *p = buffer;
152:
153: resultbuf->pw_name = p;
154: p += pw_resp.pw_name_len;
155:
156: resultbuf->pw_passwd = p;
157: p += pw_resp.pw_passwd_len;
158:
159: resultbuf->pw_gecos = p;
160: p += pw_resp.pw_gecos_len;
161:
162: resultbuf->pw_dir = p;
163: p += pw_resp.pw_dir_len;
164:
165: resultbuf->pw_shell = p;
166: p += pw_resp.pw_shell_len;
167:
168: ssize_t total = p - buffer;
169: if (__builtin_expect (pw_name + total > recend, 0))
170: goto out_close;
171: if (__builtin_expect (buflen < total, 0))
172: {
173: __set_errno (ERANGE);
174: retval = ERANGE;
175: goto out_close;
176: }
177:
178: retval = 0;
179: if (pw_name == NULL)
180: {
181: ssize_t nbytes = __readall (sock, buffer, total);
182:
183: if (__builtin_expect (nbytes != total, 0))
184: {
185:
186: __set_errno (ENOENT);
187: retval = ENOENT;
188: }
189: else
190: *result = resultbuf;
191: }
192: else
193: {
194:
195: memcpy (resultbuf->pw_name, pw_name, total);
196:
197:
198: if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
199: || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
200: || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
201: || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
202: || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
203: {
204:
205: retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
206: goto out_close;
207: }
208:
209: *result = resultbuf;
210: }
211: }
212: else
213: {
214:
215: __set_errno (0);
216:
217: retval = 0;
218: }
219:
220: out_close:
221: if (sock != -1)
222: close_not_cancel_no_status (sock);
223: out:
224: if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
225: {
226:
227:
228:
229: if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
230: {
231:
232: if (atomic_decrement_val (&mapped->counter) == 0)
233: __nscd_unmap (mapped);
234: mapped = NO_MAPPING;
235: }
236:
237: if (retval != -1)
238: goto retry;
239: }
240:
241: return retval;
242: }