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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <uuid/uuid.h> 29 #include <ctype.h> 30 #include <synch.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <assert.h> 36 37 #include <libmlrpc.h> 38 39 40 /* 41 * Global list of allocated handles. Handles are used in various 42 * server-side RPC functions: typically, issued when a service is 43 * opened and obsoleted when it is closed. Clients should treat 44 * handles as opaque data. 45 */ 46 static ndr_handle_t *ndr_handle_list; 47 static mutex_t ndr_handle_lock; 48 49 /* 50 * Table of registered services. 51 */ 52 #define NDR_MAX_SERVICES 32 53 static ndr_service_t *ndr_services[NDR_MAX_SERVICES]; 54 55 /* 56 * Register a service. 57 * 58 * Returns: 59 * 0 Success 60 * -1 Duplicate service 61 * -2 Duplicate name 62 * -3 Table overflow 63 */ 64 int 65 ndr_svc_register(ndr_service_t *svc) 66 { 67 ndr_service_t *p; 68 int free_slot = -1; 69 int i; 70 71 for (i = 0; i < NDR_MAX_SERVICES; i++) { 72 if ((p = ndr_services[i]) == NULL) { 73 if (free_slot < 0) 74 free_slot = i; 75 continue; 76 } 77 78 if (p == svc) 79 return (-1); 80 81 if (strcasecmp(p->name, svc->name) == 0) 82 return (-2); 83 } 84 85 if (free_slot < 0) 86 return (-3); 87 88 ndr_services[free_slot] = svc; 89 return (0); 90 } 91 92 void 93 ndr_svc_unregister(ndr_service_t *svc) 94 { 95 int i; 96 97 for (i = 0; i < NDR_MAX_SERVICES; i++) { 98 if (ndr_services[i] == svc) 99 ndr_services[i] = NULL; 100 } 101 } 102 103 ndr_stub_table_t * 104 ndr_svc_find_stub(ndr_service_t *svc, int opnum) 105 { 106 ndr_stub_table_t *ste; 107 108 for (ste = svc->stub_table; ste->func; ste++) { 109 if (ste->opnum == opnum) 110 return (ste); 111 } 112 113 return (NULL); 114 } 115 116 ndr_service_t * 117 ndr_svc_lookup_name(const char *name) 118 { 119 ndr_service_t *svc; 120 int i; 121 122 for (i = 0; i < NDR_MAX_SERVICES; i++) { 123 if ((svc = ndr_services[i]) == NULL) 124 continue; 125 126 if (strcasecmp(name, svc->name) != 0) 127 continue; 128 129 ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 130 return (svc); 131 } 132 133 return (NULL); 134 } 135 136 ndr_service_t * 137 ndr_svc_lookup_uuid(ndr_uuid_t *as_uuid, int as_vers, 138 ndr_uuid_t *ts_uuid, int ts_vers) 139 { 140 ndr_service_t *svc; 141 char abstract_syntax[UUID_PRINTABLE_STRING_LENGTH]; 142 char transfer_syntax[UUID_PRINTABLE_STRING_LENGTH]; 143 int i; 144 145 if (as_uuid) 146 ndr_uuid_unparse(as_uuid, abstract_syntax); 147 148 if (ts_uuid) 149 ndr_uuid_unparse(ts_uuid, transfer_syntax); 150 151 for (i = 0; i < NDR_MAX_SERVICES; i++) { 152 if ((svc = ndr_services[i]) == NULL) 153 continue; 154 155 if (as_uuid) { 156 if (svc->abstract_syntax_uuid == 0) 157 continue; 158 159 if (svc->abstract_syntax_version != as_vers) 160 continue; 161 162 if (strcasecmp(abstract_syntax, 163 svc->abstract_syntax_uuid)) 164 continue; 165 } 166 167 if (ts_uuid) { 168 if (svc->transfer_syntax_uuid == 0) 169 continue; 170 171 if (svc->transfer_syntax_version != ts_vers) 172 continue; 173 174 if (strcasecmp(transfer_syntax, 175 svc->transfer_syntax_uuid)) 176 continue; 177 } 178 179 ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 180 return (svc); 181 } 182 183 ndo_printf(0, 0, "ndr_svc_lookup_uuid: unknown service"); 184 ndo_printf(0, 0, "abstract=%s v%d, transfer=%s v%d", 185 abstract_syntax, as_vers, transfer_syntax, ts_vers); 186 return (NULL); 187 } 188 189 /* 190 * Allocate a handle for use with the server-side RPC functions. 191 * 192 * An arbitrary caller context can be associated with the handle 193 * via data; it will not be dereferenced by the handle API. 194 */ 195 ndr_hdid_t * 196 ndr_hdalloc(const ndr_xa_t *xa, const void *data) 197 { 198 static ndr_hdid_t id; 199 ndr_handle_t *hd; 200 uuid_t uu; 201 202 if ((hd = malloc(sizeof (ndr_handle_t))) == NULL) 203 return (NULL); 204 205 if (id.data2 == 0) { 206 uuid_generate_random(uu); 207 bcopy(uu, &id.data2, sizeof (uuid_t)); 208 id.data1 = 0; 209 id.data2 = 0; 210 } 211 212 ++id.data2; 213 214 bcopy(&id, &hd->nh_id, sizeof (ndr_hdid_t)); 215 hd->nh_pipe = xa->pipe; 216 hd->nh_svc = xa->binding->service; 217 hd->nh_data = (void *)data; 218 hd->nh_data_free = NULL; 219 220 (void) mutex_lock(&ndr_handle_lock); 221 hd->nh_next = ndr_handle_list; 222 ndr_handle_list = hd; 223 (void) mutex_unlock(&ndr_handle_lock); 224 225 return (&hd->nh_id); 226 } 227 228 /* 229 * Remove a handle from the global list and free it. 230 */ 231 void 232 ndr_hdfree(const ndr_xa_t *xa, const ndr_hdid_t *id) 233 { 234 ndr_service_t *svc = xa->binding->service; 235 ndr_handle_t *hd; 236 ndr_handle_t **pphd; 237 238 assert(id); 239 240 (void) mutex_lock(&ndr_handle_lock); 241 pphd = &ndr_handle_list; 242 243 while (*pphd) { 244 hd = *pphd; 245 246 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 247 if (hd->nh_svc == svc) { 248 *pphd = hd->nh_next; 249 free(hd); 250 } 251 break; 252 } 253 254 pphd = &(*pphd)->nh_next; 255 } 256 257 (void) mutex_unlock(&ndr_handle_lock); 258 } 259 260 /* 261 * Lookup a handle by id. If the handle is in the list and it matches 262 * the specified service, a pointer to it is returned. Otherwise a null 263 * pointer is returned. 264 */ 265 ndr_handle_t * 266 ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id) 267 { 268 ndr_service_t *svc = xa->binding->service; 269 ndr_handle_t *hd; 270 271 assert(id); 272 (void) mutex_lock(&ndr_handle_lock); 273 hd = ndr_handle_list; 274 275 while (hd) { 276 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 277 if (hd->nh_svc != svc) 278 break; 279 (void) mutex_unlock(&ndr_handle_lock); 280 return (hd); 281 } 282 283 hd = hd->nh_next; 284 } 285 286 (void) mutex_unlock(&ndr_handle_lock); 287 return (NULL); 288 } 289 290 /* 291 * Called when a pipe is closed to release any associated handles. 292 */ 293 void 294 ndr_hdclose(ndr_pipe_t *pipe) 295 { 296 ndr_handle_t *hd; 297 ndr_handle_t **pphd; 298 299 (void) mutex_lock(&ndr_handle_lock); 300 pphd = &ndr_handle_list; 301 302 while (*pphd) { 303 hd = *pphd; 304 305 if (hd->nh_pipe == pipe) { 306 *pphd = hd->nh_next; 307 308 if (hd->nh_data_free) 309 (*hd->nh_data_free)(hd->nh_data); 310 311 free(hd); 312 continue; 313 } 314 315 pphd = &(*pphd)->nh_next; 316 } 317 318 (void) mutex_unlock(&ndr_handle_lock); 319 } 320 321 /* 322 * Convert a UUID to a string. 323 */ 324 void 325 ndr_uuid_unparse(ndr_uuid_t *uuid, char *out) 326 { 327 (void) sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 328 uuid->data1, uuid->data2, uuid->data3, 329 uuid->data4[0], uuid->data4[1], 330 uuid->data4[2], uuid->data4[3], 331 uuid->data4[4], uuid->data4[5], 332 uuid->data4[6], uuid->data4[7]); 333 } 334 335 /* 336 * Convert a string to a UUID. 337 */ 338 int 339 ndr_uuid_parse(char *in, ndr_uuid_t *uuid) 340 { 341 char *p = in; 342 char *q; 343 char buf[4]; 344 int i; 345 346 if (strlen(in) != UUID_PRINTABLE_STRING_LENGTH - 1) 347 return (-1); 348 349 uuid->data1 = strtoul(p, &p, 16); 350 if (*p != '-') 351 return (-1); 352 p++; 353 354 uuid->data2 = strtol(p, &p, 16); 355 if (*p != '-') 356 return (-1); 357 p++; 358 359 uuid->data3 = strtol(p, &p, 16); 360 if (*p != '-') 361 return (-1); 362 p++; 363 364 for (i = 0; i < 8; i++) { 365 if (*p == '-') 366 p++; 367 368 if (p[0] == 0 || p[1] == 0) 369 return (-1); 370 371 buf[0] = *p++; 372 buf[1] = *p++; 373 buf[2] = 0; 374 uuid->data4[i] = strtol(buf, &q, 16); 375 if (*q != 0) 376 return (-1); 377 } 378 379 if (*p != 0) 380 return (-1); 381 382 return (0); 383 } 384 385 void 386 ndr_svc_binding_pool_init(ndr_binding_t **headpp, ndr_binding_t pool[], 387 int n_pool) 388 { 389 ndr_binding_t *head = NULL; 390 int ix; 391 392 for (ix = n_pool - 1; ix >= 0; ix--) { 393 pool[ix].next = head; 394 pool[ix].service = NULL; 395 pool[ix].p_cont_id = 0xffff; 396 pool[ix].instance_specific = 0; 397 head = &pool[ix]; 398 } 399 400 *headpp = head; 401 } 402 403 ndr_binding_t * 404 ndr_svc_find_binding(ndr_xa_t *mxa, ndr_p_context_id_t p_cont_id) 405 { 406 ndr_binding_t *mbind; 407 408 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 409 if (mbind->service != NULL && 410 mbind->which_side == NDR_BIND_SIDE_SERVER && 411 mbind->p_cont_id == p_cont_id) 412 break; 413 } 414 415 return (mbind); 416 } 417 418 ndr_binding_t * 419 ndr_svc_new_binding(ndr_xa_t *mxa) 420 { 421 ndr_binding_t *mbind; 422 423 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 424 if (mbind->service == NULL) 425 break; 426 } 427 428 return (mbind); 429 } 430 431 /* 432 * Move bytes between a buffer and a uio structure. 433 * The transfer direction is controlled by rw: 434 * UIO_READ: transfer from buf to uio 435 * UIO_WRITE: transfer from uio to buf 436 * 437 * Returns the number of bytes moved. 438 */ 439 ssize_t 440 ndr_uiomove(caddr_t buf, size_t buflen, enum uio_rw rw, struct uio *uio) 441 { 442 struct iovec *iov; 443 int reading = (rw == UIO_READ); 444 size_t nbytes; 445 size_t nxfer = 0; 446 447 assert(rw == UIO_READ || rw == UIO_WRITE); 448 449 while (buflen && uio->uio_resid && uio->uio_iovcnt) { 450 iov = uio->uio_iov; 451 if ((nbytes = iov->iov_len) == 0) { 452 uio->uio_iov++; 453 uio->uio_iovcnt--; 454 continue; 455 } 456 457 if (nbytes > buflen) 458 nbytes = buflen; 459 460 if (reading) 461 bcopy(buf, iov->iov_base, nbytes); 462 else 463 bcopy(iov->iov_base, buf, nbytes); 464 465 iov->iov_base += nbytes; 466 iov->iov_len -= nbytes; 467 uio->uio_resid -= nbytes; 468 uio->uio_offset += nbytes; 469 buf += nbytes; 470 buflen -= nbytes; 471 nxfer += nbytes; 472 } 473 474 return (nxfer); 475 }