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