/* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this * file for any purpose is hereby granted without fee, provided that * the above copyright notices and this notice appears in all source * code copies, and that none of the names of Open Software * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment * Corporation be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Neither Open Software Foundation, Inc., Hewlett- * Packard Company, nor Digital Equipment Corporation makes any * representations about the suitability of this software for any * purpose. * */ /* */ /* ** ** NAME: ** ** rpcd.c ** ** FACILITY: ** ** RPC Daemon ** ** ABSTRACT: ** ** This daemon is a catch all for DCE RPC support functions. This server ** exports the DCE 1.0 endpoint map (ept_) network interfaces and, optionally, ** the NCS 1.5.1 llb_ network interfaces and . Additionally, this server ** provides the RPC forwarding map function used by non-connection oriented ** protocol services. ** ** */ #include #include #include EXTERNAL ept_v3_0_epv_t ept_v3_0_mgr_epv; #ifdef RPC_LLB # include EXTERNAL llb__v4_0_epv_t llb_v4_0_mgr_epv; #endif #ifdef ENABLE_DCOM # include EXTERNAL IObjectExporter_v0_0_epv_t objex_mgr_epv; #endif #include #include #include #include #include #ifdef RPC_LLB #include #endif #include #ifndef VMS #include #include #endif #include #include #include #include /* FIXME: Hack to get prototypes we need on AIX */ #if defined(_AIX) && defined(_BSD) extern pid_t setpgrp(void); int ioctl(int d, int request, ...); #ifdef SETPGRP_ARGS # undef SETPGRP_ARGS #endif #define SETPGRP_ARGS 0 #endif INTERNAL void usage _DCE_PROTOTYPE_ (( void )); #if 0 INTERNAL boolean32 match_command _DCE_PROTOTYPE_ (( char *key, char *str, long min_len )); #endif INTERNAL void process_args _DCE_PROTOTYPE_ (( int argc, char *argv[] )); INTERNAL void register_ifs _DCE_PROTOTYPE_ (( error_status_t *status )); INTERNAL void use_protseqs _DCE_PROTOTYPE_ (( error_status_t *status )); INTERNAL void init _DCE_PROTOTYPE_ (( error_status_t *status )); INTERNAL void fwd_map _DCE_PROTOTYPE_ (( uuid_p_t object, rpc_if_id_p_t interface, rpc_syntax_id_p_t data_rep, rpc_protocol_id_t rpc_protocol, unsigned32 rpc_protocol_vers_major, unsigned32 rpc_protocol_vers_minor, rpc_addr_p_t addr, uuid_p_t actuuid, rpc_addr_p_t *fwd_addr, rpc_fwd_action_t *fwd_action, error_status_t *status )); /* * These implementation constants can be redefined in the system specific * config files if necessary (e.g. common/ultrix_mips.h). */ #ifdef DCELOCAL_PATH # define rpcd_c_database_name_prefix1 DCELOCAL_PATH # define rpcd_c_database_name_prefix2 "/var/rpc/" #else #ifndef rpcd_c_database_name_prefix1 # define rpcd_c_database_name_prefix1 "/tmp/" #endif #ifndef rpcd_c_database_name_prefix2 # define rpcd_c_database_name_prefix2 "" #endif #endif #ifndef rpcd_c_ep_database_name # define rpcd_c_ep_database_name "rpcdep.dat" #endif #ifndef rpcd_c_llb_database_name # define rpcd_c_llb_database_name "rpcdllb.dat" #endif #ifndef rpcd_c_logfile_name # define rpcd_c_logfile_name "rpcd.log" #endif /* * Optional list of protocol sequences which rpcd will use. * List is specified on the command line */ #define MAX_PROTSEQ_ARGS 8 INTERNAL unsigned_char_p_t protseq[MAX_PROTSEQ_ARGS]; INTERNAL unsigned32 num_protseq = 0; INTERNAL boolean32 use_all_protseqs = true; /* * Debug flag controls */ GLOBAL boolean32 dflag = false; #define DEBUG_LEVEL "0.1" INTERNAL boolean32 foreground = false; INTERNAL char rpcd_version_str[] = #ifdef ENABLE_DCOM "rpcd/orpcd version freedce 1.1"; #else "rpcd version freedce 1.1"; #endif GLOBAL uuid_t nil_uuid; PRIVATE boolean32 check_st_bad(str, st) char *str; error_status_t *st; { if (STATUS_OK(st)) return false; show_st(str, st); return true; } PRIVATE void show_st(str, st) char *str; error_status_t *st; { dce_error_string_t estr; int tmp_st; dce_error_inq_text(*st, (unsigned char*) estr, &tmp_st); fprintf(stderr, "(rpcd) %s: (0x%lx) %s\n", str, (unsigned long) *st, estr); syslog(LOG_ERR, "%s: (0x%lx) %s\n", str, (unsigned long) *st, estr); } INTERNAL void usage() { #ifdef DEBUG fprintf(stderr, "usage: rpcd [-vDuf] [-d] [ ...]\n"); #else fprintf(stderr, "usage: rpcd [-vuf] [ ...]\n"); #endif fprintf(stderr, " -v: Print rpcd version and exit\n"); #ifdef DEBUG fprintf(stderr, " -D: Turns on default RPC runtime debug output\n"); #endif fprintf(stderr, " -u: Print this message and exit\n"); fprintf(stderr, " -f: Run in foreground (default is to fork and parent exit)\n"); #ifdef DEBUG fprintf(stderr, " -d: Turns on specified RPC runtime debug output\n"); #endif fprintf(stderr, " If any s are specified, the rpcd listens only on those; otherwise\n"); fprintf(stderr, " all protseqs are listened on.\n"); } /* * match_command * takes a key and string as input and returns whether the * string matches the key where at least min_len characters * of the key are required to be specified. */ #if 0 INTERNAL boolean32 match_command(key,str,min_len) char *key; char *str; long min_len; { int i = 0; if (*key) while (*key == *str) { i++; key++; str++; if (*str == '\0' || *key == '\0') break; } if (*str == '\0' && i >= min_len) return true; return false; } #endif /* * Process args */ INTERNAL void process_args(argc, argv) int argc; char *argv[]; { int i, c; unsigned32 status; extern int optind; extern char *optarg; /* * Process args. */ while ((c = getopt(argc, argv, "vufDd:")) != EOF) { switch (c) { case 'u': usage(); exit(0); case 'v': printf("\t%s\n", rpcd_version_str); exit(0); case 'f': foreground = true; break; case 'd': case 'D': rpc__dbg_set_switches(c == 'd' ? optarg : DEBUG_LEVEL, &status); if (check_st_bad("Error setting debug switches", &status)) return; dflag = true; break; default: usage(); exit(1); } } argc -= optind - 1; argv = &argv[optind - 1]; use_all_protseqs = (argc == 1); for (i = 1; i < argc; i++) { rpc_network_is_protseq_valid((unsigned_char_p_t)argv[i], &status); if (check_st_bad("Protseq is not valid", &status)) return; if (num_protseq >= MAX_PROTSEQ_ARGS) { SET_STATUS(&status, ept_s_cant_perform_op); show_st("Too many protseq args", &status); return; } protseq[num_protseq++] = (unsigned_char_p_t) argv[i]; } } /* * Register the Endpoint Map and LLB interfaces. */ INTERNAL void register_ifs(status) error_status_t *status; { ept_v3_0_epv_t* _epv = &ept_v3_0_mgr_epv; rpc_mgr_epv_t epv = (rpc_mgr_epv_t) _epv; rpc_server_register_if(ept_v3_0_s_ifspec, (uuid_p_t)NULL, epv, status); if (check_st_bad("Unable to rpc_server_register_if for ept", status)) return; #ifdef RPC_LLB rpc_server_register_if(llb__v4_0_s_ifspec, (uuid_p_t)NULL, (rpc_mgr_epv_t) &llb_v4_0_mgr_epv, status); if (check_st_bad("Unable to rpc_server_register_if for llb", status)) return; #endif #ifdef ENABLE_DCOM rpc_server_register_if(IObjectExporter_v0_0_s_ifspec, (uuid_p_t)NULL, (rpc_mgr_epv_t)&objex_mgr_epv, status); if (check_st_bad("Unable to rpc_server_register_if for orpc", status)) return; #endif } /* * Arrange to handle calls on the protocol sequences of interest. * Note that while both interfaces specify well know endpoints, * the ept_ endpoints are a superset of the llb_ endpoints (which * precludes us from doing a "use_protseq_if" on both). */ INTERNAL void use_protseqs(status) error_status_t *status; { unsigned32 i; if (use_all_protseqs) { rpc_server_use_all_protseqs_if(0, ept_v3_0_s_ifspec, status); if (! STATUS_OK(status)) { if (*status == rpc_s_cant_bind_sock) show_st("Verify that no other rpcd/llbd is running", status); else show_st("Unable to rpc_server_use_all_protseqs for ept", status); } } else { for (i = 0; i < num_protseq; i++) { rpc_server_use_protseq_if(protseq[i], 0, ept_v3_0_s_ifspec, status); if (! STATUS_OK(status)) { if (*status == rpc_s_cant_bind_sock) show_st("Verify that no other rpcd/llbd is running", status); else show_st("Unable to rpc_server_use_all_protseqs for ept", status); } } } /* * If folks are interested, tell em what we're listening on... */ if (dflag) { rpc_binding_vector_p_t bv; unsigned_char_p_t bstr; error_status_t st; printf("(rpcd) got bindings:\n"); rpc_server_inq_bindings(&bv, status); if (check_st_bad("Unable to rpc_server_inq_bindings", status)) return; for (i = 0; i < bv->count; i++) { rpc_binding_to_string_binding(bv->binding_h[i], &bstr, &st); printf(" %s\n", bstr); rpc_string_free(&bstr, &st); } rpc_binding_vector_free(&bv, status); if (check_st_bad("Unable to rpc_binding_vector_free", status)) return; } } /* * Do some server database, ... initialization */ INTERNAL void init(status) error_status_t *status; { epdb_handle_t h; uuid_t epdb_obj; rpc_if_rep_p_t ept_if_rep; unsigned_char_p_t fname; unsigned_char_p_t dname; struct stat statbuf; uuid_create_nil(&nil_uuid, status); if (check_st_bad("Can't create nil uuid", status)) { return; } if (dflag) { printf("(rpcd) initializing database\n"); } fname = NULL; dname = NULL; fname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + strlen(rpcd_c_database_name_prefix2) + strlen(rpcd_c_ep_database_name) + 1); if (!fname) { *status = rpc_s_no_memory; check_st_bad("Error when allocating ept database filename", status); return; } sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, rpcd_c_database_name_prefix2, rpcd_c_ep_database_name); dname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + strlen(rpcd_c_database_name_prefix2) + 1); if (!dname) { *status = rpc_s_no_memory; check_st_bad("Error when allocating ept database directory", status); return; } sprintf((char *) dname, "%s%s", rpcd_c_database_name_prefix1, rpcd_c_database_name_prefix2); if (stat((char *) dname, &statbuf) && errno == ENOENT) { printf("(rpcd) ept database directory [%s] doesn't exist\n", dname); } h = epdb_init(fname, status); if (check_st_bad("Can't initialize ept database", status)) { free(fname); free(dname); return; } free(fname); free(dname); #ifdef RPC_LLB fname = (unsigned_char_p_t) malloc(strlen(rpcd_c_database_name_prefix1) + strlen(rpcd_c_database_name_prefix2) + strlen(rpcd_c_llb_database_name) + 1); sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, rpcd_c_database_name_prefix2, rpcd_c_llb_database_name); lbdb_init(fname, status); if (check_st_bad("Can't initialize llb database", status)) return; free(fname); #endif epdb_inq_object(h, &epdb_obj, status); if (check_st_bad("Can't get ept object uuid", status)) { /* do nothing */; } ept_if_rep = (rpc_if_rep_p_t) ept_v3_0_s_ifspec; rpc_object_set_type(&epdb_obj, &ept_if_rep->id, status); if (check_st_bad("Can't set ept object type", status)) { /* do nothing */; } if (dflag) { unsigned_char_p_t ustr; error_status_t st; uuid_to_string(&epdb_obj, &ustr, &st); printf("(rpcd) endpoint database object id: %s\n", ustr); rpc_string_free(&ustr, &st); } } /* * Perform the forwarding map algorithm to produce an rpc_addr to the * selected endpoint. * * Eventually, we probably want to get all packets from a single activity * to a single server (assuming that we can figure out how take advantage * of selecting different potential servers in the face of stale entries). * */ INTERNAL void fwd_map (object, interface, data_rep, rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr, actuuid, fwd_addr, fwd_action, status) uuid_p_t object; rpc_if_id_p_t interface; rpc_syntax_id_p_t data_rep; rpc_protocol_id_t rpc_protocol; unsigned32 rpc_protocol_vers_major; unsigned32 rpc_protocol_vers_minor; rpc_addr_p_t addr; uuid_p_t actuuid ATTRIBUTE_UNUSED; rpc_addr_p_t *fwd_addr; rpc_fwd_action_t *fwd_action; error_status_t *status; { unsigned32 num_ents; epdb_handle_t h; /* * Forwarding algorithm: * Consult ep database (and possibly the llb database) to see if * anybody has registered the matching interface/object uuids. */ num_ents = 0; h = epdb_inq_handle(); epdb_fwd(h, object, interface, data_rep, rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr, NULL, 1L, &num_ents, fwd_addr, status); #ifdef RPC_LLB if ((*status == ept_s_not_registered) || ((*status == rpc_s_ok) && (num_ents == 0)) ) { h = lbdb_inq_handle(); lbdb_fwd(h, object, &interface->uuid, addr, NULL, 1L, &num_ents, fwd_addr, status); } #endif if (*status != rpc_s_ok) { if (*status == ept_s_not_registered) { *fwd_action = rpc_e_fwd_drop; *status = rpc_s_ok; } return; } assert(num_ents <= 1); *fwd_action = num_ents == 0 ? rpc_e_fwd_drop : rpc_e_fwd_forward; return; } //#if defined(UNIX) || defined(unix) #define RPCD_PID_FILE "/var/run/dcerpcd.pid" #define PID_FILE_CONTENTS_SIZE ((9 * 2) + 2) #define RPCD_DAEMON_NAME "dcerpcd" static void StripLeadingWhitespace( char* str ) { char* pszNew = str; char* pszTmp = str; if (!str || !*str || !isspace((int)*str)) { return; } while (pszTmp != NULL && *pszTmp != '\0' && isspace((int)*pszTmp)) { pszTmp++; } while (pszTmp != NULL && *pszTmp != '\0') { *pszNew++ = *pszTmp++; } *pszNew = '\0'; } static void StripTrailingWhitespace( char* str ) { char* pszLastSpace = NULL; char* pszTmp = str; if (!str || !*str) { return; } while (pszTmp != NULL && *pszTmp != '\0') { pszLastSpace = (isspace((int)*pszTmp) ? (pszLastSpace ? pszLastSpace : pszTmp) : NULL); pszTmp++; } if (pszLastSpace != NULL) { *pszLastSpace = '\0'; } } static void StripWhitespace( char* str ) { if (!str || !*str) return; StripLeadingWhitespace(str); StripTrailingWhitespace(str); } static int MatchProgramToPID( const char* pszProgramName, pid_t pid ) { int ceError = 0; char szBuf[PATH_MAX+1]; FILE* pFile = NULL; #if defined(__MACH__) && defined(__APPLE__) sprintf(szBuf, "ps -p %d -o command= | grep %s", pid, pszProgramName); #else sprintf(szBuf, "UNIX95=1 ps -p %ld -o comm= | grep %s", (long)pid, pszProgramName); #endif pFile = popen(szBuf, "r"); if (pFile == NULL) { ceError = errno; goto error; } while (TRUE) { if (NULL == fgets(szBuf, PATH_MAX, pFile)) { if (feof(pFile)) break; else { ceError = errno; goto error; } } StripWhitespace(szBuf); if (*szBuf) { ceError = 0; break; } } error: if (pFile) fclose(pFile); return ceError; } static pid_t pid_from_pid_file() { pid_t pid = 0; int fd = -1; int result; char contents[PID_FILE_CONTENTS_SIZE]; fd = open(RPCD_PID_FILE, O_RDONLY, 0644); if (fd < 0) { goto error; } result = dcethread_read(fd, contents, sizeof(contents)-1); if (result < 0) { goto error; } else if (result == 0) { unlink(RPCD_PID_FILE); goto error; } contents[result-1] = 0; result = atoi(contents); if (result < 0) { result = -1; goto error; } else if (result == 0) { unlink(RPCD_PID_FILE); goto error; } pid = (pid_t) result; result = kill(pid, 0); if (result != 0 || errno == ESRCH) { unlink(RPCD_PID_FILE); pid = 0; } else { // Verify that the peer process is a rpc daemon if (MatchProgramToPID(RPCD_DAEMON_NAME, pid) != 0) { unlink(RPCD_PID_FILE); pid = 0; } } error: if (fd != -1) { close(fd); } return pid; } static void delete_pid_file() { pid_t pid; pid = pid_from_pid_file(); if (pid == getpid()) { unlink(RPCD_PID_FILE); } } static void create_pid_file() { int result = -1; pid_t pid; char contents[PID_FILE_CONTENTS_SIZE]; size_t len; int fd = -1; pid = pid_from_pid_file(); if (pid > 0) { fprintf(stderr, "Daemon already running as %d", (int) pid); result = -1; goto error; } fd = open(RPCD_PID_FILE, O_CREAT | O_WRONLY | O_EXCL, 0644); if (fd < 0) { fprintf(stderr, "Could not create pid file: %s", strerror(errno)); result = 1; goto error; } pid = getpid(); snprintf(contents, sizeof(contents)-1, "%d\n", (int) pid); contents[sizeof(contents)-1] = 0; len = strlen(contents); result = (int) dcethread_write(fd, contents, len); if ( result != (int) len ) { fprintf(stderr, "Could not write to pid file: %s", strerror(errno)); result = -1; goto error; } result = 0; error: if (fd != -1) { close(fd); } if (result < 0) { exit(1); } } static void attach_log_file( void ) { int fd; char *fname; char *p; if ((fname = malloc(strlen(rpcd_c_database_name_prefix1) + strlen(rpcd_c_database_name_prefix2) + strlen(rpcd_c_logfile_name) + 1)) != NULL) { sprintf((char *) fname, "%s%s%s", rpcd_c_database_name_prefix1, rpcd_c_database_name_prefix2, rpcd_c_logfile_name); if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) != -1) { (void)dup2(fd,2); } (void)close(fd); /* * We don't care if open() or dup2() failed. */ if ((p = strrchr(fname, (int)'/')) != NULL) { *p = '\0'; if (chdir(fname)) { /* * Again, we don't care if chdir() failed. */ } } free(fname); } } static void start_as_daemon( void ) { int pid; int fd; /* Use dcethread_fork() rather than fork() because we link with DCE/RPC */ if ((pid = dcethread_fork()) != 0) { // Parent terminates exit(0); } // Let the first child be a session leader setsid(); // Ignore SIGHUP, because when the first child terminates // it would be a session leader, and thus all processes in // its session would receive the SIGHUP signal. By ignoring // this signal, we are ensuring that our second child will // ignore this signal and will continue execution. if (signal(SIGHUP, SIG_IGN) < 0) { exit(1); } // Spawn a second child if ((pid = fork()) != 0) { // Let the first child terminate // This will ensure that the second child cannot be a session leader // Therefore, the second child cannot hold a controlling terminal exit(0); } for (fd = 0; fd < 3; fd++) { close(fd); } for (fd = 0; fd < 3; fd++) { int null_fd = open("/dev/null", O_RDWR, 0); if (null_fd < 0) { null_fd = open("/dev/null", O_WRONLY, 0); } if (null_fd < 0) { exit(1); } if (null_fd != fd) { exit(1); } } atexit(delete_pid_file); create_pid_file(); attach_log_file(); } static void* rpcd_listen_thread( void* arg ) { error_status_t status = 0; rpc_server_listen(5, &status); *(error_status_t*) arg = status; return arg; } static void* rpcd_network_thread( void* arg ) { error_status_t status = 0; int index = 0; static const struct timespec retry_interval = {5, 0}; static const char* network_protseqs[] = { "ncacn_ip_tcp", "ncadg_ip_udp", NULL }; while (network_protseqs[index]) { rpc_server_use_protseq_if( (unsigned char*) network_protseqs[index], 0, ept_v3_0_s_ifspec, &status); if (!STATUS_OK(&status)) { printf("(rpcd) Could not listen on %s: %x. Retrying in %i seconds\n", network_protseqs[index], status, (int) retry_interval.tv_sec); dcethread_delay(&retry_interval); } else { index++; } } *(error_status_t*) arg = status; return arg; } static void rpcd_handle_sigint( int sig ) { raise(SIGTERM); } static void rpcd_configure_signals( void ) { sigset_t set; int i = 0; static const int block_signals[] = { SIGTERM, SIGHUP, -1 }; static const struct sigaction act = { .sa_handler = rpcd_handle_sigint, .sa_flags = 0 }; if (sigaction(SIGINT, &act, NULL) < 0) { printf("(rpcd) System call failed\n"); exit(1); } if (sigemptyset(&set) < 0) { printf("(rpcd) System call failed\n"); exit(1); } for (i = 0; block_signals[i] != -1; i++) { if (sigaddset(&set, block_signals[i]) < 0) { printf("(rpcd) System call failed\n"); exit(1); } } if (pthread_sigmask(SIG_SETMASK, &set, NULL) != 0) { printf("(rpcd) pthread_sigmask(): %s\n", strerror(errno)); exit(1); } } static void rpcd_wait_signals( error_status_t* status ) { sigset_t set; static int wait_signals[] = { SIGTERM, SIGHUP, -1 }; int sig = -1; int i = 0; if (sigemptyset(&set) < 0) { *status = rpc_s_unknown_error; goto error; } for (i = 0; wait_signals[i] != -1; i++) { if (sigaddset(&set, wait_signals[i]) < 0) { *status = rpc_s_unknown_error; goto error; } } for (;;) { if (sigwait(&set, &sig) < 0) { *status = rpc_s_unknown_error; goto error; } printf("(rpcd) Received signal %i\n", sig); switch (sig) { case SIGTERM: goto cleanup; default: break; } } cleanup: return; error: goto cleanup; } int main(int argc, char *argv[]) { error_status_t status, listen_status, network_status; int uid ; int ret; const char* sm_notify = NULL; int notify_fd = -1; int notify_code = 0; dcethread* listen_thread = NULL; dcethread* network_thread = NULL; boolean32 is_listening = false; const static mode_t np_dir_mode = 0755; /* begin */ setlocale(LC_ALL, ""); process_args(argc, argv); /* * Must be root (pid=0) to be able to start llbd */ uid = getuid(); if (uid != 0) { fprintf(stderr, "(rpcd) Must be root to start rpcd, your uid = %d \n", uid); exit(2); } /* Set up signals */ rpcd_configure_signals(); /* * If not debugging, fork off a process to be the rpcd. The parent exits. */ if (!dflag && !foreground) { start_as_daemon(); } /* * Initialize the runtime by calling this public routine */ rpc_network_is_protseq_valid ((unsigned_char_p_t) "ncadg_ip_udp", &status); /* * Initialize the database and other misc stuff. */ init(&status); if (! STATUS_OK(&status)) exit(1); register_ifs(&status); if (! STATUS_OK(&status)) exit(1); /* * Ensure existence/permissions on named pipe socket directory */ if (chmod(RPC_C_NP_DIR, np_dir_mode) != 0) { if (errno != ENOENT || mkdir(RPC_C_NP_DIR, np_dir_mode) != 0) { printf("(rpcd) could not change permissions on " RPC_C_NP_DIR " directory...\n"); exit(1); } } /* * Register lcalrpc endpoint as a baseline to ensure local services can talk to us */ rpc_server_use_protseq_if((unsigned char*) "ncalrpc", 0, ept_v3_0_s_ifspec, &status); if (!STATUS_OK(&status)) { printf("(rpcd) could not listen on ncalrpc\n"); exit(1); } rpc__server_register_fwd_map(fwd_map, &status); if (check_st_bad("Unable to rpc_server_register_fwd_map", &status)) exit(1); if (dflag) printf("(rpcd) listening...\n"); /* * Fire up listener thread */ dcethread_create_throw(&listen_thread, NULL, rpcd_listen_thread, (void*) &listen_status); /* * Busy wait until we are actually listening */ while (!is_listening) { is_listening = rpc_mgmt_is_server_listening(NULL, &status); if (!STATUS_OK(&status)) { printf("(rpcd) could not determine if listener is running\n"); exit(1); } } /* * If we were started by the service manager, let it know we are ready */ if ((sm_notify = getenv("LIKEWISE_SM_NOTIFY")) != NULL) { notify_fd = atoi(sm_notify); do { ret = dcethread_write(notify_fd, ¬ify_code, sizeof(notify_code)); } while(ret != sizeof(notify_code) && errno == EINTR); if (ret < 0) { printf("(rpcd) Could not notify service manager: %s (%i)", strerror(errno), errno); exit(1); } close(notify_fd); } /* * Fire up network detection thread */ dcethread_create_throw(&network_thread, NULL, rpcd_network_thread, (void*) &network_status); /* * Wait for signals */ rpcd_wait_signals(&status); if (check_st_bad("Error waiting for signals", &status)) { exit(1); } /* * Tell listener thread to stop */ rpc_mgmt_stop_server_listening(NULL, &status); if (check_st_bad("Error stopping server", &status)) { exit(1); } /* * Wait for listener thread to exit */ dcethread_join_throw(listen_thread, NULL); /* * Cancel network detection thread */ dcethread_interrupt_throw(network_thread); /* * Join network detection thread */ dcethread_join_throw(network_thread, NULL); /* * We're done */ exit(0); }