xref: /titanic_51/usr/src/cmd/rpcbind/warmstart.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * warmstart.c
24*7c478bd9Sstevel@tonic-gate  * Allows for gathering of registrations from a earlier dumped file.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Copyright 1990,2002-2003 Sun Microsystems, Inc.  All rights reserved.
27*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <errno.h>
34*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
35*7c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
38*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
39*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
40*7c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h>
41*7c478bd9Sstevel@tonic-gate #endif
42*7c478bd9Sstevel@tonic-gate #include "rpcbind.h"
43*7c478bd9Sstevel@tonic-gate #include <syslog.h>
44*7c478bd9Sstevel@tonic-gate #include <unistd.h>
45*7c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /* These files keep the pmap_list and rpcb_list in XDR format */
48*7c478bd9Sstevel@tonic-gate static const char rpcbfile[] = DAEMON_DIR "/rpcbind.file";
49*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
50*7c478bd9Sstevel@tonic-gate static const char pmapfile[] = DAEMON_DIR "/portmap.file";
51*7c478bd9Sstevel@tonic-gate #endif
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static bool_t write_struct();
55*7c478bd9Sstevel@tonic-gate static bool_t read_struct();
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate FILE *
58*7c478bd9Sstevel@tonic-gate open_tmp_file(filename)
59*7c478bd9Sstevel@tonic-gate 	char *filename;
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	int fd;
62*7c478bd9Sstevel@tonic-gate 	FILE *fp;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	/*
65*7c478bd9Sstevel@tonic-gate 	 * Remove any existing files, and create a new one.
66*7c478bd9Sstevel@tonic-gate 	 * Ensure that rpcbind is not forced to overwrite
67*7c478bd9Sstevel@tonic-gate 	 * a file pointed to by a symbolic link created
68*7c478bd9Sstevel@tonic-gate 	 * by an attacker.
69*7c478bd9Sstevel@tonic-gate 	 * Use open O_CREAT|O_EXCL so file is not created
70*7c478bd9Sstevel@tonic-gate 	 * between unlink() and open() operation.
71*7c478bd9Sstevel@tonic-gate 	 */
72*7c478bd9Sstevel@tonic-gate 	if (unlink(filename) == -1) {
73*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT)
74*7c478bd9Sstevel@tonic-gate 			return (NULL);
75*7c478bd9Sstevel@tonic-gate 	}
76*7c478bd9Sstevel@tonic-gate 	fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600);
77*7c478bd9Sstevel@tonic-gate 	if (fd == -1)
78*7c478bd9Sstevel@tonic-gate 		return (NULL);
79*7c478bd9Sstevel@tonic-gate 	fp = fdopen(fd, "w");
80*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
81*7c478bd9Sstevel@tonic-gate 		close(fd);
82*7c478bd9Sstevel@tonic-gate 		return (NULL);
83*7c478bd9Sstevel@tonic-gate 	}
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	return (fp);
86*7c478bd9Sstevel@tonic-gate }
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static bool_t
89*7c478bd9Sstevel@tonic-gate write_struct(filename, structproc, list)
90*7c478bd9Sstevel@tonic-gate 	char *filename;
91*7c478bd9Sstevel@tonic-gate 	xdrproc_t structproc;
92*7c478bd9Sstevel@tonic-gate 	void *list;
93*7c478bd9Sstevel@tonic-gate {
94*7c478bd9Sstevel@tonic-gate 	FILE *fp;
95*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	fp = open_tmp_file(filename);
98*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
99*7c478bd9Sstevel@tonic-gate 		int i;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 10; i++)
102*7c478bd9Sstevel@tonic-gate 			close(i);
103*7c478bd9Sstevel@tonic-gate 		fp = open_tmp_file(filename);
104*7c478bd9Sstevel@tonic-gate 		if (fp == NULL) {
105*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
106*7c478bd9Sstevel@tonic-gate 				"cannot open file = %s for writing", filename);
107*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "cannot save any registration");
108*7c478bd9Sstevel@tonic-gate 			return (FALSE);
109*7c478bd9Sstevel@tonic-gate 		}
110*7c478bd9Sstevel@tonic-gate 	}
111*7c478bd9Sstevel@tonic-gate 	xdrstdio_create(&xdrs, fp, XDR_ENCODE);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (structproc(&xdrs, list) == FALSE) {
114*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rpcbind: xdr_%s: failed", filename);
115*7c478bd9Sstevel@tonic-gate 		fclose(fp);
116*7c478bd9Sstevel@tonic-gate 		return (FALSE);
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&xdrs);
119*7c478bd9Sstevel@tonic-gate 	fclose(fp);
120*7c478bd9Sstevel@tonic-gate 	return (TRUE);
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate static bool_t
124*7c478bd9Sstevel@tonic-gate read_struct(filename, structproc, list)
125*7c478bd9Sstevel@tonic-gate 	char *filename;
126*7c478bd9Sstevel@tonic-gate 	xdrproc_t structproc;
127*7c478bd9Sstevel@tonic-gate 	void *list;
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	int fd;
130*7c478bd9Sstevel@tonic-gate 	FILE *fp = NULL;
131*7c478bd9Sstevel@tonic-gate 	XDR xdrs;
132*7c478bd9Sstevel@tonic-gate 	struct stat sbuf_fstat, sbuf_lstat;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	fd = open(filename, O_RDONLY, 0600);
135*7c478bd9Sstevel@tonic-gate 	if (fd == -1) {
136*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
137*7c478bd9Sstevel@tonic-gate 		"rpcbind: cannot open file = %s for reading\n", filename);
138*7c478bd9Sstevel@tonic-gate 		goto error;
139*7c478bd9Sstevel@tonic-gate 	}
140*7c478bd9Sstevel@tonic-gate 	fp = fdopen(fd, "r");
141*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
142*7c478bd9Sstevel@tonic-gate 		close(fd);
143*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
144*7c478bd9Sstevel@tonic-gate 		"rpcbind: cannot open file = %s for reading\n", filename);
145*7c478bd9Sstevel@tonic-gate 		goto error;
146*7c478bd9Sstevel@tonic-gate 	}
147*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &sbuf_fstat) != 0) {
148*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
149*7c478bd9Sstevel@tonic-gate 		"rpcbind: cannot stat file = %s for reading\n", filename);
150*7c478bd9Sstevel@tonic-gate 		goto error;
151*7c478bd9Sstevel@tonic-gate 	}
152*7c478bd9Sstevel@tonic-gate 	if (sbuf_fstat.st_uid != DAEMON_UID ||
153*7c478bd9Sstevel@tonic-gate 	    (!S_ISREG(sbuf_fstat.st_mode)) ||
154*7c478bd9Sstevel@tonic-gate 	    (sbuf_fstat.st_mode & S_IRWXG) ||
155*7c478bd9Sstevel@tonic-gate 	    (sbuf_fstat.st_mode & S_IRWXO) ||
156*7c478bd9Sstevel@tonic-gate 	    (sbuf_fstat.st_nlink != 1)) {
157*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
158*7c478bd9Sstevel@tonic-gate 		"rpcbind: invalid permissions on file = %s for reading\n",
159*7c478bd9Sstevel@tonic-gate 			filename);
160*7c478bd9Sstevel@tonic-gate 		goto error;
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * Make sure that the pathname for fstat and lstat is the same and
164*7c478bd9Sstevel@tonic-gate 	 * that it's not a link.  An attacker can create symbolic or
165*7c478bd9Sstevel@tonic-gate 	 * hard links and use them to gain unauthorised access to the
166*7c478bd9Sstevel@tonic-gate 	 * system when rpcbind aborts or terminates on SIGINT or SIGTERM.
167*7c478bd9Sstevel@tonic-gate 	 */
168*7c478bd9Sstevel@tonic-gate 	if (lstat(filename, &sbuf_lstat) != 0) {
169*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
170*7c478bd9Sstevel@tonic-gate 		"rpcbind: cannot lstat file = %s for reading\n", filename);
171*7c478bd9Sstevel@tonic-gate 		goto error;
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 	if (sbuf_lstat.st_uid != DAEMON_UID ||
174*7c478bd9Sstevel@tonic-gate 	    (!S_ISREG(sbuf_lstat.st_mode)) ||
175*7c478bd9Sstevel@tonic-gate 	    (sbuf_lstat.st_mode & S_IRWXG) ||
176*7c478bd9Sstevel@tonic-gate 	    (sbuf_lstat.st_mode & S_IRWXO) ||
177*7c478bd9Sstevel@tonic-gate 	    (sbuf_lstat.st_nlink != 1) ||
178*7c478bd9Sstevel@tonic-gate 	    (sbuf_fstat.st_dev != sbuf_lstat.st_dev) ||
179*7c478bd9Sstevel@tonic-gate 	    (sbuf_fstat.st_ino != sbuf_lstat.st_ino)) {
180*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
181*7c478bd9Sstevel@tonic-gate 		"rpcbind: invalid lstat permissions on file = %s for reading\n",
182*7c478bd9Sstevel@tonic-gate 			filename);
183*7c478bd9Sstevel@tonic-gate 		goto error;
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 	xdrstdio_create(&xdrs, fp, XDR_DECODE);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	if (structproc(&xdrs, list) == FALSE) {
188*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rpcbind: xdr_%s: failed\n", filename);
189*7c478bd9Sstevel@tonic-gate 		goto error;
190*7c478bd9Sstevel@tonic-gate 	}
191*7c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&xdrs);
192*7c478bd9Sstevel@tonic-gate 	fclose(fp);
193*7c478bd9Sstevel@tonic-gate 	return (TRUE);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate error:	fprintf(stderr, "rpcbind: will start from scratch\n");
196*7c478bd9Sstevel@tonic-gate 	if (fp != NULL)
197*7c478bd9Sstevel@tonic-gate 		fclose(fp);
198*7c478bd9Sstevel@tonic-gate 	return (FALSE);
199*7c478bd9Sstevel@tonic-gate }
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate void
202*7c478bd9Sstevel@tonic-gate write_warmstart(void)
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	(void) write_struct(rpcbfile, xdr_rpcblist_ptr, &list_rbl);
205*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
206*7c478bd9Sstevel@tonic-gate 	(void) write_struct(pmapfile, xdr_pmaplist_ptr, &list_pml);
207*7c478bd9Sstevel@tonic-gate #endif
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate }
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate void
212*7c478bd9Sstevel@tonic-gate read_warmstart(void)
213*7c478bd9Sstevel@tonic-gate {
214*7c478bd9Sstevel@tonic-gate 	rpcblist_ptr tmp_rpcbl = NULL;
215*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
216*7c478bd9Sstevel@tonic-gate 	pmaplist_ptr tmp_pmapl = NULL;
217*7c478bd9Sstevel@tonic-gate #endif
218*7c478bd9Sstevel@tonic-gate 	int ok1, ok2 = TRUE;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	ok1 = read_struct(rpcbfile, xdr_rpcblist_ptr, &tmp_rpcbl);
221*7c478bd9Sstevel@tonic-gate 	if (ok1 == FALSE)
222*7c478bd9Sstevel@tonic-gate 		return;
223*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
224*7c478bd9Sstevel@tonic-gate 	ok2 = read_struct(pmapfile, xdr_pmaplist_ptr, &tmp_pmapl);
225*7c478bd9Sstevel@tonic-gate #endif
226*7c478bd9Sstevel@tonic-gate 	if (ok2 == FALSE) {
227*7c478bd9Sstevel@tonic-gate 		xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&tmp_rpcbl);
228*7c478bd9Sstevel@tonic-gate 		return;
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 	xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&list_rbl);
231*7c478bd9Sstevel@tonic-gate 	list_rbl = tmp_rpcbl;
232*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP
233*7c478bd9Sstevel@tonic-gate 	xdr_free((xdrproc_t)xdr_pmaplist_ptr, (char *)&list_pml);
234*7c478bd9Sstevel@tonic-gate 	list_pml = (pmaplist *)tmp_pmapl;
235*7c478bd9Sstevel@tonic-gate #endif
236*7c478bd9Sstevel@tonic-gate }
237