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