1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 
30 /*
31  * This is a proxy daemon for the real Java slpd. This deamon starts
32  * at boot time, and listens for any incoming SLP messages only on
33  * loopback -- this way, only local processes can start the real
34  * daemon. When a message comes in, the proxy daemon dups the message
35  * fds onto fds 0, 1, and 2, and execs the real Java slpd. The purpose
36  * of this approach is for performance: boot time performance is
37  * not degraded by cranking off the (huge) JVM, and systems take
38  * the JVM resource hit only if they actually use SLP.
39  */
40 
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <sys/byteorder.h>
47 #include <sys/resource.h>
48 #include <netinet/in.h>
49 #include <unistd.h>
50 #include <slp.h>
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #include <syslog.h>
54 
55 /* This is an index which points into the args array at the conf file arg */
56 #define	CONF_INDEX	6
57 
58 /* Location of the Java Virtual Machine */
59 #define	JAVA_VM	"/usr/java/jre/bin/java"
60 
61 static char *slpd_args[] = {
62 	JAVA_VM,
63 	"-Xmx128m",
64 	"-classpath",
65 	"/usr/share/lib/slp/slpd.jar",
66 	"com.sun.slp.slpd",
67 	"-f",
68 	"/etc/inet/slp.conf",
69 	0
70 };
71 
72 /*
73  * These are global so they can be easily accessed from a signal
74  * handler for cleanup.
75  */
76 
77 static void
78 run_slpd(void)
79 {
80 	closelog();
81 
82 	if (execv(*slpd_args, slpd_args) == -1) {
83 		openlog("slpd", LOG_PID, LOG_DAEMON);
84 		syslog(LOG_ERR, "execv failed: %s", strerror(errno));
85 		closelog();
86 	}
87 }
88 
89 /*
90  * If an alternate config file was specified with -f, make sure slpd
91  * uses that config file. Also, force libslp.so to use that new config
92  * file when checking to see if slpd is a DA. If any other arguments
93  * are given, they are ignored.
94  */
95 static void
96 do_args(int argc, char *const *argv)
97 {
98 	int c;
99 	char *conf = NULL;
100 
101 	while ((c = getopt(argc, argv, "f:")) != EOF)
102 		switch (c) {
103 		case 'f':
104 			conf = optarg;
105 			break;
106 		default:
107 			break;
108 		}
109 
110 	if (conf != NULL) {
111 		char	*prefix = "SLP_CONF_FILE=";
112 		int	env_size;
113 		char	*conf_env;
114 
115 		env_size = strlen(prefix) + strlen(conf) + 1;
116 		if ((conf_env = malloc(env_size)) == NULL) {
117 			syslog(LOG_ERR, "no memory");
118 			exit(1);
119 		}
120 		(void) strlcpy(conf_env, prefix, env_size);
121 		(void) strlcat(conf_env, conf, env_size);
122 
123 		(void) putenv(conf_env);
124 
125 		slpd_args[CONF_INDEX] = conf;
126 	}
127 }
128 
129 static void
130 detachfromtty(void) {
131 	switch (fork()) {
132 	case -1:
133 		perror("slpd: can not fork");
134 		exit(1);
135 		/*NOTREACHED*/
136 	case 0:
137 		break;
138 	default:
139 		exit(0);
140 	}
141 
142 	/*
143 	 * Close existing file descriptors, open "/dev/null" as
144 	 * standard input, output, and error, and detach from
145 	 * controlling terminal.
146 	 */
147 	closefrom(0);
148 	(void) open("/dev/null", O_RDONLY);
149 	(void) open("/dev/null", O_WRONLY);
150 	(void) dup(1);
151 	(void) setsid();
152 }
153 
154 static void
155 cleanup_and_exit(int retval)
156 {
157 	closelog();
158 	exit(retval);
159 }
160 
161 int
162 main(int argc, char *const *argv)
163 {
164 	struct sockaddr_in bindaddr;
165 	socklen_t addrlen;
166 	const char *isDA;
167 	const char *proxyReg;
168 	int connfd;
169 	int lfd;
170 	const int on = 1;
171 
172 	detachfromtty();
173 
174 	openlog("slpd", LOG_PID, LOG_DAEMON);
175 
176 	do_args(argc, argv);
177 
178 	/* If slpd has been configured to run as a DA, start it and exit */
179 	isDA = SLPGetProperty("net.slp.isDA");
180 	proxyReg = SLPGetProperty("net.slp.serializedRegURL");
181 	if ((isDA && (strcasecmp(isDA, "true") == 0)) || proxyReg) {
182 		run_slpd();
183 		return (1);
184 	}
185 
186 	if ((lfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
187 		syslog(LOG_ERR, "socket failed: %s", strerror(errno));
188 		cleanup_and_exit(1);
189 	}
190 
191 	(void) setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
192 
193 	(void) memset((void *)&bindaddr, 0, sizeof (bindaddr));
194 	bindaddr.sin_family = AF_INET;
195 	bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
196 	bindaddr.sin_port = htons(427);
197 
198 	if (bind(lfd, (const struct sockaddr *)&bindaddr, sizeof (bindaddr))
199 	    < 0) {
200 		syslog(LOG_ERR, "bind failed: %s", strerror(errno));
201 		cleanup_and_exit(1);
202 	}
203 
204 	if (listen(lfd, 1) < 0) {
205 		syslog(LOG_ERR, "listen failed: %s", strerror(errno));
206 		cleanup_and_exit(1);
207 	}
208 
209 	addrlen = sizeof (bindaddr);
210 	if ((connfd = accept(lfd, (struct sockaddr *)&bindaddr, &addrlen))
211 	    < 0) {
212 		syslog(LOG_ERR, "accept failed: %s", strerror(errno));
213 		cleanup_and_exit(1);
214 	}
215 
216 	(void) close(lfd);
217 
218 	(void) dup2(connfd, 0);
219 	(void) close(connfd);
220 	(void) dup2(0, 1);
221 	(void) dup2(0, 2);
222 
223 	run_slpd();
224 
225 	return (1);
226 }
227