1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 */
27
28 #include <sys/param.h>
29 #include <string.h>
30 #include <door.h>
31 #include <sys/mman.h>
32 #include "nscd_door.h"
33 #include "nscd_log.h"
34 #include <getxby_door.h>
35 #include <sys/types.h>
36 #include <errno.h>
37 #include <fcntl.h>
38
39 static void
initdoor(void * buf,int * doorfd)40 initdoor(void *buf, int *doorfd)
41 {
42 nss_pheader_t *phdr = (nss_pheader_t *)buf;
43 door_info_t doori;
44 char *me = "initdoor";
45
46 *doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0);
47
48 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
49 (me, "door is %s (fd is %d)\n", NAME_SERVICE_DOOR,
50 *doorfd);
51
52 if (*doorfd == -1) {
53 NSCD_SET_STATUS(phdr, NSS_ERROR, errno);
54 return;
55 }
56
57 if (door_info(*doorfd, &doori) < 0 ||
58 (doori.di_attributes & DOOR_REVOKED) ||
59 doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
60
61 /*
62 * we should close doorfd because we just opened it
63 */
64 (void) close(*doorfd);
65
66 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
67 (me, "door %d not valid\n", *doorfd);
68
69 NSCD_SET_STATUS(phdr, NSS_ERROR, ECONNREFUSED);
70 return;
71 }
72
73 NSCD_SET_STATUS_SUCCESS(phdr);
74 }
75
76 /* general door call functions used by nscd */
77
78 static nss_status_t
copy_output(void * outdata,int outdlen,nss_pheader_t * phdr,nss_pheader_t * outphdr)79 copy_output(void *outdata, int outdlen,
80 nss_pheader_t *phdr, nss_pheader_t *outphdr)
81 {
82 void *dp;
83 nss_status_t ret = NSS_SUCCESS;
84 char *me = "copy_output";
85
86 if (outdata != NULL && phdr->data_off > 0 && phdr->data_len > 0) {
87 if (phdr->data_len <= outdlen) {
88 dp = (char *)phdr + phdr->data_off;
89 (void) memmove(outdata, dp, phdr->data_len);
90 } else {
91
92 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
93 (me, "output buffer not large enough "
94 " should be > %d but is %d\n",
95 phdr->data_len, outdlen);
96
97 if (outphdr != NULL) {
98 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV,
99 0, NSCD_INVALID_ARGUMENT);
100 NSCD_COPY_STATUS(outphdr, phdr);
101 }
102 ret = NSS_NSCD_PRIV;
103 }
104 }
105
106 return (ret);
107 }
108
109 nss_status_t
_nscd_doorcall(int callnum)110 _nscd_doorcall(int callnum)
111 {
112 size_t buflen;
113 nss_pheader_t *phdr;
114 void *dptr;
115 size_t ndata;
116 size_t adata;
117 int ret;
118 char *me = "_nscd_doorcall";
119
120 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
121 (me, "processing door call %d ...\n", callnum);
122
123 /* allocate door buffer from the stack */
124 NSCD_ALLOC_DOORBUF(callnum, 0, dptr, buflen);
125 ndata = buflen;
126 adata = buflen;
127
128 ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
129
130 if (ret != NSS_SUCCESS) {
131 phdr = (nss_pheader_t *)dptr;
132 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
133 (me, "door call (%d) failed (status = %d, error = %s)\n",
134 callnum, ret, strerror(NSCD_GET_ERRNO(phdr)));
135 }
136
137 return (ret);
138 }
139
140
141 nss_status_t
_nscd_doorcall_data(int callnum,void * indata,int indlen,void * outdata,int outdlen,nss_pheader_t * phdr)142 _nscd_doorcall_data(int callnum, void *indata, int indlen,
143 void *outdata, int outdlen, nss_pheader_t *phdr)
144 {
145 void *uptr;
146 size_t buflen;
147 void *dptr;
148 void *datap;
149 size_t ndata;
150 size_t adata;
151 nss_pheader_t *phdr_d;
152 int ret;
153 char *me = "_nscd_doorcall_data";
154
155 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
156 (me, "processing door call %d ...\n", callnum);
157
158 /* allocate door buffer from the stack */
159 NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
160 dptr = uptr;
161 ndata = buflen;
162 adata = buflen;
163 datap = NSCD_N2N_DOOR_DATA(void, dptr);
164 if (indata != NULL)
165 (void) memmove(datap, indata, indlen);
166
167 ret = _nsc_trydoorcall(&dptr, &ndata, &adata);
168
169 phdr_d = (nss_pheader_t *)dptr;
170 if (ret != NSS_SUCCESS) {
171 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
172 (me, "door call (%d) failed (status = %d, error = %s)\n",
173 callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d)));
174 } else {
175 if (phdr != NULL) {
176 NSCD_COPY_STATUS(phdr, phdr_d);
177 }
178 ret = copy_output(outdata, outdlen, phdr_d, phdr);
179 }
180
181 /* if new buffer allocated for this door call, free it */
182 if (dptr != uptr)
183 (void) munmap(dptr, ndata);
184
185 return (ret);
186 }
187
188 nss_status_t
_nscd_doorcall_fd(int fd,int callnum,void * indata,int indlen,void * outdata,int outdlen,nss_pheader_t * phdr)189 _nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen,
190 void *outdata, int outdlen, nss_pheader_t *phdr)
191 {
192 void *uptr;
193 void *dptr;
194 void *datap;
195 size_t ndata;
196 size_t adata;
197 size_t buflen;
198 door_arg_t param;
199 int ret, errnum;
200 nss_pheader_t *phdr_d;
201 char *me = "_nscd_doorcall_fd";
202
203 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
204 (me, "processing door call %d (fd = %d)...\n", callnum, fd);
205
206 /* allocate door buffer from the stack */
207 NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
208 dptr = uptr;
209 ndata = buflen;
210 adata = buflen;
211 datap = NSCD_N2N_DOOR_DATA(void, dptr);
212 if (indata != NULL)
213 (void) memmove(datap, indata, indlen);
214
215 param.rbuf = (char *)dptr;
216 param.rsize = ndata;
217 param.data_ptr = (char *)dptr;
218 param.data_size = adata;
219 param.desc_ptr = NULL;
220 param.desc_num = 0;
221 ret = door_call(fd, ¶m);
222 if (ret < 0) {
223 errnum = errno;
224 /*
225 * door call did not get through, return errno
226 * if requested
227 */
228 if (phdr != NULL) {
229 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
230 }
231
232 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
233 (me, "door call (%d to %d) did not get through (%s)\n",
234 callnum, fd, strerror(errnum));
235
236 return (NSS_ERROR);
237 }
238 ndata = param.rsize;
239 dptr = (void *)param.data_ptr;
240
241 /*
242 * door call got through, check if operation failed.
243 * if so, return error info if requested
244 */
245 phdr_d = (nss_pheader_t *)dptr;
246 ret = NSCD_GET_STATUS(phdr_d);
247 if (ret != NSS_SUCCESS) {
248 if (phdr != NULL) {
249 NSCD_COPY_STATUS(phdr, phdr_d);
250 }
251
252 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
253 (me, "door call (%d to %d) failed: p_status = %d, "
254 "p_errno = %s, nscd status = %d\n", callnum, fd,
255 ret, strerror(NSCD_GET_ERRNO(phdr_d)),
256 NSCD_GET_NSCD_STATUS(phdr_d));
257 } else
258 ret = copy_output(outdata, outdlen, phdr_d, phdr);
259
260 /* if new buffer allocated for this door call, free it */
261 if (dptr != uptr)
262 (void) munmap(dptr, param.rsize);
263
264
265 return (ret);
266 }
267
268 static void
send_doorfd(void ** dptr,size_t * ndata,size_t * adata,door_desc_t * pdesc)269 send_doorfd(void **dptr, size_t *ndata, size_t *adata,
270 door_desc_t *pdesc)
271 {
272 nss_pheader_t *phdr = (nss_pheader_t *)*dptr;
273 door_arg_t param;
274 int ret;
275 int doorfd;
276 int errnum;
277 char *me = "send_doorfd";
278
279 initdoor(*dptr, &doorfd);
280 if (NSCD_STATUS_IS_NOT_OK(phdr))
281 return;
282
283 param.rbuf = (char *)*dptr;
284 param.rsize = *ndata;
285 param.data_ptr = (char *)*dptr;
286 param.data_size = *adata;
287 param.desc_ptr = pdesc;
288 param.desc_num = 1;
289 ret = door_call(doorfd, ¶m);
290 if (ret < 0) {
291 errnum = errno;
292
293 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
294 (me, "door call (to fd %d) failed (%s)\n",
295 doorfd, strerror(errnum));
296 (void) close(doorfd);
297 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
298 return;
299 }
300 *adata = param.data_size;
301 *ndata = param.rsize;
302 *dptr = (void *)param.data_ptr;
303
304 if (*adata == 0 || *dptr == NULL) {
305 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
306 (me, "no data\n");
307
308 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTCONN);
309 }
310
311 (void) close(doorfd);
312 }
313
314 nss_status_t
_nscd_doorcall_sendfd(int fd,int callnum,void * indata,int indlen,nss_pheader_t * phdr)315 _nscd_doorcall_sendfd(int fd, int callnum, void *indata, int indlen,
316 nss_pheader_t *phdr)
317 {
318 void *uptr;
319 void *dptr;
320 void *datap;
321 size_t ndata;
322 size_t adata;
323 size_t buflen;
324 nss_pheader_t *phdr_d;
325 door_desc_t desc;
326 char *me = "_nscd_doorcall_sendfd";
327
328 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
329 (me, "processing door call %d (fd = %d)...\n", callnum, fd);
330
331 /* allocate door buffer from the stack */
332 NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen);
333 dptr = uptr;
334 ndata = buflen;
335 adata = buflen;
336 datap = NSCD_N2N_DOOR_DATA(void, dptr);
337 if (indata != NULL)
338 (void) memmove(datap, indata, indlen);
339 desc.d_attributes = DOOR_DESCRIPTOR;
340 desc.d_data.d_desc.d_descriptor = fd;
341
342 send_doorfd(&dptr, &ndata, &adata, &desc);
343
344 phdr_d = (nss_pheader_t *)dptr;
345 if (NSCD_STATUS_IS_NOT_OK(phdr_d)) {
346 if (phdr != NULL)
347 *phdr = *phdr_d;
348
349 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
350 (me, "door call (%d) failed (status = %d, error = %s)\n",
351 callnum, NSCD_GET_STATUS(phdr_d),
352 strerror(NSCD_GET_ERRNO(phdr_d)));
353 }
354
355 return (NSCD_GET_STATUS(phdr_d));
356 }
357