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