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, &notify_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