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