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 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 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 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 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 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 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 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