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