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 */ 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 nss_status_t 109 _nscd_doorcall(int callnum) 110 { 111 size_t buflen; 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 /* allocate door buffer from the stack */ 123 NSCD_ALLOC_DOORBUF(callnum, 0, dptr, buflen); 124 ndata = buflen; 125 adata = buflen; 126 127 ret = _nsc_trydoorcall(&dptr, &ndata, &adata); 128 129 if (ret != NSS_SUCCESS) { 130 phdr = (nss_pheader_t *)dptr; 131 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 132 (me, "door call (%d) failed (status = %d, error = %s)\n", 133 callnum, ret, strerror(NSCD_GET_ERRNO(phdr))); 134 } 135 136 return (ret); 137 } 138 139 140 nss_status_t 141 _nscd_doorcall_data(int callnum, void *indata, int indlen, 142 void *outdata, int outdlen, nss_pheader_t *phdr) 143 { 144 void *uptr; 145 size_t buflen; 146 void *dptr; 147 void *datap; 148 size_t ndata; 149 size_t adata; 150 nss_pheader_t *phdr_d; 151 int ret; 152 char *me = "_nscd_doorcall_data"; 153 154 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 155 (me, "processing door call %d ...\n", callnum); 156 157 /* allocate door buffer from the stack */ 158 NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); 159 dptr = uptr; 160 ndata = buflen; 161 adata = buflen; 162 datap = NSCD_N2N_DOOR_DATA(void, dptr); 163 if (indata != NULL) 164 (void) memmove(datap, indata, indlen); 165 166 ret = _nsc_trydoorcall(&dptr, &ndata, &adata); 167 168 phdr_d = (nss_pheader_t *)dptr; 169 if (ret != NSS_SUCCESS) { 170 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 171 (me, "door call (%d) failed (status = %d, error = %s)\n", 172 callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d))); 173 } else { 174 if (phdr != NULL) { 175 NSCD_COPY_STATUS(phdr, phdr_d); 176 } 177 ret = copy_output(outdata, outdlen, phdr_d, phdr); 178 } 179 180 /* if new buffer allocated for this door call, free it */ 181 if (dptr != uptr) 182 (void) munmap(dptr, ndata); 183 184 return (ret); 185 } 186 187 nss_status_t 188 _nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen, 189 void *outdata, int outdlen, nss_pheader_t *phdr) 190 { 191 void *uptr; 192 void *dptr; 193 void *datap; 194 size_t ndata; 195 size_t adata; 196 size_t buflen; 197 door_arg_t param; 198 int ret, errnum; 199 nss_pheader_t *phdr_d; 200 char *me = "_nscd_doorcall_fd"; 201 202 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 203 (me, "processing door call %d (fd = %d)...\n", callnum, fd); 204 205 /* allocate door buffer from the stack */ 206 NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); 207 dptr = uptr; 208 ndata = buflen; 209 adata = buflen; 210 datap = NSCD_N2N_DOOR_DATA(void, dptr); 211 if (indata != NULL) 212 (void) memmove(datap, indata, indlen); 213 214 param.rbuf = (char *)dptr; 215 param.rsize = ndata; 216 param.data_ptr = (char *)dptr; 217 param.data_size = adata; 218 param.desc_ptr = NULL; 219 param.desc_num = 0; 220 ret = door_call(fd, ¶m); 221 if (ret < 0) { 222 errnum = errno; 223 /* 224 * door call did not get through, return errno 225 * if requested 226 */ 227 if (phdr != NULL) { 228 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); 229 } 230 231 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 232 (me, "door call (%d to %d) did not get through (%s)\n", 233 callnum, fd, strerror(errnum)); 234 235 return (NSS_ERROR); 236 } 237 ndata = param.rsize; 238 dptr = (void *)param.data_ptr; 239 240 /* 241 * door call got through, check if operation failed. 242 * if so, return error info if requested 243 */ 244 phdr_d = (nss_pheader_t *)dptr; 245 ret = NSCD_GET_STATUS(phdr_d); 246 if (ret != NSS_SUCCESS) { 247 if (phdr != NULL) { 248 NSCD_COPY_STATUS(phdr, phdr_d); 249 } 250 251 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 252 (me, "door call (%d to %d) failed: p_status = %d, " 253 "p_errno = %s, nscd status = %d\n", callnum, fd, 254 ret, strerror(NSCD_GET_ERRNO(phdr_d)), 255 NSCD_GET_NSCD_STATUS(phdr_d)); 256 } else 257 ret = copy_output(outdata, outdlen, phdr_d, phdr); 258 259 /* if new buffer allocated for this door call, free it */ 260 if (dptr != uptr) 261 (void) munmap(dptr, param.rsize); 262 263 264 return (ret); 265 } 266 267 static void 268 send_doorfd(void **dptr, size_t *ndata, size_t *adata, 269 door_desc_t *pdesc) 270 { 271 nss_pheader_t *phdr = (nss_pheader_t *)*dptr; 272 door_arg_t param; 273 int ret; 274 int doorfd; 275 int errnum; 276 char *me = "send_doorfd"; 277 278 initdoor(*dptr, &doorfd); 279 if (NSCD_STATUS_IS_NOT_OK(phdr)) 280 return; 281 282 param.rbuf = (char *)*dptr; 283 param.rsize = *ndata; 284 param.data_ptr = (char *)*dptr; 285 param.data_size = *adata; 286 param.desc_ptr = pdesc; 287 param.desc_num = 1; 288 ret = door_call(doorfd, ¶m); 289 if (ret < 0) { 290 errnum = errno; 291 292 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 293 (me, "door call (to fd %d) failed (%s)\n", 294 doorfd, strerror(errnum)); 295 (void) close(doorfd); 296 NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); 297 } 298 *adata = param.data_size; 299 *ndata = param.rsize; 300 *dptr = (void *)param.data_ptr; 301 302 if (*adata == 0 || *dptr == NULL) { 303 (void) close(doorfd); 304 305 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 306 (me, "no data\n"); 307 308 NSCD_RETURN_STATUS(phdr, NSS_ERROR, ENOTCONN); 309 } 310 311 (void) close(doorfd); 312 } 313 314 nss_status_t 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