Home | History | Annotate | Download | only in sh
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * Policy backing functions for kpolicy=suser,profiles=yes
     26  *
     27  */
     28 
     29 #include <sys/param.h>
     30 #include <grp.h>
     31 #include <pwd.h>
     32 #include <strings.h>
     33 #include <string.h>
     34 #include <errno.h>
     35 #include <unistd.h>
     36 #include <stdlib.h>
     37 #include "sh_policy.h"
     38 
     39 
     40 static char *username;
     41 
     42 /*
     43  * get the ruid and passwd name
     44  */
     45 void
     46 secpolicy_init(void)
     47 {
     48 	uid_t		ruid;
     49 	struct passwd	*passwd_ent;
     50 
     51 	if (username != NULL) {
     52 		free(username);
     53 		username = NULL;
     54 	}
     55 
     56 	ruid = getuid();
     57 
     58 	if ((passwd_ent = getpwuid(ruid)) == NULL) {
     59 		secpolicy_print(SECPOLICY_ERROR, ERR_PASSWD);
     60 	} else if ((username = strdup(passwd_ent->pw_name)) == NULL) {
     61 		secpolicy_print(SECPOLICY_ERROR, ERR_MEM);
     62 	}
     63 }
     64 
     65 
     66 /*
     67  * stuff pfexec full path at the begining of the argument vector
     68  * for the command to be pfexec'd
     69  *
     70  * return newly allocated argv on success, else return NULL.
     71  */
     72 static char **
     73 secpolicy_set_argv(char **arg_v)
     74 {
     75 	int	i;
     76 	int	arg_c = 0;
     77 	char	**pfarg_v = NULL;
     78 
     79 	if (*arg_v == NULL) {
     80 		return (pfarg_v);
     81 	}
     82 	for (i = 0; arg_v[i] != NULL; i++) {
     83 		arg_c++;
     84 	}
     85 	/* +2 for PFEXEC and null termination */
     86 	if ((pfarg_v = calloc(arg_c + 2, sizeof (char *))) == NULL) {
     87 		return (pfarg_v);
     88 	}
     89 	pfarg_v[0] = PFEXEC;
     90 	for (i = 0; i < arg_c; i++) {
     91 		pfarg_v[i + 1] = arg_v[i];
     92 	}
     93 
     94 	return (pfarg_v);
     95 }
     96 
     97 
     98 /*
     99  * gets realpath for cmd.
    100  * return 0 on success,  else return ENOENT.
    101  */
    102 static int
    103 secpolicy_getrealpath(const char *cmd, char *cmd_realpath)
    104 {
    105 	register char	*mover;
    106 	char	cwd[MAXPATHLEN];
    107 
    108 	/*
    109 	 * What about relative paths?  Were we passed one?
    110 	 */
    111 	mover = (char *)cmd;
    112 	if (*mover != '/') {
    113 		/*
    114 		 * Everything in here will be considered a relative
    115 		 * path, and therefore we need to prepend cwd to it.
    116 		 */
    117 		if (getcwd(cwd, MAXPATHLEN) == NULL) {
    118 			secpolicy_print(SECPOLICY_ERROR, ERR_CWD);
    119 		}
    120 		strcat(cwd, "/");
    121 		if (strlcat(cwd, cmd, MAXPATHLEN) >= MAXPATHLEN) {
    122 			return (ENOENT);
    123 		}
    124 		mover = cwd;
    125 	}
    126 	/*
    127 	 * Resolve ".." and other such nonsense.
    128 	 * Now, is there *REALLY* a file there?
    129 	 */
    130 	if (realpath(mover, cmd_realpath) == NULL) {
    131 		return (ENOENT);
    132 	}
    133 
    134 	return (0);
    135 }
    136 
    137 
    138 /*
    139  * check if the command has execution attributes
    140  * return -
    141  *    - NOATTRS   : command in profile but has no execution attributes
    142  *    - ENOMEM    : memory allocation errors
    143  *    - ENOENT    : command not in profile
    144  */
    145 
    146 int
    147 secpolicy_pfexec(const char *command, char **arg_v, const char **xecenv)
    148 {
    149 	register int	status = NOATTRS;
    150 	char		**pfarg_v = (char **)NULL;
    151 	char		cmd_realpath[MAXPATHLEN + 1];
    152 	execattr_t	*exec;
    153 
    154 	if ((status = secpolicy_getrealpath(command, cmd_realpath)) != 0) {
    155 		return (status);
    156 	}
    157 	if ((exec = getexecuser(username, KV_COMMAND,
    158 	    (const char *)cmd_realpath, GET_ONE)) == NULL) {
    159 		/*
    160 		 * command not in profile
    161 		 */
    162 		return (ENOENT);
    163 	}
    164 	/*
    165 	 * In case of "All" profile, we'd go through pfexec
    166 	 * if it had any attributes.
    167 	 */
    168 	if ((exec->attr != NULL) && (exec->attr->length != 0)) {
    169 		/*
    170 		 * command in profile and has attributes
    171 		 */
    172 		free_execattr(exec);
    173 		arg_v[0] = (char *)command;
    174 		pfarg_v = secpolicy_set_argv(arg_v);
    175 		if (pfarg_v != NULL) {
    176 			errno = 0;
    177 			if (xecenv == NULL) {
    178 				execv(PFEXEC, (char *const *)pfarg_v);
    179 			} else {
    180 				execve(PFEXEC, (char *const *)pfarg_v,
    181 				    (char *const *)xecenv);
    182 			}
    183 			free(pfarg_v);
    184 			status = errno;
    185 		} else {
    186 			status = ENOMEM;
    187 		}
    188 	} else {
    189 		/*
    190 		 * command in profile, but has no attributes
    191 		 */
    192 		free_execattr(exec);
    193 		status = NOATTRS;
    194 	}
    195 
    196 
    197 	return (status);
    198 }
    199