xref: /netbsd/sbin/mount_portal/pt_filter.c (revision bf9ec67e)
1 /*	$NetBSD: pt_filter.c,v 1.4 2001/01/10 03:33:16 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD
8  * Foundation by Brian Grayson, and is dedicated to Rebecca
9  * Margaret Pollard-Grayson.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include <sys/cdefs.h>
41 #ifndef lint
42 __RCSID("$NetBSD: pt_filter.c,v 1.4 2001/01/10 03:33:16 lukem Exp $");
43 #endif				/* not lint */
44 
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/syslog.h>
53 
54 #include "portald.h"
55 
56 /*
57  * Key will be <key><path>.  We let the configuration file
58  * tell us how to filter the file.
59  */
60 
61 #define FILTER_CMD_SIZE	8192
62 
63 static void fill_cmd __P((char **, char *, char *, int));
64 
65 static void
66 fill_cmd(cmdv, path, buff, n)
67 	char  **cmdv;
68 	char   *path;
69 	char   *buff;
70 	int     n;
71 {
72 	int     i;
73 	/* Make tempbuff at least as large as buff. */
74 	char	tempbuff[n];
75 
76 	strncpy(tempbuff, cmdv[0], n);
77 	for (i = 1; cmdv[i]; i++) {
78 		strncat(tempbuff, " ", n - strlen(tempbuff));
79 		strncat(tempbuff, cmdv[i], n - strlen(tempbuff));
80 	}
81 	strncat(tempbuff, " ", n - strlen(tempbuff));
82 	/* Now do the snprintf into buff. */
83 	snprintf(buff, n, tempbuff, path);
84 }
85 
86 
87 /*
88  * Strip v[1], replace %s in v[2] v[3] ... with the remainder
89  * of the path, and exec v[2] v[3] ... on the remainder.
90  */
91 int
92 portal_rfilter(pcr, key, v, kso, fdp)
93 	struct portal_cred *pcr;
94 	char   *key;
95 	char  **v;
96 	int     kso;
97 	int    *fdp;
98 {
99 	char    cmd[FILTER_CMD_SIZE];
100 	char   *path;
101 	FILE   *fp;
102 	int     error = 0;
103 
104 	/* We don't use this parameter. */
105 	(void) kso;
106 
107 	error = lose_credentials(pcr);
108 	if (error != 0)
109 		return error;
110 
111 #ifdef DEBUG
112 	fprintf(stderr, "rfilter:  Got key %s\n", key);
113 #endif
114 
115 	errno = 0;
116 	if (!v[1] || !v[2]) {
117 		syslog(LOG_ERR,
118 		    "rfilter: got strip-key of %s, and command start of %s\n",
119 		    v[1], v[2]);
120 		exit(1);
121 	}
122 	/*
123 	 * Format for rfilter in config file:
124 	 *
125 	 * matchkey rfilter stripkey cmd [arg1] [arg2] ...
126 	 * any of arg1, arg2, etc. can have %s, in which case %s
127 	 * will be replaced by the full path.  If arg1 is
128 	 * missing, %s is assumed, i.e.
129 	 *   bogus1 rfilter bogus1/ cmd1
130 	 * is equivalent to
131 	 *   bogus1 rfilter bogus1/ cmd1 %s
132 	 */
133 	/*
134 	 * v[3] could be NULL, or could point to "".
135 	 */
136 	if (!v[3] || strlen(v[3]) == 0)
137 	  v[3] = "%s";	/* Handle above assumption. */
138 	path = key;
139 	/* Strip out stripkey if it matches leading part of key. */
140 	if (!strncmp(v[1], key, strlen(v[1])))
141 		path += strlen(v[1]);
142 	/*
143 	 * v[0] is key match, v[1] says how much to strip, v[2]
144 	 * is beginning of command proper.  The first %s in v[2]
145 	 * ... will be replaced with the path.
146 	 */
147 	fill_cmd(v + 2, path, cmd, FILTER_CMD_SIZE);
148 	if (strlen(cmd) >= FILTER_CMD_SIZE) {
149 		syslog(LOG_WARNING,
150 		    "Warning:  potential overflow on string!  Length was %lu\n",
151 		    (unsigned long)strlen(cmd));
152 		return -1;
153 	}
154 #ifdef DEBUG
155 	fprintf(stderr, "rfilter:  Using cmd of %s\n", cmd);
156 #endif
157 	fp = popen(cmd, "r");
158 	if (fp == NULL) {
159 	  	return errno;
160 	}
161 
162 	/* Before returning, restore original uid and gid. */
163 	/* But only do this if we were root to start with. */
164 	if (getuid() == 0) {
165 		if ((seteuid((uid_t) 0) < 0) || (setegid((gid_t) 0) < 0)) {
166 			error = errno;
167 			syslog(LOG_WARNING, "setcred: %m");
168 			if (fp) {
169 				fclose(fp);
170 				fp = NULL;
171 			}
172 		}
173 	}
174 	if (error == 0)
175 		fdp[0] = fileno(fp);
176 	return (errno);
177 }
178 
179 int
180 portal_wfilter(pcr, key, v, kso, fdp)
181 	struct portal_cred *pcr;
182 	char   *key;
183 	char  **v;
184 	int     kso;
185 	int    *fdp;
186 {
187 	char    cmd[FILTER_CMD_SIZE];
188 	char   *path;
189 	FILE   *fp;
190 	int     error = 0;
191 	int     cred_change_err = 0;
192 
193 	/* We don't use this parameter. */
194 	(void) kso;
195 
196 	cred_change_err = lose_credentials(pcr);
197 	if (cred_change_err != 0)
198 		return cred_change_err;
199 
200 	errno = 0;
201 	path = key + (v[1] ? strlen(v[1]) : 0);
202 	/*
203 	 * v[0] is key match, v[1] says how much to strip, v[2]
204 	 * is beginning of command proper.
205 	 */
206 	fill_cmd(v + 2, path, cmd, FILTER_CMD_SIZE);
207 	if (strlen(cmd) >= FILTER_CMD_SIZE) {
208 		syslog(LOG_WARNING,
209 		    "Warning:  potential overflow on string!  Length was %lu\n",
210 		    (unsigned long)strlen(cmd));
211 		return -1;
212 	}
213 	fp = popen(cmd, "w");
214 	if (fp == NULL) {
215 	  	return errno;
216 	}
217 	/* Before returning, restore original uid and gid. */
218 	/* But only do this if we were root to start with. */
219 	if (getuid() == 0) {
220 		if ((seteuid((uid_t) 0) < 0) || (setegid((gid_t) 0) < 0)) {
221 			error = errno;
222 			syslog(LOG_WARNING, "setcred: %m");
223 			if (fp) {
224 				fclose(fp);
225 				fp = NULL;
226 			}
227 		}
228 	}
229 	if (error == 0)
230 		fdp[0] = fileno(fp);
231 	return (errno);
232 }
233