Home | History | Annotate | Line # | Download | only in ex
      1 /*	$NetBSD: ex_init.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
      2 /*-
      3  * Copyright (c) 1992, 1993, 1994
      4  *	The Regents of the University of California.  All rights reserved.
      5  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  *	Keith Bostic.  All rights reserved.
      7  *
      8  * See the LICENSE file for redistribution information.
      9  */
     10 
     11 #include "config.h"
     12 
     13 #include <sys/cdefs.h>
     14 #if 0
     15 #ifndef lint
     16 static const char sccsid[] = "Id: ex_init.c,v 10.31 2001/06/25 15:19:16 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:16 ";
     17 #endif /* not lint */
     18 #else
     19 __RCSID("$NetBSD: ex_init.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
     20 #endif
     21 
     22 #include <sys/param.h>
     23 #include <sys/types.h>		/* XXX: param.h may not have included types.h */
     24 #include <sys/queue.h>
     25 #include <sys/stat.h>
     26 
     27 #include <bitstring.h>
     28 #include <fcntl.h>
     29 #include <limits.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <unistd.h>
     34 
     35 #include "../common/common.h"
     36 #include "tag.h"
     37 #include "pathnames.h"
     38 
     39 enum rc { NOEXIST, NOPERM, RCOK };
     40 static enum rc	exrc_isok __P((SCR *, struct stat *, const char *, int, int));
     41 
     42 static int ex_run_file __P((SCR *, const char *));
     43 
     44 /*
     45  * ex_screen_copy --
     46  *	Copy ex screen.
     47  *
     48  * PUBLIC: int ex_screen_copy __P((SCR *, SCR *));
     49  */
     50 int
     51 ex_screen_copy(SCR *orig, SCR *sp)
     52 {
     53 	EX_PRIVATE *oexp, *nexp;
     54 
     55 	/* Create the private ex structure. */
     56 	CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE));
     57 	sp->ex_private = nexp;
     58 
     59 	/* Initialize queues. */
     60 	TAILQ_INIT(&nexp->tq);
     61 	TAILQ_INIT(&nexp->tagfq);
     62 	LIST_INIT(&nexp->cscq);
     63 
     64 	if (orig == NULL) {
     65 	} else {
     66 		oexp = EXP(orig);
     67 
     68 		if (oexp->lastbcomm != NULL &&
     69 		    (nexp->lastbcomm = v_wstrdup(sp, oexp->lastbcomm,
     70 				     STRLEN(oexp->lastbcomm))) == NULL) {
     71 			msgq(sp, M_SYSERR, NULL);
     72 			return(1);
     73 		}
     74 		if (ex_tag_copy(orig, sp))
     75 			return (1);
     76 	}
     77 	return (0);
     78 }
     79 
     80 /*
     81  * ex_screen_end --
     82  *	End a vi screen.
     83  *
     84  * PUBLIC: int ex_screen_end __P((SCR *));
     85  */
     86 int
     87 ex_screen_end(SCR *sp)
     88 {
     89 	EX_PRIVATE *exp;
     90 	int rval;
     91 
     92 	if ((exp = EXP(sp)) == NULL)
     93 		return (0);
     94 
     95 	rval = 0;
     96 
     97 	/* Close down script connections. */
     98 	if (F_ISSET(sp, SC_SCRIPT) && sscr_end(sp))
     99 		rval = 1;
    100 
    101 	if (argv_free(sp))
    102 		rval = 1;
    103 
    104 	if (exp->ibp != NULL)
    105 		free(exp->ibp);
    106 
    107 	if (exp->lastbcomm != NULL)
    108 		free(exp->lastbcomm);
    109 
    110 	if (ex_tag_free(sp))
    111 		rval = 1;
    112 
    113 	/* Free private memory. */
    114 	free(exp);
    115 	sp->ex_private = NULL;
    116 
    117 	return (rval);
    118 }
    119 
    120 /*
    121  * ex_optchange --
    122  *	Handle change of options for ex.
    123  *
    124  * PUBLIC: int ex_optchange __P((SCR *, int, const char *, u_long *));
    125  */
    126 int
    127 ex_optchange(SCR *sp, int offset, const char *str, u_long *valp)
    128 {
    129 	switch (offset) {
    130 	case O_TAGS:
    131 		return (ex_tagf_alloc(sp, str));
    132 	}
    133 	return (0);
    134 }
    135 
    136 /*
    137  * ex_exrc --
    138  *	Read the EXINIT environment variable and the startup exrc files,
    139  *	and execute their commands.
    140  *
    141  * PUBLIC: int ex_exrc __P((SCR *));
    142  */
    143 int
    144 ex_exrc(SCR *sp)
    145 {
    146 	struct stat hsb, lsb;
    147 	char *p, path[MAXPATHLEN];
    148 	const CHAR_T *wp;
    149 	size_t wlen;
    150 
    151 	/*
    152 	 * Source the system, environment, $HOME and local .exrc values.
    153 	 * Vi historically didn't check $HOME/.exrc if the environment
    154 	 * variable EXINIT was set.  This is all done before the file is
    155 	 * read in, because things in the .exrc information can set, for
    156 	 * example, the recovery directory.
    157 	 *
    158 	 * !!!
    159 	 * While nvi can handle any of the options settings of historic vi,
    160 	 * the converse is not true.  Since users are going to have to have
    161 	 * files and environmental variables that work with both, we use nvi
    162 	 * versions of both the $HOME and local startup files if they exist,
    163 	 * otherwise the historic ones.
    164 	 *
    165 	 * !!!
    166 	 * For a discussion of permissions and when what .exrc files are
    167 	 * read, see the comment above the exrc_isok() function below.
    168 	 *
    169 	 * !!!
    170 	 * If the user started the historic of vi in $HOME, vi read the user's
    171 	 * .exrc file twice, as $HOME/.exrc and as ./.exrc.  We avoid this, as
    172 	 * it's going to make some commands behave oddly, and I can't imagine
    173 	 * anyone depending on it.
    174 	 */
    175 	switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) {
    176 	case NOEXIST:
    177 	case NOPERM:
    178 		break;
    179 	case RCOK:
    180 		if (ex_run_file(sp, _PATH_SYSEXRC))
    181 			return (1);
    182 		break;
    183 	}
    184 
    185 	/* Run the commands. */
    186 	if (EXCMD_RUNNING(sp->wp))
    187 		(void)ex_cmd(sp);
    188 	if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE))
    189 		return (0);
    190 
    191 	if ((p = getenv("NEXINIT")) != NULL) {
    192 		CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
    193 		if (ex_run_str(sp, "NEXINIT", wp, wlen - 1, 1, 0))
    194 			return (1);
    195 	} else if ((p = getenv("EXINIT")) != NULL) {
    196 		CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
    197 		if (ex_run_str(sp, "EXINIT", wp, wlen - 1, 1, 0))
    198 			return (1);
    199 	} else if ((p = getenv("HOME")) != NULL && *p) {
    200 		(void)snprintf(path, sizeof(path), "%s/%s", p, _PATH_NEXRC);
    201 		switch (exrc_isok(sp, &hsb, path, 0, 1)) {
    202 		case NOEXIST:
    203 			(void)snprintf(path,
    204 			    sizeof(path), "%s/%s", p, _PATH_EXRC);
    205 			if (exrc_isok(sp,
    206 			    &hsb, path, 0, 1) == RCOK && ex_run_file(sp, path))
    207 				return (1);
    208 			break;
    209 		case NOPERM:
    210 			break;
    211 		case RCOK:
    212 			if (ex_run_file(sp, path))
    213 				return (1);
    214 			break;
    215 		}
    216 	}
    217 
    218 	/* Run the commands. */
    219 	if (EXCMD_RUNNING(sp->wp))
    220 		(void)ex_cmd(sp);
    221 	if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE))
    222 		return (0);
    223 
    224 	/* Previous commands may have set the exrc option. */
    225 	if (O_ISSET(sp, O_EXRC)) {
    226 		switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) {
    227 		case NOEXIST:
    228 			if (exrc_isok(sp, &lsb, _PATH_EXRC, 0, 0) == RCOK &&
    229 			    (lsb.st_dev != hsb.st_dev ||
    230 			    lsb.st_ino != hsb.st_ino) &&
    231 			    ex_run_file(sp, _PATH_EXRC))
    232 				return (1);
    233 			break;
    234 		case NOPERM:
    235 			break;
    236 		case RCOK:
    237 			if ((lsb.st_dev != hsb.st_dev ||
    238 			    lsb.st_ino != hsb.st_ino) &&
    239 			    ex_run_file(sp, _PATH_NEXRC))
    240 				return (1);
    241 			break;
    242 		}
    243 		/* Run the commands. */
    244 		if (EXCMD_RUNNING(sp->wp))
    245 			(void)ex_cmd(sp);
    246 		if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE))
    247 			return (0);
    248 	}
    249 
    250 	return (0);
    251 }
    252 
    253 /*
    254  * ex_run_file --
    255  *	Set up a file of ex commands to run.
    256  */
    257 static int
    258 ex_run_file(SCR *sp, const char *name)
    259 {
    260 	EXCMD cmd;
    261 	const CHAR_T *wp;
    262 	size_t wlen;
    263 
    264 	ex_cinit(sp, &cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0);
    265 	CHAR2INT(sp, name, strlen(name)+1, wp, wlen);
    266 	argv_exp0(sp, &cmd, wp, wlen - 1);
    267 	return (ex_source(sp, &cmd));
    268 }
    269 
    270 /*
    271  * ex_run_str --
    272  *	Set up a string of ex commands to run.
    273  *
    274  * PUBLIC: int ex_run_str __P((SCR *, const char *, const CHAR_T *, size_t, int, int));
    275  */
    276 int
    277 ex_run_str(SCR *sp, const char *name, const CHAR_T *str, size_t len, int ex_flags, int nocopy)
    278 {
    279 	WIN *wp;
    280 	EXCMD *ecp;
    281 
    282 	wp = sp->wp;
    283 	if (EXCMD_RUNNING(wp)) {
    284 		CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD));
    285 		LIST_INSERT_HEAD(&wp->ecq, ecp, q);
    286 	} else
    287 		ecp = &wp->excmd;
    288 
    289 	F_INIT(ecp,
    290 	    ex_flags ? E_BLIGNORE | E_NOAUTO | E_NOPRDEF | E_VLITONLY : 0);
    291 
    292 	if (nocopy)
    293 		ecp->cp = __UNCONST(str);
    294 	else
    295 		if ((ecp->cp = v_wstrdup(sp, str, len)) == NULL)
    296 			return (1);
    297 	ecp->clen = len;
    298 
    299 	if (name == NULL)
    300 		ecp->if_name = NULL;
    301 	else {
    302 		if ((ecp->if_name = v_strdup(sp, name, strlen(name))) == NULL)
    303 			return (1);
    304 		ecp->if_lno = 1;
    305 		F_SET(ecp, E_NAMEDISCARD);
    306 	}
    307 
    308 	return (0);
    309 }
    310 
    311 /*
    312  * exrc_isok --
    313  *	Check a .exrc file for source-ability.
    314  *
    315  * !!!
    316  * Historically, vi read the $HOME and local .exrc files if they were owned
    317  * by the user's real ID, or the "sourceany" option was set, regardless of
    318  * any other considerations.  We no longer support the sourceany option as
    319  * it's a security problem of mammoth proportions.  We require the system
    320  * .exrc file to be owned by root, the $HOME .exrc file to be owned by the
    321  * user's effective ID (or that the user's effective ID be root) and the
    322  * local .exrc files to be owned by the user's effective ID.  In all cases,
    323  * the file cannot be writeable by anyone other than its owner.
    324  *
    325  * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106),
    326  * it notes that System V release 3.2 and later has an option "[no]exrc".
    327  * The behavior is that local .exrc files are read only if the exrc option
    328  * is set.  The default for the exrc option was off, so, by default, local
    329  * .exrc files were not read.  The problem this was intended to solve was
    330  * that System V permitted users to give away files, so there's no possible
    331  * ownership or writeability test to ensure that the file is safe.
    332  *
    333  * POSIX 1003.2-1992 standardized exrc as an option.  It required the exrc
    334  * option to be off by default, thus local .exrc files are not to be read
    335  * by default.  The Rationale noted (incorrectly) that this was a change
    336  * to historic practice, but correctly noted that a default of off improves
    337  * system security.  POSIX also required that vi check the effective user
    338  * ID instead of the real user ID, which is why we've switched from historic
    339  * practice.
    340  *
    341  * We initialize the exrc variable to off.  If it's turned on by the system
    342  * or $HOME .exrc files, and the local .exrc file passes the ownership and
    343  * writeability tests, then we read it.  This breaks historic 4BSD practice,
    344  * but it gives us a measure of security on systems where users can give away
    345  * files.
    346  */
    347 static enum rc
    348 exrc_isok(SCR *sp, struct stat *sbp, const char *path, int rootown, int rootid)
    349 {
    350 	enum { ROOTOWN, OWN, WRITER } etype;
    351 	uid_t euid;
    352 	int nf1, nf2;
    353 	char *a, *b, buf[MAXPATHLEN];
    354 
    355 	/* Check for the file's existence. */
    356 	if (stat(path, sbp))
    357 		return (NOEXIST);
    358 
    359 	/* Check ownership permissions. */
    360 	euid = geteuid();
    361 	if (!(rootown && sbp->st_uid == 0) &&
    362 	    !(rootid && euid == 0) && sbp->st_uid != euid) {
    363 		etype = rootown ? ROOTOWN : OWN;
    364 		goto denied;
    365 	}
    366 
    367 	/* Check writeability. */
    368 	if (sbp->st_mode & (S_IWGRP | S_IWOTH)) {
    369 		etype = WRITER;
    370 		goto denied;
    371 	}
    372 	return (RCOK);
    373 
    374 denied:	a = msg_print(sp, path, &nf1);
    375 	if (strchr(path, '/') == NULL && getcwd(buf, sizeof(buf)) != NULL) {
    376 		b = msg_print(sp, buf, &nf2);
    377 		switch (etype) {
    378 		case ROOTOWN:
    379 			msgq(sp, M_ERR,
    380 			    "125|%s/%s: not sourced: not owned by you or root",
    381 			    b, a);
    382 			break;
    383 		case OWN:
    384 			msgq(sp, M_ERR,
    385 			    "126|%s/%s: not sourced: not owned by you", b, a);
    386 			break;
    387 		case WRITER:
    388 			msgq(sp, M_ERR,
    389     "127|%s/%s: not sourced: writeable by a user other than the owner", b, a);
    390 			break;
    391 		}
    392 		if (nf2)
    393 			FREE_SPACE(sp, b, 0);
    394 	} else
    395 		switch (etype) {
    396 		case ROOTOWN:
    397 			msgq(sp, M_ERR,
    398 			    "128|%s: not sourced: not owned by you or root", a);
    399 			break;
    400 		case OWN:
    401 			msgq(sp, M_ERR,
    402 			    "129|%s: not sourced: not owned by you", a);
    403 			break;
    404 		case WRITER:
    405 			msgq(sp, M_ERR,
    406 	    "130|%s: not sourced: writeable by a user other than the owner", a);
    407 			break;
    408 		}
    409 
    410 	if (nf1)
    411 		FREE_SPACE(sp, a, 0);
    412 	return (NOPERM);
    413 }
    414