Home | History | Annotate | Line # | Download | only in mount_portal
      1 /*	$NetBSD: pt_filter.c,v 1.13 2021/04/12 09:18:14 mrg 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  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 #ifndef lint
     35 __RCSID("$NetBSD: pt_filter.c,v 1.13 2021/04/12 09:18:14 mrg Exp $");
     36 #endif				/* not lint */
     37 
     38 #include <stdio.h>
     39 #include <unistd.h>
     40 #include <stdlib.h>
     41 #include <errno.h>
     42 #include <string.h>
     43 #include <err.h>
     44 #include <sys/types.h>
     45 #include <sys/param.h>
     46 #include <sys/syslog.h>
     47 
     48 #include "portald.h"
     49 
     50 /*
     51  * Key will be <key><path>.  We let the configuration file
     52  * tell us how to filter the file.
     53  */
     54 
     55 #define FILTER_CMD_SIZE	8192
     56 
     57 static void fill_cmd(char **, char *, char *, int);
     58 
     59 static void
     60 fill_cmd(char **cmdv, char *path, char *buff, int n)
     61 {
     62 	int     i;
     63 	/* Make tempbuff at least as large as buff. */
     64 	char	*tempbuff = malloc(n);
     65 	if (tempbuff == NULL)
     66 		err(1, NULL);
     67 
     68 	strncpy(tempbuff, cmdv[0], n - 1);
     69 	tempbuff[n - 1] = '\0';
     70 	for (i = 1; cmdv[i]; i++) {
     71 		strncat(tempbuff, " ", n - strlen(tempbuff));
     72 		strncat(tempbuff, cmdv[i], n - strlen(tempbuff));
     73 	}
     74 	strncat(tempbuff, " ", n - strlen(tempbuff));
     75 	/* Now do the snprintf into buff. */
     76 	snprintf(buff, n, tempbuff, path);
     77 	free(tempbuff);
     78 }
     79 
     80 
     81 /*
     82  * Strip v[1], replace %s in v[2] v[3] ... with the remainder
     83  * of the path, and exec v[2] v[3] ... on the remainder.
     84  */
     85 int
     86 portal_rfilter(struct portal_cred *pcr, char *key, char **v, int *fdp)
     87 {
     88 	char    cmd[FILTER_CMD_SIZE];
     89 	char   *path;
     90 	FILE   *fp;
     91 	int     error = 0;
     92 	char	percent_s[] = "%s";
     93 
     94 	error = lose_credentials(pcr);
     95 	if (error != 0)
     96 		return error;
     97 
     98 #ifdef DEBUG
     99 	fprintf(stderr, "rfilter:  Got key %s\n", key);
    100 #endif
    101 
    102 	if (!v[1] || !v[2]) {
    103 		syslog(LOG_ERR,
    104 		    "rfilter: got strip-key of %s, and command start of %s\n",
    105 		    v[1], v[2]);
    106 		exit(1);
    107 	}
    108 	/*
    109 	 * Format for rfilter in config file:
    110 	 *
    111 	 * matchkey rfilter stripkey cmd [arg1] [arg2] ...
    112 	 * any of arg1, arg2, etc. can have %s, in which case %s
    113 	 * will be replaced by the full path.  If arg1 is
    114 	 * missing, %s is assumed, i.e.
    115 	 *   bogus1 rfilter bogus1/ cmd1
    116 	 * is equivalent to
    117 	 *   bogus1 rfilter bogus1/ cmd1 %s
    118 	 */
    119 	/*
    120 	 * v[3] could be NULL, or could point to "".
    121 	 */
    122 	if (!v[3] || strlen(v[3]) == 0)
    123 		v[3] = percent_s;	/* Handle above assumption. */
    124 	path = key;
    125 	/* Strip out stripkey if it matches leading part of key. */
    126 	if (!strncmp(v[1], key, strlen(v[1])))
    127 		path += strlen(v[1]);
    128 	/*
    129 	 * v[0] is key match, v[1] says how much to strip, v[2]
    130 	 * is beginning of command proper.  The first %s in v[2]
    131 	 * ... will be replaced with the path.
    132 	 */
    133 	fill_cmd(v + 2, path, cmd, FILTER_CMD_SIZE);
    134 	if (strlen(cmd) >= FILTER_CMD_SIZE) {
    135 		syslog(LOG_WARNING,
    136 		    "Warning:  potential overflow on string!  Length was %lu\n",
    137 		    (unsigned long)strlen(cmd));
    138 		return ENAMETOOLONG;
    139 	}
    140 #ifdef DEBUG
    141 	fprintf(stderr, "rfilter:  Using cmd of %s\n", cmd);
    142 #endif
    143 	fp = popen(cmd, "r");
    144 	if (fp == NULL)
    145 	  	return errno;
    146 
    147 	/* Before returning, restore original uid and gid. */
    148 	/* But only do this if we were root to start with. */
    149 	if (getuid() == 0) {
    150 		if ((seteuid((uid_t) 0) < 0) || (setegid((gid_t) 0) < 0)) {
    151 			error = errno;
    152 			syslog(LOG_WARNING, "setcred: %m");
    153 			pclose(fp);
    154 			fp = NULL;
    155 		}
    156 	}
    157 	if (fp)
    158 		fdp[0] = fileno(fp);
    159 	return error;
    160 }
    161 
    162 int
    163 portal_wfilter(struct portal_cred *pcr, char *key, char **v, int *fdp)
    164 {
    165 	char    cmd[FILTER_CMD_SIZE];
    166 	char   *path;
    167 	FILE   *fp;
    168 	int     error = 0;
    169 	int     cred_change_err = 0;
    170 
    171 	cred_change_err = lose_credentials(pcr);
    172 	if (cred_change_err != 0)
    173 		return cred_change_err;
    174 
    175 	path = key + (v[1] ? strlen(v[1]) : 0);
    176 	/*
    177 	 * v[0] is key match, v[1] says how much to strip, v[2]
    178 	 * is beginning of command proper.
    179 	 */
    180 	fill_cmd(v + 2, path, cmd, FILTER_CMD_SIZE);
    181 	if (strlen(cmd) >= FILTER_CMD_SIZE) {
    182 		syslog(LOG_WARNING,
    183 		    "Warning:  potential overflow on string!  Length was %lu\n",
    184 		    (unsigned long)strlen(cmd));
    185 		return ENAMETOOLONG;
    186 	}
    187 	fp = popen(cmd, "w");
    188 	if (fp == NULL) {
    189 	  	return errno;
    190 	}
    191 	/* Before returning, restore original uid and gid. */
    192 	/* But only do this if we were root to start with. */
    193 	if (getuid() == 0) {
    194 		if ((seteuid((uid_t) 0) < 0) || (setegid((gid_t) 0) < 0)) {
    195 			error = errno;
    196 			syslog(LOG_WARNING, "setcred: %m");
    197 			pclose(fp);
    198 			fp = NULL;
    199 		}
    200 	}
    201 	if (fp)
    202 		fdp[0] = fileno(fp);
    203 	return error;
    204 }
    205