1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** rpcd.c 82** 83** FACILITY: 84** 85** RPC Daemon 86** 87** ABSTRACT: 88** 89** This daemon is a catch all for DCE RPC support functions. This server 90** exports the DCE 1.0 endpoint map (ept_) network interfaces and, optionally, 91** the NCS 1.5.1 llb_ network interfaces and . Additionally, this server 92** provides the RPC forwarding map function used by non-connection oriented 93** protocol services. 94** 95** 96*/ 97 98#include <commonp.h> 99#include <com.h> 100 101#include <dce/ep.h> 102EXTERNAL ept_v3_0_epv_t ept_v3_0_mgr_epv; 103 104#ifdef RPC_LLB 105# include <dce/llb.h> 106EXTERNAL llb__v4_0_epv_t llb_v4_0_mgr_epv; 107#endif 108 109#ifdef ENABLE_DCOM 110# include <objex.h> 111EXTERNAL IObjectExporter_v0_0_epv_t objex_mgr_epv; 112#endif 113 114#include <comfwd.h> 115 116#include <dsm.h> 117 118#include <rpcdp.h> 119#include <rpcddb.h> 120#include <rpcdepdb.h> 121 122#ifdef RPC_LLB 123#include <rpcdlbdb.h> 124#endif 125 126#include <dce/dce_error.h> 127 128#include <sys/ioctl.h> 129#include <sys/stat.h> 130#include <locale.h> 131#include <syslog.h> 132#include <ctype.h> 133 134#include <errno.h> 135 136/* FIXME: Hack to get prototypes we need on AIX */ 137#if defined(_AIX) && defined(_BSD) 138extern pid_t setpgrp(void); 139int ioctl(int d, int request, ...); 140#ifdef SETPGRP_ARGS 141# undef SETPGRP_ARGS 142#endif 143#define SETPGRP_ARGS 0 144#endif 145 146INTERNAL void usage 147 ( 148 void 149 ); 150 151#if 0 152INTERNAL boolean32 match_command 153 ( 154 char *key, 155 char *str, 156 long min_len 157 ); 158#endif 159 160INTERNAL void process_args 161 ( 162 int argc, 163 char *argv[] 164 ); 165 166INTERNAL void register_ifs 167 ( 168 error_status_t *status 169 ); 170 171INTERNAL void use_protseqs 172 ( 173 error_status_t *status 174 ); 175 176INTERNAL void init 177 ( 178 error_status_t *status 179 ); 180 181INTERNAL void fwd_map 182 ( 183 uuid_p_t object, 184 rpc_if_id_p_t interface, 185 rpc_syntax_id_p_t data_rep, 186 rpc_protocol_id_t rpc_protocol, 187 unsigned32 rpc_protocol_vers_major, 188 unsigned32 rpc_protocol_vers_minor, 189 rpc_addr_p_t addr, 190 uuid_p_t actuuid, 191 rpc_addr_p_t *fwd_addr, 192 rpc_fwd_action_t *fwd_action, 193 error_status_t *status 194 ); 195 196 197/* 198 * These implementation constants can be redefined in the system specific 199 * config files if necessary (e.g. common/ultrix_mips.h). 200 */ 201 202#ifdef DCELOCAL_PATH 203# define rpcd_c_database_name_prefix1 DCELOCAL_PATH 204# define rpcd_c_database_name_prefix2 "/var/rpc/" 205#else 206 207#ifndef rpcd_c_database_name_prefix1 208# define rpcd_c_database_name_prefix1 "/tmp/" 209#endif 210 211#ifndef rpcd_c_database_name_prefix2 212# define rpcd_c_database_name_prefix2 "" 213#endif 214 215#endif 216 217#ifndef rpcd_c_ep_database_name 218# define rpcd_c_ep_database_name "rpcdep.dat" 219#endif 220 221#ifndef rpcd_c_llb_database_name 222# define rpcd_c_llb_database_name "rpcdllb.dat" 223#endif 224 225#ifndef rpcd_c_logfile_name 226# define rpcd_c_logfile_name "rpcd.log" 227#endif 228 229/* 230 * Optional list of protocol sequences which rpcd will use. 231 * List is specified on the command line 232 */ 233#define MAX_PROTSEQ_ARGS 8 234INTERNAL unsigned_char_p_t protseq[MAX_PROTSEQ_ARGS]; 235INTERNAL unsigned32 num_protseq = 0; 236INTERNAL boolean32 use_all_protseqs = true; 237 238/* 239 * Debug flag controls 240 */ 241GLOBAL boolean32 dflag = false; 242#define DEBUG_LEVEL "0.1" 243 244INTERNAL boolean32 foreground = false; 245 246INTERNAL char rpcd_version_str[] = 247#ifdef ENABLE_DCOM 248 "rpcd/orpcd version freedce 1.1"; 249#else 250 "rpcd version freedce 1.1"; 251#endif 252 253GLOBAL idl_uuid_t nil_uuid; 254 255 256PRIVATE boolean32 check_st_bad( 257 const char *str, 258 const error_status_t *st) 259{ 260 if (STATUS_OK(st)) 261 return false; 262 263 show_st(str, st); 264 return true; 265} 266 267PRIVATE void show_st( 268 const char *str, 269 const error_status_t *st) 270{ 271 dce_error_string_t estr; 272 int tmp_st; 273 274 dce_error_inq_text(*st, estr, &tmp_st); 275 fprintf(stderr, "(rpcd) %s: (0x%lx) %s\n", str, (unsigned long) *st, estr); 276 syslog(LOG_ERR, "%s: (0x%lx) %s\n", str, (unsigned long) *st, estr); 277} 278 279INTERNAL void usage(void) 280{ 281#ifdef DEBUG 282 fprintf(stderr, "usage: rpcd [-vDuf] [-d<debug switches>] [<protseq> ...]\n"); 283#else 284 fprintf(stderr, "usage: rpcd [-vuf] [<protseq> ...]\n"); 285#endif 286 fprintf(stderr, " -v: Print rpcd version and exit\n"); 287#ifdef DEBUG 288 fprintf(stderr, " -D: Turns on default RPC runtime debug output\n"); 289#endif 290 fprintf(stderr, " -u: Print this message and exit\n"); 291 fprintf(stderr, " -f: Run in foreground (default is to fork and parent exit)\n"); 292#ifdef DEBUG 293 fprintf(stderr, " -d: Turns on specified RPC runtime debug output\n"); 294#endif 295 fprintf(stderr, " If any <protseq>s are specified, the rpcd listens only on those; otherwise\n"); 296 fprintf(stderr, " all protseqs are listened on.\n"); 297} 298 299/* 300 * match_command 301 * takes a key and string as input and returns whether the 302 * string matches the key where at least min_len characters 303 * of the key are required to be specified. 304 */ 305#if 0 306INTERNAL boolean32 match_command(key,str,min_len) 307char *key; 308char *str; 309long min_len; 310{ 311 int i = 0; 312 313 if (*key) while (*key == *str) { 314 i++; 315 key++; 316 str++; 317 if (*str == '\0' || *key == '\0') 318 break; 319 } 320 if (*str == '\0' && i >= min_len) 321 return true; 322 return false; 323} 324#endif 325 326/* 327 * Process args 328 */ 329INTERNAL void process_args( 330 int argc, 331 char *argv[]) 332{ 333 int i, c; 334 unsigned32 status; 335 extern int optind; 336 extern char *optarg; 337 338 /* 339 * Process args. 340 */ 341 342 while ((c = getopt(argc, argv, "vufDd:")) != EOF) 343 { 344 switch (c) 345 { 346 case 'u': 347 usage(); 348 exit(0); 349 350 case 'v': 351 printf("\t%s\n", rpcd_version_str); 352 exit(0); 353 354 case 'f': 355 foreground = true; 356 break; 357 358 case 'd': 359 case 'D': 360 rpc__dbg_set_switches(c == 'd' ? optarg : DEBUG_LEVEL, &status); 361 if (check_st_bad("Error setting debug switches", &status)) 362 return; 363 dflag = true; 364 break; 365 366 default: 367 usage(); 368 exit(1); 369 } 370 } 371 372 argc -= optind - 1; 373 argv = &argv[optind - 1]; 374 375 use_all_protseqs = (argc == 1); 376 377 for (i = 1; i < argc; i++) 378 { 379 380 rpc_network_is_protseq_valid((unsigned_char_p_t)argv[i], &status); 381 if (check_st_bad("Protseq is not valid", &status)) 382 return; 383 384 if (num_protseq >= MAX_PROTSEQ_ARGS) 385 { 386 SET_STATUS(&status, ept_s_cant_perform_op); 387 show_st("Too many protseq args", &status); 388 return; 389 } 390 391 protseq[num_protseq++] = (unsigned_char_p_t) argv[i]; 392 use_all_protseqs = false; 393 } 394} 395 396/* 397 * Register the Endpoint Map and LLB interfaces. 398 */ 399INTERNAL void register_ifs( 400 error_status_t *status) 401{ 402 ept_v3_0_epv_t* _epv = &ept_v3_0_mgr_epv; 403 rpc_mgr_epv_t epv = (rpc_mgr_epv_t) _epv; 404 405 rpc_server_register_if(ept_v3_0_s_ifspec, (uuid_p_t)NULL, 406 epv, status); 407 if (check_st_bad("Unable to rpc_server_register_if for ept", status)) 408 return; 409 410#ifdef RPC_LLB 411 rpc_server_register_if(llb__v4_0_s_ifspec, (uuid_p_t)NULL, 412 (rpc_mgr_epv_t) &llb_v4_0_mgr_epv, status); 413 if (check_st_bad("Unable to rpc_server_register_if for llb", status)) 414 return; 415#endif 416 417#ifdef ENABLE_DCOM 418 rpc_server_register_if(IObjectExporter_v0_0_s_ifspec, (uuid_p_t)NULL, 419 (rpc_mgr_epv_t)&objex_mgr_epv, status); 420 if (check_st_bad("Unable to rpc_server_register_if for orpc", status)) 421 return; 422#endif 423 424} 425 426/* 427 * Arrange to handle calls on the protocol sequences of interest. 428 * Note that while both interfaces specify well know endpoints, 429 * the ept_ endpoints are a superset of the llb_ endpoints (which 430 * precludes us from doing a "use_protseq_if" on both). 431 */ 432INTERNAL void use_protseqs( 433 error_status_t *status) 434{ 435 unsigned32 i; 436 437 if (use_all_protseqs) 438 { 439 rpc_server_use_all_protseqs_if(0, ept_v3_0_s_ifspec, status); 440 if (! STATUS_OK(status)) 441 { 442 if (*status == rpc_s_cant_bind_sock) 443 show_st("Verify that no other rpcd/llbd is running", status); 444 else 445 show_st("Unable to rpc_server_use_all_protseqs for ept", status); 446 } 447 } 448 else 449 { 450 for (i = 0; i < num_protseq; i++) 451 { 452 rpc_server_use_protseq_if(protseq[i], 0, ept_v3_0_s_ifspec, status); 453 if (! STATUS_OK(status)) 454 { 455 if (*status == rpc_s_cant_bind_sock) 456 show_st("Verify that no other rpcd/llbd is running", status); 457 else 458 show_st("Unable to rpc_server_use_all_protseqs for ept", status); 459 } 460 } 461 } 462 463 /* 464 * If folks are interested, tell em what we're listening on... 465 */ 466 467 if (dflag) 468 { 469 rpc_binding_vector_p_t bv; 470 unsigned_char_p_t bstr; 471 error_status_t st; 472 473 printf("(rpcd) got bindings:\n"); 474 475 rpc_server_inq_bindings(&bv, status); 476 if (check_st_bad("Unable to rpc_server_inq_bindings", status)) 477 return; 478 479 for (i = 0; i < bv->count; i++) 480 { 481 rpc_binding_to_string_binding(bv->binding_h[i], &bstr, &st); 482 printf(" %s\n", bstr); 483 rpc_string_free(&bstr, &st); 484 } 485 486 rpc_binding_vector_free(&bv, status); 487 if (check_st_bad("Unable to rpc_binding_vector_free", status)) 488 return; 489 } 490} 491 492/* 493 * Do some server database, ... initialization 494 */ 495INTERNAL void init( 496 error_status_t *status) 497{ 498 epdb_handle_t h; 499 idl_uuid_t epdb_obj; 500 rpc_if_rep_p_t ept_if_rep; 501 unsigned_char_p_t fname; 502 unsigned_char_p_t dname; 503 struct stat statbuf; 504 505 uuid_create_nil(&nil_uuid, status); 506 if (check_st_bad("Can't create nil uuid", status)) { 507 return; 508 } 509 510 if (dflag) { 511 printf("(rpcd) initializing database\n"); 512 } 513 514 fname = NULL; 515 dname = NULL; 516 517 fname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + 518 strlen(rpcd_c_database_name_prefix2) + 519 strlen(rpcd_c_ep_database_name) + 1); 520 if (!fname) { 521 *status = rpc_s_no_memory; 522 check_st_bad("Error when allocating ept database filename", status); 523 return; 524 } 525 526 sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, 527 rpcd_c_database_name_prefix2, rpcd_c_ep_database_name); 528 529 dname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + 530 strlen(rpcd_c_database_name_prefix2) + 1); 531 if (!dname) { 532 *status = rpc_s_no_memory; 533 check_st_bad("Error when allocating ept database directory", status); 534 return; 535 } 536 537 sprintf((char *) dname, "%s%s", rpcd_c_database_name_prefix1, 538 rpcd_c_database_name_prefix2); 539 540 if (stat((const char *) dname, &statbuf) && 541 errno == ENOENT) { 542 printf("(rpcd) ept database directory [%s] doesn't exist\n", dname); 543 } 544 545 h = epdb_init(fname, status); 546 if (check_st_bad("Can't initialize ept database", status)) { 547 free(fname); 548 free(dname); 549 550 return; 551 } 552 553 free(fname); 554 free(dname); 555 556#ifdef RPC_LLB 557 fname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + 558 strlen(rpcd_c_database_name_prefix2) + 559 strlen(rpcd_c_llb_database_name) + 1); 560 sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, 561 rpcd_c_database_name_prefix2, rpcd_c_llb_database_name); 562 563 lbdb_init(fname, status); 564 if (check_st_bad("Can't initialize llb database", status)) 565 return; 566 567 free(fname); 568#endif 569 570 epdb_inq_object(h, &epdb_obj, status); 571 if (check_st_bad("Can't get ept object uuid", status)) { 572 /* do nothing */; 573 } 574 ept_if_rep = (rpc_if_rep_p_t) ept_v3_0_s_ifspec; 575 rpc_object_set_type(&epdb_obj, &ept_if_rep->id, status); 576 if (check_st_bad("Can't set ept object type", status)) { 577 /* do nothing */; 578 } 579 580 if (dflag) 581 { 582 unsigned_char_p_t ustr; 583 error_status_t st; 584 585 uuid_to_string(&epdb_obj, &ustr, &st); 586 printf("(rpcd) endpoint database object id: %s\n", ustr); 587 rpc_string_free(&ustr, &st); 588 } 589} 590 591 592/* 593 * Perform the forwarding map algorithm to produce an rpc_addr to the 594 * selected endpoint. 595 * 596 * Eventually, we probably want to get all packets from a single activity 597 * to a single server (assuming that we can figure out how take advantage 598 * of selecting different potential servers in the face of stale entries). 599 * 600 */ 601INTERNAL void fwd_map( 602 uuid_p_t object, 603 rpc_if_id_p_t interface, 604 rpc_syntax_id_p_t data_rep, 605 rpc_protocol_id_t rpc_protocol, 606 unsigned32 rpc_protocol_vers_major, 607 unsigned32 rpc_protocol_vers_minor, 608 rpc_addr_p_t addr, 609 uuid_p_t actuuid ATTRIBUTE_UNUSED, 610 rpc_addr_p_t *fwd_addr, 611 rpc_fwd_action_t *fwd_action, 612 error_status_t *status) 613{ 614 unsigned32 num_ents; 615 epdb_handle_t h; 616 617 /* 618 * Forwarding algorithm: 619 * Consult ep database (and possibly the llb database) to see if 620 * anybody has registered the matching interface/object uuids. 621 */ 622 623 num_ents = 0; 624 625 h = epdb_inq_handle(); 626 epdb_fwd(h, object, interface, data_rep, 627 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, 628 addr, NULL, 1L, &num_ents, fwd_addr, status); 629 630#ifdef RPC_LLB 631 if ((*status == ept_s_not_registered) || 632 ((*status == rpc_s_ok) && (num_ents == 0)) ) 633 { 634 h = lbdb_inq_handle(); 635 lbdb_fwd(h, object, &interface->uuid, addr, 636 NULL, 1L, &num_ents, fwd_addr, status); 637 } 638#endif 639 640 if (*status != rpc_s_ok) 641 { 642 if (*status == ept_s_not_registered) 643 { 644 *fwd_action = rpc_e_fwd_drop; 645 *status = rpc_s_ok; 646 } 647 return; 648 } 649 650 assert(num_ents <= 1); 651 652 *fwd_action = num_ents == 0 ? rpc_e_fwd_drop : rpc_e_fwd_forward; 653 return; 654} 655 656 657//#if defined(UNIX) || defined(unix) 658 659#define RPCD_PID_FILE "/var/run/dcerpcd.pid" 660#define PID_FILE_CONTENTS_SIZE ((9 * 2) + 2) 661#define RPCD_DAEMON_NAME "dcerpcd" 662 663INTERNAL void StripLeadingWhitespace( 664 char *str) 665{ 666 char* pszNew = str; 667 char* pszTmp = str; 668 669 if (!str || !*str || !isspace((int)*str)) { 670 return; 671 } 672 673 while (pszTmp != NULL && *pszTmp != '\0' && isspace((int)*pszTmp)) { 674 pszTmp++; 675 } 676 677 while (pszTmp != NULL && *pszTmp != '\0') { 678 *pszNew++ = *pszTmp++; 679 } 680 *pszNew = '\0'; 681} 682 683INTERNAL void StripTrailingWhitespace( 684 char *str) 685{ 686 char* pszLastSpace = NULL; 687 char* pszTmp = str; 688 689 if (!str || !*str) { 690 return; 691 } 692 693 while (pszTmp != NULL && *pszTmp != '\0') { 694 pszLastSpace = (isspace((int)*pszTmp) ? (pszLastSpace ? pszLastSpace : pszTmp) : NULL); 695 pszTmp++; 696 } 697 698 if (pszLastSpace != NULL) { 699 *pszLastSpace = '\0'; 700 } 701} 702 703INTERNAL void StripWhitespace( 704 char *str) 705{ 706 if (!str || !*str) 707 return; 708 StripLeadingWhitespace(str); 709 StripTrailingWhitespace(str); 710} 711 712INTERNAL int MatchProgramToPID( 713 const char *pszProgramName, 714 pid_t pid) 715{ 716 int ceError = 0; 717 char szBuf[PATH_MAX+1]; 718 FILE* pFile = NULL; 719 720#if defined(__MACH__) && defined(__APPLE__) 721 sprintf(szBuf, "ps -p %d -o command= | grep %s", pid, pszProgramName); 722#else 723 sprintf(szBuf, "UNIX95=1 ps -p %ld -o comm= | grep %s", (long)pid, pszProgramName); 724#endif 725 726 pFile = popen(szBuf, "r"); 727 if (pFile == NULL) { 728 ceError = errno; 729 goto error; 730 } 731 732 while (TRUE) { 733 734 if (NULL == fgets(szBuf, PATH_MAX, pFile)) { 735 if (feof(pFile)) 736 break; 737 else { 738 ceError = errno; 739 goto error; 740 } 741 } 742 743 StripWhitespace(szBuf); 744 if (*szBuf) { 745 ceError = 0; 746 break; 747 } 748 749 } 750 751error: 752 753 if (pFile) 754 fclose(pFile); 755 756 return ceError; 757} 758 759INTERNAL pid_t pid_from_pid_file(void) 760{ 761 pid_t pid = 0; 762 int fd = -1; 763 int result; 764 char contents[PID_FILE_CONTENTS_SIZE]; 765 766 fd = open(RPCD_PID_FILE, O_RDONLY, 0644); 767 if (fd < 0) { 768 goto error; 769 } 770 771 result = dcethread_read(fd, contents, sizeof(contents)-1); 772 if (result < 0) { 773 goto error; 774 } else if (result == 0) { 775 unlink(RPCD_PID_FILE); 776 goto error; 777 } 778 contents[result-1] = 0; 779 780 result = atoi(contents); 781 if (result < 0) { 782 result = -1; 783 goto error; 784 } else if (result == 0) { 785 unlink(RPCD_PID_FILE); 786 goto error; 787 } 788 789 pid = (pid_t) result; 790 result = kill(pid, 0); 791 if (result != 0 || errno == ESRCH) { 792 unlink(RPCD_PID_FILE); 793 pid = 0; 794 } else { 795 // Verify that the peer process is a rpc daemon 796 if (MatchProgramToPID(RPCD_DAEMON_NAME, pid) != 0) { 797 unlink(RPCD_PID_FILE); 798 pid = 0; 799 } 800 } 801 802error: 803 if (fd != -1) { 804 close(fd); 805 } 806 807 return pid; 808} 809 810static 811void 812delete_pid_file() 813{ 814 pid_t pid; 815 816 pid = pid_from_pid_file(); 817 if (pid == getpid()) { 818 unlink(RPCD_PID_FILE); 819 } 820} 821 822INTERNAL void create_pid_file(void) 823{ 824 int result = -1; 825 pid_t pid; 826 char contents[PID_FILE_CONTENTS_SIZE]; 827 size_t len; 828 int fd = -1; 829 830 pid = pid_from_pid_file(); 831 if (pid > 0) { 832 fprintf(stderr, "Daemon already running as %d", (int) pid); 833 result = -1; 834 goto error; 835 } 836 837 fd = open(RPCD_PID_FILE, O_CREAT | O_WRONLY | O_EXCL, 0644); 838 if (fd < 0) { 839 fprintf(stderr, "Could not create pid file: %s", strerror(errno)); 840 result = 1; 841 goto error; 842 } 843 844 pid = getpid(); 845 snprintf(contents, sizeof(contents)-1, "%d\n", (int) pid); 846 contents[sizeof(contents)-1] = 0; 847 len = strlen(contents); 848 849 result = (int) dcethread_write(fd, contents, len); 850 if ( result != (int) len ) { 851 fprintf(stderr, "Could not write to pid file: %s", strerror(errno)); 852 result = -1; 853 goto error; 854 } 855 856 result = 0; 857 858error: 859 if (fd != -1) { 860 close(fd); 861 } 862 863 if (result < 0) { 864 exit(1); 865 } 866} 867 868INTERNAL void attach_log_file(void) 869{ 870 int fd; 871 char *fname; 872 char *p; 873 874 if ((fname = malloc(strlen(rpcd_c_database_name_prefix1) + 875 strlen(rpcd_c_database_name_prefix2) + 876 strlen(rpcd_c_logfile_name) + 1)) != NULL) 877 { 878 sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, 879 rpcd_c_database_name_prefix2, rpcd_c_logfile_name); 880 if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 881 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) != -1) 882 { 883 (void)dup2(fd,2); 884 } 885 (void)close(fd); 886 /* 887 * We don't care if open() or dup2() failed. 888 */ 889 890 if ((p = strrchr(fname, (int)'/')) != NULL) 891 { 892 *p = '\0'; 893 if (chdir(fname)) 894 { 895 /* 896 * Again, we don't care if chdir() failed. 897 */ 898 } 899 } 900 free(fname); 901 } 902} 903 904INTERNAL void start_as_daemon(void) 905{ 906 int pid; 907 int fd; 908 909 /* Use dcethread_fork() rather than fork() because we link with DCE/RPC */ 910 if ((pid = dcethread_fork()) != 0) 911 { 912 // Parent terminates 913 exit(0); 914 } 915 916 // Let the first child be a session leader 917 setsid(); 918 919 // Ignore SIGHUP, because when the first child terminates 920 // it would be a session leader, and thus all processes in 921 // its session would receive the SIGHUP signal. By ignoring 922 // this signal, we are ensuring that our second child will 923 // ignore this signal and will continue execution. 924#ifdef SIG_ERR 925 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) 926#else 927 if (signal(SIGHUP, SIG_IGN) < 0) 928#endif 929 { 930 exit(1); 931 } 932 933 // Spawn a second child 934 if ((pid = fork()) != 0) { 935 // Let the first child terminate 936 // This will ensure that the second child cannot be a session leader 937 // Therefore, the second child cannot hold a controlling terminal 938 exit(0); 939 } 940 941 for (fd = 0; fd < 3; fd++) 942 { 943 close(fd); 944 } 945 946 for (fd = 0; fd < 3; fd++) 947 { 948 int null_fd = open("/dev/null", O_RDWR, 0); 949 if (null_fd < 0) 950 { 951 null_fd = open("/dev/null", O_WRONLY, 0); 952 } 953 if (null_fd < 0) 954 { 955 exit(1); 956 } 957 if (null_fd != fd) 958 { 959 exit(1); 960 } 961 } 962 963 atexit(delete_pid_file); 964 create_pid_file(); 965 attach_log_file(); 966} 967 968static 969void* 970rpcd_listen_thread( 971 void* arg 972 ) 973{ 974 error_status_t status = 0; 975 976 rpc_server_listen(5, &status); 977 *(error_status_t*) arg = status; 978 979 return arg; 980} 981 982static 983void* 984rpcd_network_thread( 985 void* arg 986 ) 987{ 988 error_status_t status = 0; 989 int index = 0; 990 int jndex = 0; 991 boolean32 use_protseq = false; 992 static const struct timespec retry_interval = {5, 0}; 993 static const char* network_protseqs[] = 994 { 995 "ncacn_ip_tcp", 996 "ncadg_ip_udp", 997 NULL 998 }; 999 1000 while (network_protseqs[index]) 1001 { 1002 use_protseq = false; 1003 if (!use_all_protseqs) 1004 { 1005 for (jndex = 0; jndex < num_protseq; jndex++) 1006 { 1007 if (!strcmp(network_protseqs[index], protseq[jndex])) 1008 { 1009 use_protseq = true; 1010 break; 1011 } 1012 } 1013 } 1014 else 1015 { 1016 use_protseq = true; 1017 } 1018 if (use_protseq) 1019 { 1020 rpc_server_use_protseq_if( 1021 (unsigned char*) network_protseqs[index], 1022 0, 1023 ept_v3_0_s_ifspec, 1024 &status); 1025 } 1026 1027 if (!STATUS_OK(&status)) 1028 { 1029 printf("(rpcd) Could not listen on %s: %x. Retrying in %i seconds\n", 1030 network_protseqs[index], status, (int) retry_interval.tv_sec); 1031 dcethread_delay(&retry_interval); 1032 } 1033 else 1034 { 1035 index++; 1036 } 1037 } 1038 1039 *(error_status_t*) arg = status; 1040 1041 return arg; 1042} 1043 1044static 1045void 1046rpcd_handle_sigint( 1047 int sig 1048 ) 1049{ 1050 raise(SIGTERM); 1051} 1052 1053static 1054void 1055rpcd_configure_signals( 1056 void 1057 ) 1058{ 1059 sigset_t set; 1060 int i = 0; 1061 1062 static const int block_signals[] = 1063 { 1064 SIGTERM, 1065 SIGHUP, 1066 -1 1067 }; 1068 static const struct sigaction act = 1069 { 1070 .sa_handler = rpcd_handle_sigint, 1071 .sa_flags = 0 1072 }; 1073 1074 if (sigaction(SIGINT, &act, NULL) < 0) 1075 { 1076 printf("(rpcd) System call failed\n"); 1077 exit(1); 1078 } 1079 1080 if (sigemptyset(&set) < 0) 1081 { 1082 printf("(rpcd) System call failed\n"); 1083 exit(1); 1084 } 1085 1086 for (i = 0; block_signals[i] != -1; i++) 1087 { 1088 if (sigaddset(&set, block_signals[i]) < 0) 1089 { 1090 printf("(rpcd) System call failed\n"); 1091 exit(1); 1092 } 1093 } 1094 1095 if (pthread_sigmask(SIG_SETMASK, &set, NULL) != 0) 1096 { 1097 printf("(rpcd) pthread_sigmask(): %s\n", strerror(errno)); 1098 exit(1); 1099 } 1100} 1101 1102static 1103void 1104rpcd_wait_signals( 1105 error_status_t* status 1106 ) 1107{ 1108 sigset_t set; 1109 static int wait_signals[] = 1110 { 1111 SIGTERM, 1112 SIGHUP, 1113 -1 1114 }; 1115 int sig = -1; 1116 int i = 0; 1117 1118 if (sigemptyset(&set) < 0) 1119 { 1120 *status = rpc_s_unknown_error; 1121 goto error; 1122 } 1123 1124 for (i = 0; wait_signals[i] != -1; i++) 1125 { 1126 if (sigaddset(&set, wait_signals[i]) < 0) 1127 { 1128 *status = rpc_s_unknown_error; 1129 goto error; 1130 } 1131 } 1132 1133 for (;;) 1134 { 1135 if (sigwait(&set, &sig) < 0) 1136 { 1137 *status = rpc_s_unknown_error; 1138 goto error; 1139 } 1140 1141 printf("(rpcd) Received signal %i\n", sig); 1142 1143 switch (sig) 1144 { 1145 case SIGTERM: 1146 goto cleanup; 1147 default: 1148 break; 1149 } 1150 } 1151 1152cleanup: 1153 1154 return; 1155 1156error: 1157 1158 goto cleanup; 1159} 1160 1161static void 1162rpcd_verify_sockets_directory( 1163 const char * path) 1164{ 1165 const static mode_t np_dir_mode = 0755; 1166 1167 if (chmod(path, np_dir_mode) != 0) 1168 { 1169 if (errno != ENOENT || mkdir(path, np_dir_mode) != 0) 1170 { 1171 1172 printf("(rpcd) could not change permissions on %s directory...\n", 1173 path); 1174 exit(1); 1175 } 1176 } 1177} 1178 1179int main(int argc, char *argv[]) 1180{ 1181 error_status_t status, listen_status, network_status; 1182 int uid ; 1183 int ret; 1184 const char* sm_notify = NULL; 1185 int notify_fd = -1; 1186 int notify_code = 0; 1187 dcethread* listen_thread = NULL; 1188 dcethread* network_thread = NULL; 1189 boolean32 is_listening = false; 1190 1191 /* begin */ 1192 1193 setlocale(LC_ALL, ""); 1194 1195 process_args(argc, argv); 1196 1197 /* 1198 * Must be root (pid=0) to be able to start llbd 1199 */ 1200 uid = getuid(); 1201 if (uid != 0) { 1202 fprintf(stderr, "(rpcd) Must be root to start rpcd, your uid = %d \n", uid); 1203 exit(2); 1204 } 1205 1206 /* Set up signals */ 1207 rpcd_configure_signals(); 1208 1209 /* 1210 * If not debugging, fork off a process to be the rpcd. The parent exits. 1211 */ 1212 1213 if (!dflag && !foreground) 1214 { 1215 start_as_daemon(); 1216 } 1217 1218 /* 1219 * Initialize the runtime by calling this public routine 1220 */ 1221 rpc_network_is_protseq_valid ((unsigned_char_p_t) "ncadg_ip_udp", &status); 1222 1223 /* 1224 * Initialize the database and other misc stuff. 1225 */ 1226 init(&status); 1227 if (! STATUS_OK(&status)) exit(1); 1228 1229 register_ifs(&status); 1230 if (! STATUS_OK(&status)) exit(1); 1231 1232 /* 1233 * Ensure permissions on pipes directory and on unix sockets 1234 * directory if it's different. 1235 */ 1236 rpcd_verify_sockets_directory(RPC_C_NP_DIR); 1237 if (strcmp(RPC_C_NP_DIR, RPC_C_UXD_DIR) != 0) 1238 { 1239 rpcd_verify_sockets_directory(RPC_C_UXD_DIR); 1240 } 1241 1242 /* 1243 * Register lcalrpc endpoint as a baseline to ensure local services can talk to us 1244 */ 1245 rpc_server_use_protseq_if((unsigned char*) "ncalrpc", 0, ept_v3_0_s_ifspec, &status); 1246 1247 if (!STATUS_OK(&status)) 1248 { 1249 printf("(rpcd) could not listen on ncalrpc\n"); 1250 exit(1); 1251 } 1252 1253 rpc__server_register_fwd_map(fwd_map, &status); 1254 if (check_st_bad("Unable to rpc_server_register_fwd_map", &status)) 1255 exit(1); 1256 1257 if (dflag) 1258 printf("(rpcd) listening...\n"); 1259 1260 /* 1261 * Fire up listener thread 1262 */ 1263 dcethread_create_throw(&listen_thread, NULL, rpcd_listen_thread, (void*) &listen_status); 1264 1265 /* 1266 * Busy wait until we are actually listening 1267 */ 1268 while (!is_listening) 1269 { 1270 is_listening = rpc_mgmt_is_server_listening(NULL, &status); 1271 1272 if (!STATUS_OK(&status)) 1273 { 1274 printf("(rpcd) could not determine if listener is running\n"); 1275 exit(1); 1276 } 1277 } 1278 1279 /* 1280 * If we were started by the service manager, let it know we are ready 1281 */ 1282 if ((sm_notify = getenv("LIKEWISE_SM_NOTIFY")) != NULL) 1283 { 1284 notify_fd = atoi(sm_notify); 1285 1286 do 1287 { 1288 ret = dcethread_write(notify_fd, ¬ify_code, sizeof(notify_code)); 1289 } while(ret != sizeof(notify_code) && errno == EINTR); 1290 1291 if (ret < 0) 1292 { 1293 printf("(rpcd) Could not notify service manager: %s (%i)", strerror(errno), errno); 1294 exit(1); 1295 } 1296 1297 close(notify_fd); 1298 } 1299 1300 /* 1301 * Fire up network detection thread 1302 */ 1303 1304 dcethread_create_throw(&network_thread, NULL, rpcd_network_thread, (void*) &network_status); 1305 1306 /* 1307 * Wait for signals 1308 */ 1309 1310 rpcd_wait_signals(&status); 1311 1312 if (check_st_bad("Error waiting for signals", &status)) 1313 { 1314 exit(1); 1315 } 1316 1317 /* 1318 * Tell listener thread to stop 1319 */ 1320 1321 rpc_mgmt_stop_server_listening(NULL, &status); 1322 1323 if (check_st_bad("Error stopping server", &status)) 1324 { 1325 exit(1); 1326 } 1327 1328 /* 1329 * Wait for listener thread to exit 1330 */ 1331 dcethread_join_throw(listen_thread, NULL); 1332 1333 /* 1334 * Cancel network detection thread 1335 */ 1336 dcethread_interrupt_throw(network_thread); 1337 1338 /* 1339 * Join network detection thread 1340 */ 1341 dcethread_join_throw(network_thread, NULL); 1342 1343 /* 1344 * We're done 1345 */ 1346 exit(0); 1347} 1348